diff --git a/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java index e9b6b3e0f..140a46579 100644 --- a/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java +++ b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java @@ -4,6 +4,7 @@ import com.fr.design.ExtraDesignClassManager; import com.fr.design.fun.ClipboardHandlerProvider; import com.fr.plugin.injectable.PluginModule; +import java.util.HashSet; import java.util.Set; /** @@ -11,11 +12,25 @@ import java.util.Set; **/ @SuppressWarnings({"rawtypes", "unchecked"}) public abstract class ClipboardFilter { + public static Set clipboardHandlerProviders = new HashSet(); + + public static void registerClipboardHandler(ClipboardHandlerProvider provider) { + if (!clipboardHandlerProviders.contains(provider)) { + clipboardHandlerProviders.add(provider); + } + } + + public static void removeClipboardHandler(ClipboardHandlerProvider provider) { + if (clipboardHandlerProviders.contains(provider)) { + clipboardHandlerProviders.remove(provider); + } + } public static T cut(T selection) { - + ExtraDesignClassManager manager = PluginModule.getAgent(PluginModule.ExtraDesign); Set providers = manager.getArray(ClipboardHandlerProvider.XML_TAG); + providers.addAll(clipboardHandlerProviders); for (ClipboardHandlerProvider provider : providers) { if (provider.support(selection)) { selection = ((ClipboardHandlerProvider) provider).cut(selection); @@ -25,9 +40,9 @@ public abstract class ClipboardFilter { } public static T copy(T selection) { - ExtraDesignClassManager manager = PluginModule.getAgent(PluginModule.ExtraDesign); Set providers = manager.getArray(ClipboardHandlerProvider.XML_TAG); + providers.addAll(clipboardHandlerProviders); for (ClipboardHandlerProvider provider : providers) { if (provider.support(selection)) { selection = ((ClipboardHandlerProvider) provider).copy(selection); @@ -37,9 +52,10 @@ public abstract class ClipboardFilter { } public static T paste(T selection) { - ExtraDesignClassManager manager = PluginModule.getAgent(PluginModule.ExtraDesign); Set providers = manager.getArray(ClipboardHandlerProvider.XML_TAG); + providers.addAll(clipboardHandlerProviders); + for (ClipboardHandlerProvider provider : providers) { if (provider.support(selection)) { selection = ((ClipboardHandlerProvider) provider).paste(selection); diff --git a/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHandler.java b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHandler.java new file mode 100644 index 000000000..25ab24a32 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHandler.java @@ -0,0 +1,35 @@ +package com.fr.design.base.clipboard; + +public interface ClipboardHandler { + /** + * 剪切 + * + * @param selection 选中 + * @return 处理后的内容 + */ + T cut(T selection); + + /** + * 复制 + * + * @param selection 选中 + * @return 处理后的内容 + */ + T copy(T selection); + + /** + * 粘贴 + * + * @param selection 选中 + * @return 处理后的内容 + */ + T paste(T selection); + + /** + * 支持的类型 + * + * @param selection 内容 + * @return 是否 + */ + boolean support(Object selection); +} diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java new file mode 100644 index 000000000..6e0313ec7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java @@ -0,0 +1,485 @@ +package com.fr.design.gui.controlpane; + +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ilist.JNameEdList; +import com.fr.design.gui.ilist.ListModelElement; +import com.fr.design.gui.ilist.ModNameActionListener; +import com.fr.design.gui.ilist.UINameEdList; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.widget.EventCreator; +import com.fr.form.event.Listener; +import com.fr.form.ui.Widget; +import com.fr.general.NameObject; +import com.fr.report.web.util.ReportEngineEventMapping; +import com.fr.stable.ArrayUtils; +import com.fr.stable.Nameable; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListModel; +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Created by kerry on 5/31/21 + */ +public abstract class UIListGroupControlPane extends UIControlPane implements ListControlPaneProvider { + private boolean isPopulating = false; + private UINameEdList selectNameEdList; + + private Map nameEdListMap = new HashMap<>(); + + private CommonShortCutHandlers commonHandlers; + + private ListControlPaneHelper helper; + + private JPanel contentPane; + + public JPanel getContentPane() { + return contentPane; + } + + private ListControlPaneHelper getHelper() { + if (helper == null) { + helper = ListControlPaneHelper.newInstance(this); + } + return helper; + } + + private CommonShortCutHandlers getCommonHandlers() { + if (commonHandlers == null) { + commonHandlers = CommonShortCutHandlers.newInstance(this); + } + return commonHandlers; + } + + public boolean isPopulating() { + return isPopulating; + } + + @Override + protected void initLeftPane(JPanel leftPane) { + leftPane.add(new UIScrollPane(contentPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 0)), BorderLayout.CENTER); + } + + + protected void refreshPane(Widget widget, NameableCreator[] creators) { + refreshContentPane(widget.supportedEvents()); + refreshNameableCreator(creators); + populateNameObjects(widget); + } + + + private void refreshContentPane(String[] supportedEvents) { + for (String event : supportedEvents) { + if (nameEdListMap.containsKey(event)) { + continue; + } + UINameEdList list = createJNameList(event); + ListWrapperPane wrapperPane = new ListWrapperPane(switchLang(event), list); + if (this.selectNameEdList == null) { + this.selectNameEdList = wrapperPane.getNameEdList(); + } + contentPane.add(wrapperPane); + nameEdListMap.put(event, wrapperPane); + } + } + + protected void populateNameObjects(Widget widget) { + ArrayList nameObjectList = new ArrayList<>(); + for (int i = 0, size = widget.getListenerSize(); i < size; i++) { + Listener listener = widget.getListener(i); + if (!listener.isDefault()) { + nameObjectList.add(i, new NameObject(switchLang(listener.getEventName()) + (i + 1), listener)); + } + } + populate(getHelper().processCatalog(nameObjectList)); + checkButtonEnabled(); + this.repaint(); + } + + private void populate(Map> map) { + isPopulating = true; // 加一个标识位,避免切换单元格时,触发 saveSettings + Iterator>> iterator = map.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + List valueList = entry.getValue(); + ListWrapperPane eventListWrapperPane = nameEdListMap.get(entry.getKey()); + populateChildNameList(eventListWrapperPane.getNameEdList(), valueList.toArray(new NameObject[valueList.size()])); + } + this.checkButtonEnabled(); + refreshEventListWrapperPane(); + isPopulating = false; + } + + private void refreshEventListWrapperPane() { + Iterator> iterator = nameEdListMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + ListWrapperPane eventListWrapperPane = entry.getValue(); + UINameEdList nameEdList = eventListWrapperPane.getNameEdList(); + int listSize = nameEdList.getModel().getSize(); + if (this.selectNameEdList.getModel().getSize() == 0 && listSize > 0) { + this.selectNameEdList = nameEdList; + } + eventListWrapperPane.setVisible(listSize > 0); + } + if (this.selectNameEdList != null) { + this.selectNameEdList.setSelectedIndex(0); + } + this.repaint(); + } + + + private void populateChildNameList(UINameEdList nameableList, Nameable[] nameableArray) { + nameableList.getCellEditor().stopCellEditing(); + DefaultListModel listModel = (DefaultListModel) nameableList.getModel(); + listModel.removeAllElements(); + if (ArrayUtils.isEmpty(nameableArray)) { + isPopulating = false; + return; + } + + listModel.setSize(nameableArray.length); + for (int i = 0; i < nameableArray.length; i++) { + listModel.set(i, new ListModelElement(nameableArray[i])); + } + + } + + + private UINameEdList createJNameList(String text) { + UINameEdList nameEdList = new UINameEdList(new DefaultListModel()) { + @Override + protected void doAfterLostFocus() { + ((JControlUpdatePane) controlUpdatePane).update(); + } + + @Override + protected void doAfterStopEditing() { + saveSettings(); + } + }; + + nameEdList.setCellRenderer(new UINameableListCellRenderer(true, this.creators)); + nameEdList.setName(text); + nameEdList.setSelectionBackground(UIConstants.ATTRIBUTE_PRESS); + nameEdList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + nameEdList.addMouseListener(new MouseAdapter() { + @Override + public void mouseReleased(MouseEvent e) { + selectNameEdList = nameEdList; + updateUINameListSelect(); + } + }); + nameEdList.addMouseListener(getHelper().getListMouseListener(nameEdList, this)); + nameEdList.addModNameActionListener(new ModNameActionListener() { + @Override + public void nameModed(int index, String oldName, String newName) { + saveSettings(); + } + }); + nameEdList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent evt) { + // richie:避免多次update和populate大大降低效率 + if (!evt.getValueIsAdjusting()) { + // shoc 切换的时候加检验 + if (hasInvalid(false)) { + return; + } + ((JControlUpdatePane) UIListGroupControlPane.this.controlUpdatePane).update(); + ((JControlUpdatePane) UIListGroupControlPane.this.controlUpdatePane).populate(); + UIListGroupControlPane.this.checkButtonEnabled(); + } + } + }); + nameEdList.getModel().addListDataListener(new ListDataListener() { + @Override + public void intervalAdded(ListDataEvent e) { + saveSettings(); + } + + @Override + public void intervalRemoved(ListDataEvent e) { + saveSettings(); + } + + @Override + public void contentsChanged(ListDataEvent e) { + saveSettings(); + } + }); + return nameEdList; + } + + private void updateUINameListSelect() { + Iterator> iterator = nameEdListMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + UINameEdList nameEdList = entry.getValue().getNameEdList(); + if (nameEdList != selectNameEdList) { + nameEdList.clearSelection(); + } + } + } + + @Override + public void checkButtonEnabled() { + getHelper().checkButtonEnabled(); + } + + + + private String switchLang(String eventName) { + // 在 properties 文件中找到相应的 key 值 + String localeKey = ReportEngineEventMapping.getLocaleName(eventName); + return com.fr.design.i18n.Toolkit.i18nText(localeKey); + } + + + + /** + * 生成不重复的名字 + * + * @param prefix 名字前缀 + * @return 名字 + */ + @Override + public String createUnrepeatedName(String prefix) { + return getCommonHandlers().createUnrepeatedName(prefix); + } + + private void updateSelectedNameList(NameableCreator creator) { + String eventName = ((EventCreator) creator).getEventName(); + ListWrapperPane wrapperPane = nameEdListMap.get(eventName); + wrapperPane.setVisible(true); + setSelectNameEdList(wrapperPane.getNameEdList()); + } + + private void setSelectNameEdList(UINameEdList nameEdList) { + if (this.selectNameEdList != null) { + this.selectNameEdList.clearSelection(); + } + this.selectNameEdList = nameEdList; + } + + @Override + public void onAddItem(NameableCreator creator) { + updateSelectedNameList(creator); + getCommonHandlers().onAddItem(creator); + } + + @Override + public void onRemoveItem() { + getCommonHandlers().onRemoveItem(); + refreshEventListWrapperPane(); + } + + @Override + public void onCopyItem() { + getCommonHandlers().onCopyItem(); + } + + @Override + public void onMoveUpItem() { + getCommonHandlers().onMoveUpItem(); + } + + @Override + public void onMoveDownItem() { + getCommonHandlers().onMoveDownItem(); + } + + @Override + public void onSortItem(boolean isAtoZ) { + Iterator> iterator = nameEdListMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + UINameEdList nameEdList = entry.getValue().getNameEdList(); + getCommonHandlers().onSortItem(isAtoZ, nameEdList); + } + + } + + @Override + public boolean isItemSelected() { + return getModel().getSize() > 0 && getSelectedIndex() != -1; + } + + + @Override + protected JPanel createControlUpdatePane() { + return JControlUpdatePane.newInstance(this); + } + + + @Override + public Nameable[] update() { + java.util.List res = new java.util.ArrayList(); + getControlUpdatePane().update(); + Iterator> iterator = nameEdListMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + UINameEdList nameEdList = entry.getValue().getNameEdList(); + DefaultListModel listModel = (DefaultListModel) nameEdList.getModel(); + for (int i = 0, len = listModel.getSize(); i < len; i++) { + res.add(((ListModelElement) listModel.getElementAt(i)).wrapper); + } + } + return res.toArray(new Nameable[0]); + } + + + @Override + public abstract NameableCreator[] createNameableCreators(); + + @Override + public abstract void saveSettings(); + + + public BasicBeanPane createPaneByCreators(NameableCreator creator) { + try { + return creator.getUpdatePane().newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public BasicBeanPane createPaneByCreators(NameableCreator creator, String string) { + Constructor constructor = null; + try { + constructor = creator.getUpdatePane().getDeclaredConstructor(new Class[]{String.class}); + constructor.setAccessible(true); + return (BasicBeanPane) constructor.newInstance(string); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + @Override + public DefaultListModel getModel() { + if (this.selectNameEdList == null) { + return new DefaultListModel(); + } + return (DefaultListModel) this.selectNameEdList.getModel(); + } + + /** + * 检查是否符合规范 + * + * @throws Exception + */ + @Override + public void checkValid() throws Exception { + ((JControlUpdatePane) this.controlUpdatePane).checkValid(); + } + + @Override + public boolean hasInvalid(boolean isAdd) { + return getHelper().hasInvalid(isAdd); + } + + public void addNameable(Nameable nameable, int index) { + getHelper().addNameable(nameable, index); + popupEditDialog(); + } + + + /** + * 设置选中项 + * + * @param index 选中项的序列号 + */ + public void setSelectedIndex(int index) { + if (this.selectNameEdList != null) { + this.selectNameEdList.setSelectedIndex(index); + + } + } + + @Override + public int getSelectedIndex() { + if (this.selectNameEdList == null) { + return -1; + } + return this.selectNameEdList.getSelectedIndex(); + } + + + @Override + public ListModelElement getSelectedValue() { + if (this.selectNameEdList == null) { + return null; + } + return (ListModelElement) this.selectNameEdList.getSelectedValue(); + } + + @Override + public JControlUpdatePane getControlUpdatePane() { + return (JControlUpdatePane) controlUpdatePane; + } + + @Override + public JNameEdList getNameableList() { + return this.selectNameEdList; + } + + private void popupEditDialog() { + getHelper().popupEditDialog(null, this.selectNameEdList, this); + } + + protected String getWrapperLabelText(){ + return StringUtils.EMPTY; + } + + + private class ListWrapperPane extends JPanel { + private UINameEdList nameEdList; + + public ListWrapperPane(String labelText, UINameEdList nameEdList) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + UILabel label = new UILabel(labelText + getWrapperLabelText()); + label.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 0)); + label.setBackground(Color.decode("#FFFFFF")); + label.setPreferredSize(new Dimension(224, 26)); + this.nameEdList = nameEdList; + this.add(label, BorderLayout.NORTH); + this.add(this.nameEdList, BorderLayout.CENTER); + } + + public UINameEdList getNameEdList() { + return this.nameEdList; + } + + } + + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/ContentChange.java b/designer-base/src/main/java/com/fr/design/mod/ContentChange.java new file mode 100644 index 000000000..8361d8609 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/ContentChange.java @@ -0,0 +1,29 @@ +package com.fr.design.mod; + +import com.fr.design.mod.bean.ChangeItem; + +import java.util.Map; + +/** + * + * @author hades + * @version 10.0 + * Created by hades on 2021/4/27 + */ +public interface ContentChange { + + /** + * 标识内容替换类型 + * + * @return + */ + String type(); + + /** + * 替换详情信息 + * + * @return + */ + Map> changeInfo(); + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java b/designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java new file mode 100644 index 000000000..72ea9bb63 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java @@ -0,0 +1,66 @@ +package com.fr.design.mod; + +import com.fr.base.Formula; +import com.fr.chart.web.ChartHyperRelateCellLink; +import com.fr.chart.web.ChartHyperRelateFloatLink; +import com.fr.design.file.filter.ClassFilter; +import com.fr.invoke.ClassHelper; +import com.fr.js.JavaScriptImpl; +import com.fr.plugin.chart.base.VanChartHtmlLabel; +import com.fr.stable.Filter; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.jetbrains.annotations.Nullable; + +/** + * 管理所有需要替换内容的对象 + * + * @author hades + * @version 10.0 + * Created by hades on 2021/4/28 + */ +public class ContentObjectManager { + + private static ContentObjectManager INSTANCE = new ContentObjectManager(); + + public static ContentObjectManager getInstance() { + return INSTANCE; + } + + /** + * 放置所有需要替换内容的对象 + */ + private Map> objectMap; + + private final Set set = new HashSet<>(); + + private ContentObjectManager() { + set.add(Formula.class.getName()); + set.add(JavaScriptImpl.class.getName()); + set.add(ChartHyperRelateCellLink.class.getName()); + set.add(ChartHyperRelateFloatLink.class.getName()); + set.add(VanChartHtmlLabel.class.getName()); + } + + public void searchObject(Object ob) { + objectMap = ClassHelper.searchObject(ob, set, ModClassFilter.getInstance()); + } + + public void searchObject(Object ob, Filter filter) { + objectMap = ClassHelper.searchObject(ob, set, filter); + } + + public void searchObject(Object ob, Set set, Filter filter) { + objectMap = ClassHelper.searchObject(ob, set, filter); + } + public void clearObject() { + objectMap = null; + } + + @Nullable + public Map> getObjectMap() { + return objectMap; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/ContentReplaceUtil.java b/designer-base/src/main/java/com/fr/design/mod/ContentReplaceUtil.java new file mode 100644 index 000000000..218c66fad --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/ContentReplaceUtil.java @@ -0,0 +1,20 @@ +package com.fr.design.mod; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/31 + */ +public class ContentReplaceUtil { + + public static final String EQ_STRING = "="; + + public static String replaceContent(String content, String oldName, String newName) { + return content.replaceAll(generateStr(oldName), generateStr(newName)); + } + + private static String generateStr(String str) { + return "\"" + str + "\""; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/ContentReplacer.java b/designer-base/src/main/java/com/fr/design/mod/ContentReplacer.java new file mode 100644 index 000000000..3f7126535 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/ContentReplacer.java @@ -0,0 +1,13 @@ +package com.fr.design.mod; + +/** + * + * @author hades + * @version 10.0 + * Created by hades on 2021/5/27 + */ +public interface ContentReplacer { + + void replace(T t, String oldName, String newName); + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java b/designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java new file mode 100644 index 000000000..3a18a6ea2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java @@ -0,0 +1,108 @@ +package com.fr.design.mod; + +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.bean.ContentChangeItem; +import com.fr.design.mod.event.TableDataModifyEvent; +import com.fr.design.mod.event.WidgetNameModifyEvent; +import com.fr.design.mod.impl.change.ChartHyperRelateCellLinkContentChange; +import com.fr.design.mod.impl.change.ChartHyperRelateFloatLinkContentChange; +import com.fr.design.mod.impl.change.FormulaContentChange; +import com.fr.design.mod.impl.change.JavaScriptContentChange; +import com.fr.design.mod.impl.change.VanChartHtmlLabelContentChange; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.log.FineLoggerFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 默认联动内容替换器实现 + * + * 当前替换顺序:组件名-> 数据集名 + * + * @author hades + * @version 10.0 + * Created by hades on 2021/5/27 + */ +public class ContentReplacerCenter { + + private static final ContentReplacerCenter INSTANCE = new ContentReplacerCenter(); + + public static ContentReplacerCenter getInstance() { + return INSTANCE; + } + + private List contentChangeList = new ArrayList<>(); + private List items = new ArrayList<>(); + + private ContentReplacerCenter() { + + EventDispatcher.listen(WidgetNameModifyEvent.INSTANCE, new Listener() { + @Override + public void on(Event event, ContentChangeItem param) { + if (param.getChangeMap().isEmpty()) { + return; + } + items.add(param); + } + }); + + EventDispatcher.listen(TableDataModifyEvent.INSTANCE, new Listener() { + @Override + public void on(Event event, ContentChangeItem param) { + items.add(param); + long start = System.currentTimeMillis(); + ContentObjectManager.getInstance().searchObject(param.getObject()); + FineLoggerFactory.getLogger().debug("search object spend {} ms", (System.currentTimeMillis() - start)); + FineLoggerFactory.getLogger().debug("search result: {}", ContentObjectManager.getInstance().getObjectMap() == null + ? null : ContentObjectManager.getInstance().getObjectMap().keySet()); + List itemsCopy = new ArrayList<>(items); + items.clear(); + onRename(itemsCopy, contentChangeList); + } + }); + + } + + public void register() { + contentChangeList.add(new ChartHyperRelateCellLinkContentChange()); + contentChangeList.add(new ChartHyperRelateFloatLinkContentChange()); + contentChangeList.add(new FormulaContentChange()); + contentChangeList.add(new JavaScriptContentChange()); + contentChangeList.add(new VanChartHtmlLabelContentChange()); + } + + private void onRename(List contentChangeItemList, List contentChangeList) { + Map> objectMap = ContentObjectManager.getInstance().getObjectMap(); + if (objectMap != null) { + long start = System.currentTimeMillis(); + for (ContentChange contentChange : contentChangeList) { + Set set = objectMap.get(contentChange.type()); + // 所有需要处理的js等对象 + if (set != null) { + for (Object ob : set) { + fireChange(ob, contentChange, contentChangeItemList); + } + } + } + objectMap.clear(); + FineLoggerFactory.getLogger().debug("replace all content spend {} ms", (System.currentTimeMillis() - start)); + } + } + + private void fireChange(Object o, ContentChange contentChange, List itemList) { + // 当前两项存在两项: 数据集名称和组件名称 + for (ContentChangeItem contentChangeItem : itemList) { + Map map = contentChange.changeInfo(); + if (map.containsKey(contentChangeItem.getChangeItem())) { + // 具体重命名取决于复用组件存在多少个组件或数据集 + for (Map.Entry entry : contentChangeItem.getChangeMap().entrySet()) { + map.get(contentChangeItem.getChangeItem()).replace(o, entry.getKey(), entry.getValue()); + } + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mod/ModClassFilter.java b/designer-base/src/main/java/com/fr/design/mod/ModClassFilter.java new file mode 100644 index 000000000..4bf02549a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/ModClassFilter.java @@ -0,0 +1,33 @@ +package com.fr.design.mod; + +import com.fr.stable.Filter; +import java.util.HashSet; +import java.util.Set; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/31 + */ +public class ModClassFilter implements Filter { + + private static final Set FILTER_SET = new HashSet<>(); + + private static final Filter INSTANCE = new ModClassFilter(); + + public static Filter getInstance() { + return INSTANCE; + } + + static { + FILTER_SET.add("java.awt.image.BufferedImage"); + FILTER_SET.add("sun.awt.AppContext"); + FILTER_SET.add("com.fr.poly.creator.ECBlockCreator"); + FILTER_SET.add("io.netty.channel.nio.SelectedSelectionKeySet"); + } + + @Override + public boolean accept(String s) { + return FILTER_SET.contains(s); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mod/bean/ChangeItem.java b/designer-base/src/main/java/com/fr/design/mod/bean/ChangeItem.java new file mode 100644 index 000000000..179a3819b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/bean/ChangeItem.java @@ -0,0 +1,14 @@ +package com.fr.design.mod.bean; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public enum ChangeItem { + + TABLE_DATA_NAME, + + WIDGET_NAME + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/bean/ContentChangeItem.java b/designer-base/src/main/java/com/fr/design/mod/bean/ContentChangeItem.java new file mode 100644 index 000000000..8904a0c45 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/bean/ContentChangeItem.java @@ -0,0 +1,33 @@ +package com.fr.design.mod.bean; + +import java.util.Map; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class ContentChangeItem { + + private final Map changeMap; + private final ChangeItem changeItem; + private final Object object; + + public ContentChangeItem(Map changeMap,Object object, ChangeItem changeItem) { + this.changeMap = changeMap; + this.changeItem = changeItem; + this.object = object; + } + + public Map getChangeMap() { + return changeMap; + } + + public ChangeItem getChangeItem() { + return changeItem; + } + + public Object getObject() { + return object; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mod/event/ModifyEvent.java b/designer-base/src/main/java/com/fr/design/mod/event/ModifyEvent.java new file mode 100644 index 000000000..a5debb430 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/event/ModifyEvent.java @@ -0,0 +1,13 @@ +package com.fr.design.mod.event; + +import com.fr.design.mod.bean.ContentChangeItem; +import com.fr.event.Event; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class ModifyEvent implements Event { + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/event/TableDataModifyEvent.java b/designer-base/src/main/java/com/fr/design/mod/event/TableDataModifyEvent.java new file mode 100644 index 000000000..6359682cf --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/event/TableDataModifyEvent.java @@ -0,0 +1,12 @@ +package com.fr.design.mod.event; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class TableDataModifyEvent extends ModifyEvent { + + public static final TableDataModifyEvent INSTANCE = new TableDataModifyEvent(); + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/event/WidgetNameModifyEvent.java b/designer-base/src/main/java/com/fr/design/mod/event/WidgetNameModifyEvent.java new file mode 100644 index 000000000..d3d8a9164 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/event/WidgetNameModifyEvent.java @@ -0,0 +1,12 @@ +package com.fr.design.mod.event; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class WidgetNameModifyEvent extends ModifyEvent { + + public static final WidgetNameModifyEvent INSTANCE = new WidgetNameModifyEvent(); + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateCellLinkContentChange.java b/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateCellLinkContentChange.java new file mode 100644 index 000000000..8b8b32e81 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateCellLinkContentChange.java @@ -0,0 +1,16 @@ +package com.fr.design.mod.impl.change; + +import com.fr.chart.web.ChartHyperRelateCellLink; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class ChartHyperRelateCellLinkContentChange extends ChartHyperRelateLinkContentChange { + + @Override + public String type() { + return ChartHyperRelateCellLink.class.getName(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateFloatLinkContentChange.java b/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateFloatLinkContentChange.java new file mode 100644 index 000000000..dc3cf04ae --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateFloatLinkContentChange.java @@ -0,0 +1,16 @@ +package com.fr.design.mod.impl.change; + +import com.fr.chart.web.ChartHyperRelateFloatLink; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class ChartHyperRelateFloatLinkContentChange extends ChartHyperRelateLinkContentChange{ + + @Override + public String type() { + return ChartHyperRelateFloatLink.class.getName(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateLinkContentChange.java b/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateLinkContentChange.java new file mode 100644 index 000000000..139bda0c2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/change/ChartHyperRelateLinkContentChange.java @@ -0,0 +1,30 @@ +package com.fr.design.mod.impl.change; + +import com.fr.chart.web.ChartHyperRelateLink; +import com.fr.design.mod.ContentChange; +import com.fr.design.mod.ContentReplacer; +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.impl.repalce.ChartHyperRelateLink4WidgetNameContentReplacer; +import java.util.HashMap; +import java.util.Map; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/27 + */ +public abstract class ChartHyperRelateLinkContentChange implements ContentChange { + + private final Map> map; + + public ChartHyperRelateLinkContentChange() { + this.map = new HashMap<>(); + map.put(ChangeItem.WIDGET_NAME, new ChartHyperRelateLink4WidgetNameContentReplacer()); + } + + @Override + public Map> changeInfo() { + return map; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/change/FormulaContentChange.java b/designer-base/src/main/java/com/fr/design/mod/impl/change/FormulaContentChange.java new file mode 100644 index 000000000..de69b49d5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/change/FormulaContentChange.java @@ -0,0 +1,37 @@ +package com.fr.design.mod.impl.change; + +import com.fr.base.Formula; +import com.fr.design.mod.ContentChange; +import com.fr.design.mod.ContentReplacer; +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.impl.repalce.Formula4TableDataNameContentReplacer; +import com.fr.design.mod.impl.repalce.Formula4WidgetNameContentReplacer; +import java.util.HashMap; +import java.util.Map; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/27 + */ +public class FormulaContentChange implements ContentChange { + + private final Map> map; + + public FormulaContentChange() { + map = new HashMap<>(); + map.put(ChangeItem.WIDGET_NAME, new Formula4WidgetNameContentReplacer()); + map.put(ChangeItem.TABLE_DATA_NAME, new Formula4TableDataNameContentReplacer()); + } + + @Override + public String type() { + return Formula.class.getName(); + } + + @Override + public Map> changeInfo() { + return map; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/change/JavaScriptContentChange.java b/designer-base/src/main/java/com/fr/design/mod/impl/change/JavaScriptContentChange.java new file mode 100644 index 000000000..62653349c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/change/JavaScriptContentChange.java @@ -0,0 +1,36 @@ +package com.fr.design.mod.impl.change; + +import com.fr.design.mod.ContentChange; +import com.fr.design.mod.ContentReplacer; +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.impl.repalce.JavaScriptContentReplacer; +import com.fr.js.JavaScriptImpl; +import java.util.HashMap; +import java.util.Map; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/27 + */ +public class JavaScriptContentChange implements ContentChange { + + private final Map> map; + + public JavaScriptContentChange() { + map = new HashMap<>(); + map.put(ChangeItem.WIDGET_NAME, new JavaScriptContentReplacer()); + map.put(ChangeItem.TABLE_DATA_NAME, new JavaScriptContentReplacer()); + } + + @Override + public String type() { + return JavaScriptImpl.class.getName(); + } + + @Override + public Map> changeInfo() { + return map; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/change/VanChartHtmlLabelContentChange.java b/designer-base/src/main/java/com/fr/design/mod/impl/change/VanChartHtmlLabelContentChange.java new file mode 100644 index 000000000..a51fd732d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/change/VanChartHtmlLabelContentChange.java @@ -0,0 +1,35 @@ +package com.fr.design.mod.impl.change; + +import com.fr.design.mod.ContentChange; +import com.fr.design.mod.ContentReplacer; +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.impl.repalce.VanChartHtmlLabelContentReplacer; +import com.fr.plugin.chart.base.VanChartHtmlLabel; +import java.util.HashMap; +import java.util.Map; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/31 + */ +public class VanChartHtmlLabelContentChange implements ContentChange { + + private final Map> map; + + public VanChartHtmlLabelContentChange() { + map = new HashMap<>(); + map.put(ChangeItem.WIDGET_NAME, new VanChartHtmlLabelContentReplacer()); + map.put(ChangeItem.TABLE_DATA_NAME, new VanChartHtmlLabelContentReplacer()); + } + + @Override + public String type() { + return VanChartHtmlLabel.class.getName(); + } + + @Override + public Map> changeInfo() { + return map; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/repalce/ChartHyperRelateLink4WidgetNameContentReplacer.java b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/ChartHyperRelateLink4WidgetNameContentReplacer.java new file mode 100644 index 000000000..9fa32280f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/ChartHyperRelateLink4WidgetNameContentReplacer.java @@ -0,0 +1,21 @@ +package com.fr.design.mod.impl.repalce; + +import com.fr.chart.web.ChartHyperRelateLink; +import com.fr.design.mod.ContentReplacer; +import com.fr.general.ComparatorUtils; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class ChartHyperRelateLink4WidgetNameContentReplacer implements ContentReplacer { + + @Override + public void replace(ChartHyperRelateLink chartHyperRelateLink, String oldName, String newName) { + if (ComparatorUtils.equals(chartHyperRelateLink.getRelateCCName(), oldName)) { + chartHyperRelateLink.setRelateCCName(newName); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/repalce/Formula4TableDataNameContentReplacer.java b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/Formula4TableDataNameContentReplacer.java new file mode 100644 index 000000000..8f4dafa2a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/Formula4TableDataNameContentReplacer.java @@ -0,0 +1,22 @@ +package com.fr.design.mod.impl.repalce; + +import com.fr.base.Formula; +import com.fr.design.mod.ContentReplaceUtil; +import com.fr.design.mod.ContentReplacer; +import com.fr.parser.FRFormulaTransformer; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class Formula4TableDataNameContentReplacer implements ContentReplacer { + + @Override + public void replace(Formula formula, String oldName, String newName) { + FRFormulaTransformer frFormulaTransformer = new FRFormulaTransformer(); + frFormulaTransformer.addRenamedDataset(oldName, newName); + formula.setContent(ContentReplaceUtil.EQ_STRING + frFormulaTransformer.transform(formula.getPureContent())); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/repalce/Formula4WidgetNameContentReplacer.java b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/Formula4WidgetNameContentReplacer.java new file mode 100644 index 000000000..0e0e2e05f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/Formula4WidgetNameContentReplacer.java @@ -0,0 +1,21 @@ +package com.fr.design.mod.impl.repalce; + +import com.fr.base.Formula; +import com.fr.design.mod.ContentReplaceUtil; +import com.fr.design.mod.ContentReplacer; +import com.fr.parser.FRFormulaTransformer; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class Formula4WidgetNameContentReplacer implements ContentReplacer { + + @Override + public void replace(Formula formula, String oldName, String newName) { + FRFormulaTransformer frFormulaTransformer = new FRFormulaTransformer(); + frFormulaTransformer.addRenamedWidget(oldName, newName); + formula.setContent(ContentReplaceUtil.EQ_STRING + frFormulaTransformer.transform(formula.getPureContent())); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/repalce/JavaScriptContentReplacer.java b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/JavaScriptContentReplacer.java new file mode 100644 index 000000000..118f1b79c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/JavaScriptContentReplacer.java @@ -0,0 +1,22 @@ +package com.fr.design.mod.impl.repalce; + +import com.fr.design.mod.ContentReplacer; +import com.fr.design.mod.ContentReplaceUtil; +import com.fr.js.JavaScriptImpl; +import com.fr.stable.StringUtils; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/28 + */ +public class JavaScriptContentReplacer implements ContentReplacer { + + @Override + public void replace(JavaScriptImpl javaScript, String oldName, String newName) { + if (StringUtils.isNotEmpty(javaScript.getContent())) { + javaScript.setContent(ContentReplaceUtil.replaceContent(javaScript.getContent(), oldName, newName)); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mod/impl/repalce/VanChartHtmlLabelContentReplacer.java b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/VanChartHtmlLabelContentReplacer.java new file mode 100644 index 000000000..95cd12e0a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mod/impl/repalce/VanChartHtmlLabelContentReplacer.java @@ -0,0 +1,22 @@ +package com.fr.design.mod.impl.repalce; + +import com.fr.design.mod.ContentReplacer; +import com.fr.design.mod.ContentReplaceUtil; +import com.fr.plugin.chart.base.VanChartHtmlLabel; +import com.fr.stable.StringUtils; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/5/31 + */ +public class VanChartHtmlLabelContentReplacer implements ContentReplacer { + + @Override + public void replace(VanChartHtmlLabel vanChartHtmlLabel, String oldName, String newName) { + if (StringUtils.isNotEmpty(vanChartHtmlLabel.getCustomText())) { + vanChartHtmlLabel.setCustomText( + ContentReplaceUtil.replaceContent(vanChartHtmlLabel.getCustomText(), oldName, newName)); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/ModelUtil.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/ModelUtil.java index 32d217adc..10e672f58 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/models/ModelUtil.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/ModelUtil.java @@ -2,11 +2,17 @@ package com.fr.design.designer.beans.models; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XWParameterLayout; +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.bean.ContentChangeItem; +import com.fr.design.mod.event.WidgetNameModifyEvent; +import com.fr.event.EventDispatcher; import com.fr.form.main.Form; import com.fr.form.ui.Widget; import com.fr.stable.StringUtils; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -25,10 +31,16 @@ abstract class ModelUtil { Set nameRelatedCreators = new HashSet<>(); //直接遍历出来目标值,然后按需处理 xCreator.traversalNameRelatedXCreators(nameRelatedCreators); + Map renameMap = new HashMap<>(); for (XCreator target : nameRelatedCreators) { String uniqueName = uniqueName(form, target, duplicated); + String oldName = target.toData().getWidgetName(); + if (StringUtils.isNotEmpty(oldName)) { + renameMap.put(oldName, uniqueName); + } target.resetCreatorName(uniqueName); } + EventDispatcher.fire(WidgetNameModifyEvent.INSTANCE, new ContentChangeItem(renameMap, xCreator.toData(), ChangeItem.WIDGET_NAME)); } private static String uniqueName(Form form, XCreator xCreator, Set duplicated) { diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java index dc74087c4..d105aaf48 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java @@ -25,6 +25,7 @@ import com.fr.design.fun.FormWidgetOptionProvider; import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.FormSelection; import com.fr.design.mainframe.FormSelectionUtils; +import com.fr.design.mainframe.share.encrypt.clipboard.impl.EncryptSelectionClipboardHandler; import com.fr.design.utils.ComponentUtils; import com.fr.design.utils.gui.LayoutUtils; import com.fr.general.ComparatorUtils; diff --git a/designer-form/src/main/java/com/fr/design/gui/controlpane/EventPropertyPane.java b/designer-form/src/main/java/com/fr/design/gui/controlpane/EventPropertyPane.java index 25cefe3af..72ff96982 100644 --- a/designer-form/src/main/java/com/fr/design/gui/controlpane/EventPropertyPane.java +++ b/designer-form/src/main/java/com/fr/design/gui/controlpane/EventPropertyPane.java @@ -1,93 +1,30 @@ package com.fr.design.gui.controlpane; - -import com.fr.design.beans.BasicBeanPane; -import com.fr.design.constants.UIConstants; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.properties.EventPropertyTable; -import com.fr.design.gui.icontainer.UIScrollPane; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.gui.ilist.JNameEdList; -import com.fr.design.gui.ilist.ListModelElement; -import com.fr.design.gui.ilist.ModNameActionListener; -import com.fr.design.gui.ilist.UINameEdList; import com.fr.design.i18n.Toolkit; -import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.FormDesigner; import com.fr.design.widget.EventCreator; import com.fr.form.event.Listener; import com.fr.form.ui.Widget; import com.fr.general.NameObject; -import com.fr.report.web.util.ReportEngineEventMapping; -import com.fr.stable.ArrayUtils; import com.fr.stable.Nameable; -import javax.swing.BorderFactory; -import javax.swing.DefaultListModel; -import javax.swing.JPanel; -import javax.swing.ListSelectionModel; -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; /** * Created by kerry on 5/17/21 */ -public class EventPropertyPane extends UIControlPane implements ListControlPaneProvider { +public class EventPropertyPane extends UIListGroupControlPane { private XCreator creator; - private boolean isPopulating = false; - private UINameEdList selectNameEdList; - - private Map nameEdListMap = new HashMap<>(); - - private CommonShortCutHandlers commonHandlers; - - private ListControlPaneHelper helper; - - private JPanel contentPane; private FormDesigner designer; - private ListControlPaneHelper getHelper() { - if (helper == null) { - helper = ListControlPaneHelper.newInstance(this); - } - return helper; - } - - private CommonShortCutHandlers getCommonHandlers() { - if (commonHandlers == null) { - commonHandlers = CommonShortCutHandlers.newInstance(this); - } - return commonHandlers; - } - - public EventPropertyPane(FormDesigner designer) { super(); this.designer = designer; } - @Override - protected void initLeftPane(JPanel leftPane) { - leftPane.add(new UIScrollPane(contentPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 0)), BorderLayout.CENTER); - } - /** * 刷新 */ @@ -98,184 +35,19 @@ public class EventPropertyPane extends UIControlPane implements ListControlPaneP .getSelection().getSelectedCreator(); } else { this.creator = null; - contentPane.removeAll(); + this.getContentPane().removeAll(); checkButtonEnabled(); return; } Widget widget = creator.toData(); - - refreshContentPane(widget.supportedEvents()); - refreshNameableCreator(EventCreator.createEventCreator(widget.supportedEvents(), EventPropertyTable.WidgetEventListenerUpdatePane.class)); - populateNameObjects(); + refreshPane(widget, EventCreator.createEventCreator(widget.supportedEvents(), EventPropertyTable.WidgetEventListenerUpdatePane.class)); } - private void refreshContentPane(String[] supportedEvents) { - for (String event : supportedEvents) { - if (nameEdListMap.containsKey(event)) { - continue; - } - UINameEdList list = createJNameList(event); - EventListWrapperPane wrapperPane = new EventListWrapperPane(switchLang(event), list); - if (this.selectNameEdList == null) { - this.selectNameEdList = wrapperPane.getNameEdList(); - } - contentPane.add(wrapperPane); - nameEdListMap.put(event, wrapperPane); - } - } public void populateNameObjects() { Widget widget = creator.toData(); - - ArrayList nameObjectList = new ArrayList<>(); - for (int i = 0, size = widget.getListenerSize(); i < size; i++) { - Listener listener = widget.getListener(i); - if (!listener.isDefault()) { - nameObjectList.add(i, new NameObject(switchLang(listener.getEventName()) + (i + 1), listener)); - } - } - populate(getHelper().processCatalog(nameObjectList)); - checkButtonEnabled(); - this.repaint(); - } - - public void populate(Map> map) { - isPopulating = true; // 加一个标识位,避免切换单元格时,触发 saveSettings - Iterator>> iterator = map.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry> entry = iterator.next(); - List valueList = entry.getValue(); - EventListWrapperPane eventListWrapperPane = nameEdListMap.get(entry.getKey()); - populateChildNameList(eventListWrapperPane.getNameEdList(), valueList.toArray(new NameObject[valueList.size()])); - } - this.checkButtonEnabled(); - refreshEventListWrapperPane(); - isPopulating = false; - } - - private void refreshEventListWrapperPane() { - Iterator> iterator = nameEdListMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - EventListWrapperPane eventListWrapperPane = entry.getValue(); - UINameEdList nameEdList = eventListWrapperPane.getNameEdList(); - int listSize = nameEdList.getModel().getSize(); - if (this.selectNameEdList.getModel().getSize() == 0 && listSize > 0) { - this.selectNameEdList = nameEdList; - } - eventListWrapperPane.setVisible(listSize > 0); - } - if (this.selectNameEdList != null) { - this.selectNameEdList.setSelectedIndex(0); - } - this.repaint(); - } - - - private void populateChildNameList(UINameEdList nameableList, Nameable[] nameableArray) { - nameableList.getCellEditor().stopCellEditing(); - DefaultListModel listModel = (DefaultListModel) nameableList.getModel(); - listModel.removeAllElements(); - if (ArrayUtils.isEmpty(nameableArray)) { - isPopulating = false; - return; - } - - listModel.setSize(nameableArray.length); - for (int i = 0; i < nameableArray.length; i++) { - listModel.set(i, new ListModelElement(nameableArray[i])); - } - - } - - - protected UINameEdList createJNameList(String text) { - UINameEdList nameEdList = new UINameEdList(new DefaultListModel()) { - @Override - protected void doAfterLostFocus() { - ((JControlUpdatePane) controlUpdatePane).update(); - } - - @Override - protected void doAfterStopEditing() { - saveSettings(); - } - }; - - nameEdList.setCellRenderer(new UINameableListCellRenderer(true, this.creators)); - nameEdList.setName(text); - nameEdList.setSelectionBackground(UIConstants.ATTRIBUTE_PRESS); - nameEdList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - nameEdList.addMouseListener(new MouseAdapter() { - @Override - public void mouseReleased(MouseEvent e) { - selectNameEdList = nameEdList; - updateUINameListSelect(); - } - }); - nameEdList.addMouseListener(getHelper().getListMouseListener(nameEdList, this)); - nameEdList.addModNameActionListener(new ModNameActionListener() { - @Override - public void nameModed(int index, String oldName, String newName) { - saveSettings(); - } - }); - nameEdList.addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent evt) { - // richie:避免多次update和populate大大降低效率 - if (!evt.getValueIsAdjusting()) { - // shoc 切换的时候加检验 - if (hasInvalid(false)) { - return; - } - ((JControlUpdatePane) EventPropertyPane.this.controlUpdatePane).update(); - ((JControlUpdatePane) EventPropertyPane.this.controlUpdatePane).populate(); - EventPropertyPane.this.checkButtonEnabled(); - } - } - }); - nameEdList.getModel().addListDataListener(new ListDataListener() { - @Override - public void intervalAdded(ListDataEvent e) { - saveSettings(); - } - - @Override - public void intervalRemoved(ListDataEvent e) { - saveSettings(); - } - - @Override - public void contentsChanged(ListDataEvent e) { - saveSettings(); - } - }); - return nameEdList; - } - - private void updateUINameListSelect() { - Iterator> iterator = nameEdListMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - UINameEdList nameEdList = entry.getValue().getNameEdList(); - if (nameEdList != selectNameEdList) { - nameEdList.clearSelection(); - } - } - } - - @Override - public void checkButtonEnabled() { - getHelper().checkButtonEnabled(); - } - - - - private String switchLang(String eventName) { - // 在 properties 文件中找到相应的 key 值 - String localeKey = ReportEngineEventMapping.getLocaleName(eventName); - return com.fr.design.i18n.Toolkit.i18nText(localeKey); + populateNameObjects(widget); } /** @@ -296,98 +68,6 @@ public class EventPropertyPane extends UIControlPane implements ListControlPaneP } - /** - * 生成不重复的名字 - * - * @param prefix 名字前缀 - * @return 名字 - */ - @Override - public String createUnrepeatedName(String prefix) { - return getCommonHandlers().createUnrepeatedName(prefix); - } - - private void updateSelectedNameList(NameableCreator creator) { - String eventName = ((EventCreator) creator).getEventName(); - EventListWrapperPane wrapperPane = nameEdListMap.get(eventName); - wrapperPane.setVisible(true); - setSelectNameEdList(wrapperPane.getNameEdList()); - } - - private void setSelectNameEdList(UINameEdList nameEdList) { - if (this.selectNameEdList != null) { - this.selectNameEdList.clearSelection(); - } - this.selectNameEdList = nameEdList; - } - - @Override - public void onAddItem(NameableCreator creator) { - updateSelectedNameList(creator); - getCommonHandlers().onAddItem(creator); - } - - @Override - public void onRemoveItem() { - getCommonHandlers().onRemoveItem(); - refreshEventListWrapperPane(); - } - - @Override - public void onCopyItem() { - getCommonHandlers().onCopyItem(); - } - - @Override - public void onMoveUpItem() { - getCommonHandlers().onMoveUpItem(); - } - - @Override - public void onMoveDownItem() { - getCommonHandlers().onMoveDownItem(); - } - - @Override - public void onSortItem(boolean isAtoZ) { - Iterator> iterator = nameEdListMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - UINameEdList nameEdList = entry.getValue().getNameEdList(); - getCommonHandlers().onSortItem(isAtoZ, nameEdList); - } - - } - - @Override - public boolean isItemSelected() { - return getModel().getSize() > 0 && getSelectedIndex() != -1; - } - - - @Override - protected JPanel createControlUpdatePane() { - return JControlUpdatePane.newInstance(this); - } - - - @Override - public Nameable[] update() { - java.util.List res = new java.util.ArrayList(); - getControlUpdatePane().update(); - Iterator> iterator = nameEdListMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - UINameEdList nameEdList = entry.getValue().getNameEdList(); - DefaultListModel listModel = (DefaultListModel) nameEdList.getModel(); - for (int i = 0, len = listModel.getSize(); i < len; i++) { - res.add(((ListModelElement) listModel.getElementAt(i)).wrapper); - } - } - return res.toArray(new Nameable[0]); - } - - @Override public NameableCreator[] createNameableCreators() { return new NameableCreator[]{ @@ -397,7 +77,7 @@ public class EventPropertyPane extends UIControlPane implements ListControlPaneP @Override public void saveSettings() { - if (isPopulating) { + if (isPopulating()) { return; } updateWidgetListener(creator); @@ -413,123 +93,8 @@ public class EventPropertyPane extends UIControlPane implements ListControlPaneP return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Add_Event"); } - public BasicBeanPane createPaneByCreators(NameableCreator creator) { - try { - return creator.getUpdatePane().newInstance(); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public BasicBeanPane createPaneByCreators(NameableCreator creator, String string) { - Constructor constructor = null; - try { - constructor = creator.getUpdatePane().getDeclaredConstructor(new Class[]{String.class}); - constructor.setAccessible(true); - return (BasicBeanPane) constructor.newInstance(string); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - @Override - public DefaultListModel getModel() { - if (this.selectNameEdList == null) { - return new DefaultListModel(); - } - return (DefaultListModel) this.selectNameEdList.getModel(); - } - - /** - * 检查是否符合规范 - * - * @throws Exception - */ - @Override - public void checkValid() throws Exception { - ((JControlUpdatePane) this.controlUpdatePane).checkValid(); - } - - @Override - public boolean hasInvalid(boolean isAdd) { - return getHelper().hasInvalid(isAdd); - } - - public void addNameable(Nameable nameable, int index) { - getHelper().addNameable(nameable, index); - popupEditDialog(); + protected String getWrapperLabelText(){ + return Toolkit.i18nText("Fine-Design_Report_Event"); } - - /** - * 设置选中项 - * - * @param index 选中项的序列号 - */ - public void setSelectedIndex(int index) { - if (this.selectNameEdList != null) { - this.selectNameEdList.setSelectedIndex(index); - - } - } - - @Override - public int getSelectedIndex() { - if (this.selectNameEdList == null) { - return -1; - } - return this.selectNameEdList.getSelectedIndex(); - } - - - @Override - public ListModelElement getSelectedValue() { - if (this.selectNameEdList == null) { - return null; - } - return (ListModelElement) this.selectNameEdList.getSelectedValue(); - } - - @Override - public JControlUpdatePane getControlUpdatePane() { - return (JControlUpdatePane) controlUpdatePane; - } - - @Override - public JNameEdList getNameableList() { - return this.selectNameEdList; - } - - private void popupEditDialog() { - getHelper().popupEditDialog(null, this.selectNameEdList, this); - } - - - private class EventListWrapperPane extends JPanel { - private UINameEdList nameEdList; - - public EventListWrapperPane(String labelText, UINameEdList nameEdList) { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - UILabel label = new UILabel(labelText + Toolkit.i18nText("Fine-Design_Report_Event")); - label.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 0)); - label.setBackground(Color.decode("#FFFFFF")); - label.setPreferredSize(new Dimension(226, 26)); - this.nameEdList = nameEdList; - this.add(label, BorderLayout.NORTH); - this.add(this.nameEdList, BorderLayout.CENTER); - } - - public UINameEdList getNameEdList() { - return this.nameEdList; - } - - } } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java b/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java index eb036239b..1b8940064 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java @@ -21,7 +21,11 @@ import com.fr.design.form.util.XCreatorConstants; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.icon.IconPathConstants; import com.fr.design.mainframe.chart.info.ChartInfoCollector; +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.bean.ContentChangeItem; +import com.fr.design.mod.event.TableDataModifyEvent; import com.fr.design.utils.ComponentUtils; +import com.fr.event.EventDispatcher; import com.fr.form.share.editor.SharableEditorProvider; import com.fr.form.share.SharableWidgetProvider; import com.fr.form.share.ShareLoader; @@ -29,6 +33,7 @@ import com.fr.form.ui.Widget; import com.fr.stable.Constants; import com.fr.stable.StringUtils; +import java.util.Collections; import javax.swing.BorderFactory; import javax.swing.JWindow; import java.util.List; @@ -102,14 +107,16 @@ public class FormCreatorDropTarget extends DropTarget { String shareId = addingXCreator.getShareId(); SharableEditorProvider sharableEditor = ShareLoader.getLoader().getSharedElCaseEditorById(shareId); SharableWidgetProvider bindInfo = ShareLoader.getLoader().getElCaseBindInfoById(shareId); + Map tdNameMap = Collections.emptyMap(); if (sharableEditor != null && bindInfo != null) { - Map tdNameMap = TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).addTableData(bindInfo.getName(), sharableEditor.getTableDataSource(), true); + tdNameMap = TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).addTableData(bindInfo.getName(), sharableEditor.getTableDataSource(), true); //合并数据集之后,可能会有数据集名称变化,做一下联动 //共享的组件拿的时候都是克隆的,这边改拖拽中克隆的对象而非新克隆对象,上面这个新克隆的对象只是为了拿数据集 for (Map.Entry entry : tdNameMap.entrySet()) { designer.getTarget().renameTableData(widget, entry.getKey(), entry.getValue()); } } + EventDispatcher.fire(TableDataModifyEvent.INSTANCE, new ContentChangeItem(tdNameMap, widget, ChangeItem.TABLE_DATA_NAME)); } designer.getSelectionModel().setSelectedCreators( FormSelectionUtils.rebuildSelection(xCreator, new Widget[]{widget})); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/AbstractCrossClipBoardState.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/AbstractCrossClipBoardState.java new file mode 100644 index 000000000..f99349134 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/AbstractCrossClipBoardState.java @@ -0,0 +1,62 @@ +package com.fr.design.mainframe.share.encrypt.clipboard; + +import com.fr.stable.StringUtils; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * 跨模版禁用 + *

+ * created by Harrison on 2020/05/14 + **/ +public abstract class AbstractCrossClipBoardState implements CrossClipboardState { + private final AtomicReference sourceId = new AtomicReference<>(); + + @Override + public synchronized boolean isBan() { + + String sourceId = this.sourceId.get(); + if (StringUtils.isEmpty(sourceId)) { + return false; + } + //这里只获取新的,不能更新 + //因为新的模板可能不是限制模板,然而剪贴板中的内容没有清空。 + //所以,直接在新的模板中再一次粘贴,就可以避过限制 + String targetId = get(); + return isCross(sourceId, targetId) && isRestrict(sourceId); + } + + protected boolean isRestrict(String sourceId) { + + return true; + } + + @Override + public synchronized void mark() { + + update(); + } + + private String get() { + + return currentId(); + } + + private void update() { + + String templateId = currentId(); + sourceId.set(templateId); + } + + private boolean isCross(String sourceId, String targetId) { + + //源 id 不等于 null + //如果源 id 等于 null , 两种情况 + //1-之前没有 + //2-是从其他地方,复制过来,这样的话,直接通过就好了。 + return StringUtils.isNotEmpty(sourceId) + && !StringUtils.equals(sourceId, targetId); + } + + protected abstract String currentId(); +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/CrossClipboardHandler.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/CrossClipboardHandler.java new file mode 100644 index 000000000..f00ab8302 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/CrossClipboardHandler.java @@ -0,0 +1,79 @@ +package com.fr.design.mainframe.share.encrypt.clipboard; + +import com.fr.design.fun.impl.AbstractClipboardHandlerProvider; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * created by Harrison on 2020/05/14 + **/ +public abstract class CrossClipboardHandler extends AbstractClipboardHandlerProvider { + + private List states = new ArrayList<>(8); + + public CrossClipboardHandler(CrossClipboardState... states) { + + init(states); + } + + private void init(CrossClipboardState... states) { + + if (states == null) { + return; + } + Collections.addAll(this.states, states); + } + + @Override + public T cut(T selection) { + + mark(); + return cut0(selection); + } + + protected T cut0(T selection) { + + return selection; + } + + @Override + public T copy(T selection) { + + mark(); + return copy0(selection); + } + + protected T copy0(T selection) { + + return selection; + } + + @Override + public T paste(T selection) { + + return isBan() ? null : paste0(selection); + } + + protected T paste0(T selection) { + + return selection; + } + + private void mark() { + + for (CrossClipboardState state : states) { + state.mark(); + } + } + + private boolean isBan() { + + boolean isBan = false; + for (CrossClipboardState state : states) { + isBan |= state.isBan(); + } + return isBan; + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/CrossClipboardState.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/CrossClipboardState.java new file mode 100644 index 000000000..4458ded3a --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/CrossClipboardState.java @@ -0,0 +1,22 @@ +package com.fr.design.mainframe.share.encrypt.clipboard; + +/** + * created by Harrison on 2020/05/18 + **/ +public interface CrossClipboardState { + + + /** + * 是否禁用 + * + * @return y/n + */ + boolean isBan(); + + /** + * 标记状态 + */ + void mark(); +} + + diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/RestrictTemplateSet.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/RestrictTemplateSet.java new file mode 100644 index 000000000..bd781641c --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/RestrictTemplateSet.java @@ -0,0 +1,72 @@ +package com.fr.design.mainframe.share.encrypt.clipboard; + +import com.fr.form.main.Form; +import com.fr.form.main.WidgetUtil; +import com.fr.base.iofile.attr.EncryptSharableAttrMark; +import com.fr.form.ui.AbstractBorderStyleWidget; +import com.fr.form.ui.container.WLayout; +import com.fr.stable.fun.IOFileAttrMark; + +import java.util.HashMap; +import java.util.Map; + +/** + * created by Harrison on 2020/05/14 + **/ +public abstract class RestrictTemplateSet { + + private static Map restrictMap = new HashMap<>(8); + + public static void monitorGracefully(Form form) { + monitor(form, true); + } + + public static void monitorForcefully(Form form) { + monitor(form, false); + } + + private static void monitor(Form form, boolean useCache) { + + String templateID = form.getTemplateID(); + if (useCache) { + if (restrictMap.containsKey(templateID)) { + return; + } + } + //检测 + 缓存 + monitor0(form); + } + + private static void monitor0(Form form) { + + final String templateID = form.getTemplateID(); + WLayout container = form.getContainer(); + WidgetUtil.bfsTraversalWidget(container, new WidgetUtil.BfsWidgetGather() { + @Override + public boolean dealWith(AbstractBorderStyleWidget widget) { + IOFileAttrMark mark = widget.getWidgetAttrMark(EncryptSharableAttrMark.XML_TAG); + boolean existEncrypt = mark != null; + if (existEncrypt) { + restrictMap.put(templateID, existEncrypt); + } + return existEncrypt; + } + }, AbstractBorderStyleWidget.class); + + initIfAbsent(templateID); + } + + private static void initIfAbsent(String templateID) { + + if (!restrictMap.containsKey(templateID)) { + restrictMap.put(templateID, false); + } + } + + public static boolean isRestrict(String templateId) { + + Boolean restrict = restrictMap.get(templateId); + return restrict == null ? false : restrict; + } + +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/TemplateStateListenerProvider.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/TemplateStateListenerProvider.java new file mode 100644 index 000000000..d46ba0f55 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/TemplateStateListenerProvider.java @@ -0,0 +1,116 @@ +package com.fr.design.mainframe.share.encrypt.clipboard; + +import com.fr.base.io.BaseBook; +import com.fr.base.iofile.attr.ExtendSharableAttrMark; +import com.fr.design.DesignModelAdapter; +import com.fr.design.data.datapane.TableDataTreePane; +import com.fr.design.designer.beans.events.DesignerEvent; +import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XWTitleLayout; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.fun.impl.AbstractDesignerEditListenerProvider; +import com.fr.design.mainframe.JTemplate; +import com.fr.form.main.Form; +import com.fr.form.main.WidgetGatherAdapter; +import com.fr.form.share.SharableWidgetProvider; +import com.fr.form.share.editor.SharableEditorProvider; +import com.fr.form.share.utils.ShareUtils; +import com.fr.form.ui.AbstractBorderStyleWidget; +import com.fr.form.ui.Widget; +import com.fr.form.ui.container.WLayout; +import com.fr.general.ComparatorUtils; +import com.fr.stable.StringUtils; + +import java.util.Iterator; + +/** + * 创建,删除的时候要初始化部分状态 + *

+ * created by Harrison on 2020/05/19 + **/ +public class TemplateStateListenerProvider extends AbstractDesignerEditListenerProvider { + + public static final int CREATOR_ADDED = 1; + + public static final int CREATOR_DELETED = 2; + + private static final String SEPARATOR = "-"; + + private String lastAffectedCreatorShareID; + + + @Override + public void fireCreatorModified(DesignerEvent evt) { + + int eventId = evt.getCreatorEventID(); + if (eventId == CREATOR_ADDED || eventId == CREATOR_DELETED) { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + BaseBook book = template.getTarget(); + if (book instanceof Form) { + Form form = (Form) book; + RestrictTemplateSet.monitorForcefully(form); + refreshTableDataTree(form, evt); + } + } + if (eventId == DesignerEvent.CREATOR_SELECTED) { + XCreator lastAffectedCreator = (XCreator) evt.getAffectedCreator(); + if (lastAffectedCreator == null) { + return; + } + lastAffectedCreatorShareID = lastAffectedCreator.getShareId(); + //做下兼容处理,有标题的老的组件其外层的creator上是没有shareID的,新生成的组件是有的 + if (!lastAffectedCreator.acceptType(XWTitleLayout.class) || StringUtils.isNotEmpty(lastAffectedCreatorShareID)) { + return; + } + XCreator body = getBodyCreator((XWTitleLayout) lastAffectedCreator); + if (body != null) { + lastAffectedCreatorShareID = body.getShareId(); + } + + } + } + + private XCreator getBodyCreator(XWTitleLayout titleLayout) { + for (int i = 0; i < titleLayout.getXCreatorCount(); i++) { + XCreator creator = titleLayout.getXCreator(i); + if (creator.hasTitleStyle()) { + return creator; + } + } + return null; + } + + private void refreshTableDataTree(Form form, DesignerEvent evt) { + if (evt.getCreatorEventID() == DesignerEvent.CREATOR_DELETED && StringUtils.isNotEmpty(lastAffectedCreatorShareID)) { + if (!needDeleteTableData(form.getContainer(), lastAffectedCreatorShareID)) { + return; + } + //TODO 目前组件没版本号,可以直接遍历,之后可能还是要改的 + SharableWidgetProvider bindInfo = ShareUtils.getElCaseBindInfoById(lastAffectedCreatorShareID); + SharableEditorProvider sharableEditor = ShareUtils.getSharedElCaseEditorById(lastAffectedCreatorShareID); + if (sharableEditor == null || bindInfo == null) { + return; + } + Iterator tdIterator = sharableEditor.getTableDataSource().getTableDataNameIterator(); + while (tdIterator.hasNext()) { + String tdName = bindInfo.getName() + SEPARATOR + tdIterator.next(); + TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).removeTableData(tdName); + } + } + } + + private boolean needDeleteTableData(WLayout widget, final String shareId) { + final boolean[] needDeleteTableData = {true}; + Form.traversalWidget(widget, new WidgetGatherAdapter() { + @Override + public void dealWith(Widget widget) { + AbstractBorderStyleWidget borderStyleWidget = (AbstractBorderStyleWidget) widget; + ExtendSharableAttrMark attrMark = borderStyleWidget.getWidgetAttrMark(ExtendSharableAttrMark.XML_TAG); + if (attrMark != null) { + needDeleteTableData[0] &= !ComparatorUtils.equals(shareId, attrMark.getShareId()); + } + } + }, AbstractBorderStyleWidget.class); + return needDeleteTableData[0]; + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossLayoutClipBoardState.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossLayoutClipBoardState.java new file mode 100644 index 000000000..63d3c3293 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossLayoutClipBoardState.java @@ -0,0 +1,86 @@ +package com.fr.design.mainframe.share.encrypt.clipboard.impl; + +import com.fr.base.io.BaseBook; +import com.fr.base.iofile.attr.ExtendSharableAttrMark; +import com.fr.design.designer.beans.models.SelectionModel; +import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XCreatorUtils; +import com.fr.design.designer.creator.XLayoutContainer; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.FormSelection; +import com.fr.design.mainframe.WidgetPropertyPane; +import com.fr.form.main.Form; +import com.fr.design.mainframe.share.encrypt.clipboard.AbstractCrossClipBoardState; +import com.fr.base.iofile.attr.EncryptSharableAttrMark; +import com.fr.form.ui.AbstractBorderStyleWidget; +import com.fr.form.ui.container.WLayout; +import com.fr.stable.StringUtils; +import com.fr.stable.fun.IOFileAttrMark; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * 只需要看是否跨布局去粘贴。 + *

+ * created by Harrison on 2020/06/04 + **/ +public class CrossLayoutClipBoardState extends AbstractCrossClipBoardState { + + @Override + protected String currentId() { + //默认id + final AtomicReference finalId = new AtomicReference<>(StringUtils.EMPTY); + WidgetPropertyPane pane = WidgetPropertyPane.getInstance(); + FormDesigner designer = pane.getEditingFormDesigner(); + if (designer == null) { + return null; + } + Form target = designer.getTarget(); + BaseBook current = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getTarget(); + //如果不是同一个 + if (!StringUtils.equals(target.getTemplateID(), current.getTemplateID())) { + return null; + } + SelectionModel selectionModel = designer.getSelectionModel(); + if (selectionModel == null) { + return null; + } + FormSelection selection = selectionModel.getSelection(); + if (selection == null) { + return null; + } + XCreator[] xCreators = selection.getSelectedCreators(); + if (xCreators != null) { + XCreator xCreator = xCreators[0]; + if (StringUtils.isEmpty(finalId.get())) { + XLayoutContainer layout = XCreatorUtils.getParentXLayoutContainer(xCreator); + if (layout != null) { + WLayout wLayout = layout.toData(); + String encryptWidgetId = findEncryptWidgetId(wLayout); + boolean hasId = StringUtils.isNotEmpty(encryptWidgetId); + if (hasId) { + finalId.set(encryptWidgetId); + } + } + } + + } + return finalId.get(); + } + + @Nullable + private String findEncryptWidgetId(AbstractBorderStyleWidget widget) { + + IOFileAttrMark widgetAttrMark = widget.getWidgetAttrMark(EncryptSharableAttrMark.XML_TAG); + boolean isEncrypt = widgetAttrMark != null; + if (isEncrypt) { + ExtendSharableAttrMark sharableAttrMark = widget.getWidgetAttrMark(ExtendSharableAttrMark.XML_TAG); + if (sharableAttrMark != null) { + return (sharableAttrMark.getShareId()); + } + } + return null; + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossTemplateClipBoardState.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossTemplateClipBoardState.java new file mode 100644 index 000000000..f232deafc --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossTemplateClipBoardState.java @@ -0,0 +1,32 @@ +package com.fr.design.mainframe.share.encrypt.clipboard.impl; + +import com.fr.base.io.BaseBook; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.share.encrypt.clipboard.AbstractCrossClipBoardState; +import com.fr.design.mainframe.share.encrypt.clipboard.RestrictTemplateSet; +import com.fr.form.main.Form; + +/** + * created by Harrison on 2020/05/18 + **/ +public class CrossTemplateClipBoardState extends AbstractCrossClipBoardState { + + @Override + protected String currentId() { + + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + BaseBook book = template.getTarget(); + if (book instanceof Form) { + Form form = (Form) book; + RestrictTemplateSet.monitorGracefully(form); + } + return book.getTemplateID(); + } + + @Override + protected boolean isRestrict(String sourceId) { + + return RestrictTemplateSet.isRestrict(sourceId); + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossWidgetClipBoardState.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossWidgetClipBoardState.java new file mode 100644 index 000000000..4a2ea776f --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/CrossWidgetClipBoardState.java @@ -0,0 +1,68 @@ +package com.fr.design.mainframe.share.encrypt.clipboard.impl; + +import com.fr.base.io.BaseBook; +import com.fr.base.iofile.attr.ExtendSharableAttrMark; +import com.fr.design.designer.beans.models.SelectionModel; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.FormSelection; +import com.fr.design.mainframe.WidgetPropertyPane; +import com.fr.design.mainframe.share.encrypt.clipboard.AbstractCrossClipBoardState; +import com.fr.form.main.Form; +import com.fr.form.main.WidgetUtil; +import com.fr.base.iofile.attr.EncryptSharableAttrMark; +import com.fr.form.ui.AbstractBorderStyleWidget; +import com.fr.form.ui.Widget; +import com.fr.stable.StringUtils; +import com.fr.stable.fun.IOFileAttrMark; + +/** + * created by Harrison on 2020/05/18 + **/ +public class CrossWidgetClipBoardState extends AbstractCrossClipBoardState { + + @Override + protected String currentId() { + + final String[] finalIds = new String[]{null}; + WidgetPropertyPane pane = WidgetPropertyPane.getInstance(); + FormDesigner designer = pane.getEditingFormDesigner(); + if (designer == null) { + return null; + } + Form target = designer.getTarget(); + BaseBook current = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getTarget(); + //如果不是同一个 + if (!StringUtils.equals(target.getTemplateID(), current.getTemplateID())) { + return null; + } + SelectionModel selectionModel = designer.getSelectionModel(); + if (selectionModel == null) { + return null; + } + FormSelection selection = selectionModel.getSelection(); + if (selection == null) { + return null; + } + Widget[] selectedWidgets = selection.getSelectedWidgets(); + if (selectedWidgets != null && selectedWidgets.length == 1) { + final Widget selectedWidget = selectedWidgets[0]; + WidgetUtil.bfsTraversalWidget(selectedWidget, new WidgetUtil.BfsWidgetGather() { + @Override + public boolean dealWith(AbstractBorderStyleWidget widget) { + + IOFileAttrMark widgetAttrMark = widget.getWidgetAttrMark(EncryptSharableAttrMark.XML_TAG); + boolean isEncrypt = widgetAttrMark != null; + if (isEncrypt) { + ExtendSharableAttrMark sharableAttrMark = widget.getWidgetAttrMark(ExtendSharableAttrMark.XML_TAG); + if (sharableAttrMark != null) { + finalIds[0] = sharableAttrMark.getShareId(); + } + } + return isEncrypt; + } + }, AbstractBorderStyleWidget.class); + } + return finalIds[0]; + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/EncryptSelectionClipboardHandler.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/EncryptSelectionClipboardHandler.java new file mode 100644 index 000000000..81e1f25e7 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/EncryptSelectionClipboardHandler.java @@ -0,0 +1,31 @@ +package com.fr.design.mainframe.share.encrypt.clipboard.impl; + +import com.fr.design.mainframe.FormSelection; +import com.fr.design.mainframe.share.encrypt.clipboard.CrossClipboardHandler; + +/** + * 组件选择 + *

+ * created by Harrison on 2020/05/18 + **/ +public class EncryptSelectionClipboardHandler extends CrossClipboardHandler { + private static EncryptSelectionClipboardHandler selectionClipboardHandler; + + public static EncryptSelectionClipboardHandler getInstance() { + if (selectionClipboardHandler == null) { + selectionClipboardHandler = new EncryptSelectionClipboardHandler(); + } + return selectionClipboardHandler; + } + + public EncryptSelectionClipboardHandler() { + + super(new CrossTemplateClipBoardState(), new CrossLayoutClipBoardState()); + } + + @Override + public boolean support(Object selection) { + + return selection instanceof FormSelection; + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/EncryptTransferableClipboardHandler.java b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/EncryptTransferableClipboardHandler.java new file mode 100644 index 000000000..cfce3eb77 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/encrypt/clipboard/impl/EncryptTransferableClipboardHandler.java @@ -0,0 +1,32 @@ +package com.fr.design.mainframe.share.encrypt.clipboard.impl; + +import com.fr.design.mainframe.share.encrypt.clipboard.CrossClipboardHandler; + +import java.awt.datatransfer.Transferable; + +/** + * 单元格 + *

+ * created by Harrison on 2020/05/18 + **/ +public class EncryptTransferableClipboardHandler extends CrossClipboardHandler { + private static EncryptTransferableClipboardHandler transferableClipboardHandler; + + public static EncryptTransferableClipboardHandler getInstance() { + if (transferableClipboardHandler == null) { + transferableClipboardHandler = new EncryptTransferableClipboardHandler(); + } + return transferableClipboardHandler; + } + + public EncryptTransferableClipboardHandler() { + + super(new CrossTemplateClipBoardState(), new CrossWidgetClipBoardState()); + } + + @Override + public boolean support(Object selection) { + + return selection instanceof Transferable; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/app/DesignerAppUtils.java b/designer-realize/src/main/java/com/fr/design/mainframe/app/DesignerAppUtils.java index 4ac1a273a..2064bc044 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/app/DesignerAppUtils.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/app/DesignerAppUtils.java @@ -7,16 +7,24 @@ import com.fr.design.extra.exe.callback.ModifyStatusCallback; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.design.ui.util.UIUtil; -import com.fr.io.TemplateIOErrorUtils; +import com.fr.locale.InterProviderFactory; import com.fr.plugin.context.PluginMarker; import com.fr.plugin.context.PluginMarkerAdapter; +import com.fr.plugin.engine.remote.PluginRemoteSync; import com.fr.plugin.manage.PluginManager; import com.fr.plugin.manage.control.PluginControllerHelper; import com.fr.plugin.manage.control.PluginTask; +import com.fr.stable.StringUtils; +import com.fr.stable.TemplateIOErrorContextHolder; +import com.fr.third.guava.cache.Cache; +import com.fr.third.guava.cache.CacheBuilder; import com.fr.third.guava.collect.Multimap; import com.fr.workspace.WorkContext; +import java.time.Duration; import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; /** * 设计器app共用工具类 @@ -26,6 +34,118 @@ import java.util.Collection; * Created by vito on 2021/5/27 */ public class DesignerAppUtils { + private static final int DEFAULT_MAX_CACHE_SIZE = 50; + private static final int DEFAULT_CONCURRENCY_LEVEL = 8; + private static final long DEFAULT_EXPIRE_HOURS = 1; + + private static final Cache> ERROR_CACHE = CacheBuilder.newBuilder() + .maximumSize(DEFAULT_MAX_CACHE_SIZE) + .expireAfterAccess(Duration.ofHours(DEFAULT_EXPIRE_HOURS)) + .concurrencyLevel(DEFAULT_CONCURRENCY_LEVEL) + .build(); + + /** + * 弹出指定的插件信息, + * 并失效缓存 + * + * @param key 指定key + * @return 插件安装信息 + */ + public static Multimap popPluginInfoMap(String key) { + Multimap ifPresent = ERROR_CACHE.getIfPresent(key); + ERROR_CACHE.invalidate(key); + return ifPresent; + } + + /** + * 失效指定的插件信息缓存 + * + * @param key 指定key + */ + public static void invalidatePlugins(String key) { + ERROR_CACHE.invalidate(key); + } + + + /** + * 格式化多行插件错误信息详情并缓存, + * 用于界面展示 + * + * @param key 缓存key + * @return 格式化后的多行插件错误信息详情 + */ + public static String dealWithErrorDetailMultiLineAndCache(String key) { + Multimap pendingPlugins = TemplateIOErrorContextHolder.getPendingPlugin(); + if (pendingPlugins.isEmpty()) { + return StringUtils.EMPTY; + } + dealWithRemote(pendingPlugins); + StringBuilder sb = new StringBuilder(); + if (WorkContext.getCurrent().isLocal()) { + // 缓存等待后续处理 + ERROR_CACHE.put(key, pendingPlugins); + } + Collection unknownPlugins = pendingPlugins.get(TemplateIOErrorContextHolder.UNKNOWN_PLUGIN); + if (!unknownPlugins.isEmpty()) { + sb.append(InterProviderFactory.getProvider().getLocText("Fine-Core_Plugin_Error_UnknownPlugin")).append(":\n"); + for (PluginMarkerAdapter pluginMarker : unknownPlugins) { + sb.append("\"").append(pluginMarker.getPluginID()).append("\"") + .append(InterProviderFactory.getProvider().getLocText("Fine-Dec_Platform_Plugin")).append('\n'); + } + } + Collection notInstalledPlugins = pendingPlugins.get(TemplateIOErrorContextHolder.NOT_INSTALLED_PLUGIN); + if (!notInstalledPlugins.isEmpty()) { + sb.append(InterProviderFactory.getProvider().getLocText("Fine-Core_Plugin_Error_UninstalledPlugins")).append(":\n"); + for (PluginMarkerAdapter pluginMarker : notInstalledPlugins) { + sb.append("\"").append(pluginMarker.getPluginName()).append("\"") + .append(InterProviderFactory.getProvider().getLocText("Fine-Dec_Platform_Plugin")).append('\n'); + } + } + Collection disablePlugins = pendingPlugins.get(TemplateIOErrorContextHolder.DISABLE_PLUGIN); + if (!disablePlugins.isEmpty()) { + sb.append(InterProviderFactory.getProvider().getLocText("Fine-Core_Plugin_Error_InactivePlugins")).append(":\n"); + for (PluginMarkerAdapter pluginMarker : disablePlugins) { + sb.append("\"").append(pluginMarker.getPluginName()).append("\"") + .append(InterProviderFactory.getProvider().getLocText("Fine-Dec_Platform_Plugin")).append('\n'); + + } + } + return sb.toString(); + } + + /** + * 远程环境下需要特殊处理远程服务器尚未安装的插件 + * + * @param pendingPlugins 待处理插件 + */ + private static void dealWithRemote(Multimap pendingPlugins) { + if (!WorkContext.getCurrent().isLocal()) { + rearrange(pendingPlugins); + } + } + + /** + * 远程设计重新整理下列表 + * + * @param pendingPlugins 待处理列表 + */ + public static void rearrange(Multimap pendingPlugins) { + Map pluginRemoteStatusByIdIndex = PluginRemoteSync.getInstance().getPluginRemoteStatusByIdIndex(); + Collection unknownPlugins = pendingPlugins.get(TemplateIOErrorContextHolder.UNKNOWN_PLUGIN); + Collection notInstall = pendingPlugins.get(TemplateIOErrorContextHolder.NOT_INSTALLED_PLUGIN); + Collection disable = pendingPlugins.get(TemplateIOErrorContextHolder.DISABLE_PLUGIN); + unknownPlugins.removeIf(adapter -> pluginRemoteStatusByIdIndex.containsKey(adapter.getPluginID())); + // 本地未启用名单不准确添加到一起之后重新分配 + notInstall.addAll(disable); + disable.clear(); + // 从所有未安装中过滤远程未启用的,添加到未启用列表 + disable.addAll(notInstall.stream().filter(plugin -> + pluginRemoteStatusByIdIndex.containsKey(plugin.getPluginID()) + && !pluginRemoteStatusByIdIndex.get(plugin.getPluginID()).isRunning()) + .collect(Collectors.toList())); + // 清理未安装中所有远程安装过的插件(包含启用和未启用) + notInstall.removeIf(adapter -> pluginRemoteStatusByIdIndex.containsKey(adapter.getPluginID())); + } /** * 处理模板读取时的异常 @@ -34,7 +154,7 @@ public class DesignerAppUtils { */ public static void dealWithTemplateIOError(String path) { // 试图获取多行读取错误提示并缓存待处理列表 - String detail = TemplateIOErrorUtils.dealWithErrorDetailMultiLineAndCache(path); + String detail = dealWithErrorDetailMultiLineAndCache(path); if (detail.length() > 0) { UIUtil.invokeLaterIfNeeded(() -> { if (WorkContext.getCurrent().isLocal()) { @@ -52,7 +172,7 @@ public class DesignerAppUtils { @Override public void doCancel() { - TemplateIOErrorUtils.invalidatePlugins(path); + invalidatePlugins(path); } }).build().setVisible(true); } else { @@ -68,13 +188,13 @@ public class DesignerAppUtils { } private static void installAndEnablePlugin(String key) { - Multimap stringPluginMarkerAdapterMultimap = TemplateIOErrorUtils.popPluginInfoMap(key); - Collection disablePlugins = stringPluginMarkerAdapterMultimap.get(TemplateIOErrorUtils.DISABLE_PLUGIN); + Multimap stringPluginMarkerAdapterMultimap = popPluginInfoMap(key); + Collection disablePlugins = stringPluginMarkerAdapterMultimap.get(TemplateIOErrorContextHolder.DISABLE_PLUGIN); for (PluginMarkerAdapter disablePlugin : disablePlugins) { PluginManager.getController().enable(disablePlugin, new ModifyStatusCallback(false)); } - Collection uninstallPlugins = stringPluginMarkerAdapterMultimap.get(TemplateIOErrorUtils.NOT_INSTALLED_PLUGIN); + Collection uninstallPlugins = stringPluginMarkerAdapterMultimap.get(TemplateIOErrorContextHolder.NOT_INSTALLED_PLUGIN); for (PluginMarker uninstallPlugin : uninstallPlugins) { PluginTask pluginTask = PluginTask.installTask(uninstallPlugin); PluginControllerHelper.installOnline(uninstallPlugin, new InstallOnlineCallback(pluginTask)); diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/app/FormApp.java b/designer-realize/src/main/java/com/fr/design/mainframe/app/FormApp.java index 511c98e62..f28e2c984 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/app/FormApp.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/app/FormApp.java @@ -23,6 +23,7 @@ import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.Constants; import com.fr.stable.bridge.StableFactory; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.concurrent.Callable; @@ -62,8 +63,7 @@ class FormApp extends AbstractAppProvider { new Callable>() { @Override public OpenResult call() throws Exception { - Form form = asIOFile(tplFile); - DesignerAppUtils.dealWithTemplateIOError(tplFile.getPath()); + Form form = getForm(tplFile); return new OpenResult<>(form, form.getParameters()); } }, emptyForm); @@ -72,22 +72,31 @@ class FormApp extends AbstractAppProvider { public JTemplate call() throws Exception { OpenResult result = worker.getResult(); return (JTemplate) StableFactory.getMarkedInstanceObjectFromClass(BaseJForm.XML_TAG, - new Object[]{result.getBaseBook(), tplFile, result.getRef()}, classType, BaseJForm.class); + new Object[]{result.getBaseBook(), tplFile, result.getRef()}, classType, BaseJForm.class); } }); worker.start(tplFile.getPath()); OpenResult result = worker.getResult(); if (result != null) { return (JTemplate) StableFactory.getMarkedInstanceObjectFromClass(BaseJForm.XML_TAG, - new Object[]{result.getBaseBook(), tplFile, new Parameter[0]}, classType, BaseJForm.class); + new Object[]{result.getBaseBook(), tplFile, new Parameter[0]}, classType, BaseJForm.class); } return emptyForm; } else { return (JTemplate) StableFactory.getMarkedInstanceObjectFromClass(BaseJForm.XML_TAG, - new Object[]{asIOFile(tplFile), tplFile}, classType, BaseJForm.class); + new Object[]{getForm(tplFile), tplFile}, classType, BaseJForm.class); } } + @Nullable + private Form getForm(FILE tplFile) { + Form form = asIOFile(tplFile); + if (form != null) { + DesignerAppUtils.dealWithTemplateIOError(tplFile.getPath()); + } + return form; + } + @Override public Form asIOFile(FILE file) { diff --git a/designer-realize/src/main/java/com/fr/design/share/SharableInitManager.java b/designer-realize/src/main/java/com/fr/design/share/SharableInitManager.java index 42870535b..a01068421 100644 --- a/designer-realize/src/main/java/com/fr/design/share/SharableInitManager.java +++ b/designer-realize/src/main/java/com/fr/design/share/SharableInitManager.java @@ -1,11 +1,16 @@ package com.fr.design.share; +import com.fr.design.base.clipboard.ClipboardFilter; import com.fr.design.mainframe.share.collect.SharableCollectorManager; +import com.fr.design.mainframe.share.encrypt.clipboard.impl.EncryptSelectionClipboardHandler; +import com.fr.design.mainframe.share.encrypt.clipboard.impl.EncryptTransferableClipboardHandler; import com.fr.design.mainframe.share.util.SharableXMLUtils; public class SharableInitManager { public static void start() { SharableXMLUtils.registerSharableReadHelper(); SharableCollectorManager.getInstance().execute(); + ClipboardFilter.registerClipboardHandler(EncryptSelectionClipboardHandler.getInstance()); + ClipboardFilter.registerClipboardHandler(EncryptTransferableClipboardHandler.getInstance()); } } diff --git a/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java b/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java index 79673c11d..936001d70 100644 --- a/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java +++ b/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java @@ -1,10 +1,10 @@ package com.fr.design.widget; -import java.util.ArrayList; -import java.util.List; - -import com.fr.design.gui.controlpane.ObjectUIControlPane; +import java.lang.reflect.Constructor; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.gui.controlpane.UIListGroupControlPane; +import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.CellWidgetPropertyPane; import com.fr.design.write.submit.DBManipulationPane; import com.fr.design.write.submit.SmartInsertDBManipulationInWidgetEventPane; @@ -20,18 +20,20 @@ import com.fr.grid.selection.Selection; import com.fr.general.NameObject; import com.fr.grid.selection.CellSelection; +import com.fr.stable.AssistUtils; import com.fr.stable.Nameable; import javax.swing.*; -public class WidgetEventPane extends ObjectUIControlPane { +public class WidgetEventPane extends UIListGroupControlPane { private static final Selection NO_SELECTION = new CellSelection(-1, -1, -1, -1); private Selection selection = NO_SELECTION; + private ElementCasePane object; + public WidgetEventPane(ElementCasePane pane) { - super(pane); - this.setNameListEditable(false); + this.object = pane; if(pane != null){ selection = pane.getSelection(); } @@ -62,7 +64,7 @@ public class WidgetEventPane extends ObjectUIControlPane { protected String title4PopupWindow() { return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Event"); } - + public static class WidgetEventListenerUpdatePane extends ListenerUpdatePane { private ElementCasePane epane; // 反射会用到 @@ -91,8 +93,8 @@ public class WidgetEventPane extends ObjectUIControlPane { protected DBManipulationPane createDBManipulationPane() { if(epane == null && DesignerContext.getDesignerFrame().getSelectedJTemplate() != null) { return autoCreateDBManipulationInWidgetEventPane(); - } - + } + return new SmartInsertDBManipulationInWidgetEventPane(epane); } @@ -100,7 +102,7 @@ public class WidgetEventPane extends ObjectUIControlPane { protected String title4PopupWindow() { return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Callback_Function"); } - + @Override protected boolean isForm() { return false; @@ -116,26 +118,14 @@ public class WidgetEventPane extends ObjectUIControlPane { protected boolean supportCellAction() { return false; } - + } public void populate(Widget widget) { if (widget == null) { return; } - - this.refreshNameableCreator(EventCreator.createEventCreator(widget.supportedEvents(), WidgetEventListenerUpdatePane.class)); - - List list = new ArrayList(); - Listener listener; - for (int i = 0, size = widget.getListenerSize(); i < size; i++) { - listener = widget.getListener(i); - if (!listener.isDefault()) //name+(i+1)需要确保名字不重复 - { - list.add(new NameObject(EventCreator.switchLang(listener.getEventName()) + (i + 1), listener)); - } - } - this.populate(list.toArray(new NameObject[list.size()])); + refreshPane(widget, EventCreator.createEventCreator(widget.supportedEvents(), WidgetEventListenerUpdatePane.class)); } /** @@ -150,4 +140,49 @@ public class WidgetEventPane extends ObjectUIControlPane { } return res_array; } + + @Override + public BasicBeanPane createPaneByCreators(NameableCreator creator) { + try { + if (object == null) { + return super.createPaneByCreators(creator); + } else if (object.getClass().isArray()) { + return creator.getUpdatePane().getConstructor(object.getClass()).newInstance(object); + } else { + Constructor constructor = getConstructor(creator.getUpdatePane(), object.getClass()); + return constructor == null ? super.createPaneByCreators(creator) : constructor.newInstance(object); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 传进BasicBeanPane的构造函数的参数,可能是 + * + * @param clazz + * @param cls + * @return + */ + private Constructor getConstructor(Class clazz, Class cls) { + Constructor constructor = null; + try { + constructor = clazz.getConstructor(cls); + } catch (SecurityException e) { + } catch (NoSuchMethodException e) { + } + if (constructor != null) { + return constructor; + } else { + if (AssistUtils.equals(cls.getName(),Object.class.getName())) { + return null; + } + return getConstructor(clazz, cls.getSuperclass()); + } + } + + protected String getWrapperLabelText(){ + return Toolkit.i18nText("Fine-Design_Report_Event"); + } + } diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java b/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java index 43c0e720f..e73e9387f 100644 --- a/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java +++ b/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java @@ -55,6 +55,7 @@ import com.fr.design.mainframe.form.FormReportComponentComposite; import com.fr.design.mainframe.loghandler.DesignerLogAppender; import com.fr.design.mainframe.share.constants.ShareEntryKey; import com.fr.design.mainframe.socketio.DesignerSocketIO; +import com.fr.design.mod.ContentReplacerCenter; import com.fr.design.module.DesignModuleFactory; import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.parameter.FormParameterReader; @@ -158,6 +159,7 @@ public class DesignerActivator extends Activator { storePassport(); AlphaFineHelper.switchConfig4Locale(); RecoverManager.register(new RecoverForDesigner()); + ContentReplacerCenter.getInstance().register(); pushUpdateTask.run(); } diff --git a/designer-realize/src/test/java/com/fr/design/mainframe/app/DesignerAppUtilsTest.java b/designer-realize/src/test/java/com/fr/design/mainframe/app/DesignerAppUtilsTest.java new file mode 100644 index 000000000..c2f7ef769 --- /dev/null +++ b/designer-realize/src/test/java/com/fr/design/mainframe/app/DesignerAppUtilsTest.java @@ -0,0 +1,106 @@ +package com.fr.design.mainframe.app; + +import com.fr.invoke.Reflect; +import com.fr.plugin.context.PluginMarker; +import com.fr.plugin.context.PluginMarkerAdapter; +import com.fr.plugin.engine.remote.PluginRemoteSync; +import com.fr.stable.TemplateIOErrorContextHolder; +import com.fr.third.guava.collect.Multimap; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; + +/** + * @author vito + * @version 10.0 + * Created by vito on 2021/5/31 + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({PluginRemoteSync.class}) +public class DesignerAppUtilsTest { + @Test + public void testDealWithErrorDetailMultiLineAndCache() { + TemplateIOErrorContextHolder.registerPluginNameMap(new HashMap() {{ + put("2", "好用的插件"); + }},new HashSet<>()); + TemplateIOErrorContextHolder.addNeedEnablePlugin(PluginMarkerAdapter.create("1", "1.0", "1插件")); + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("2", "1.0")); + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("3", "1.0")); + String log = DesignerAppUtils.dealWithErrorDetailMultiLineAndCache("template1"); + Assert.assertTrue(log.contains("1插件")); + Assert.assertTrue(log.contains("好用的插件")); + Assert.assertTrue(log.contains("3")); + Multimap map = DesignerAppUtils.popPluginInfoMap("template1"); + Assert.assertEquals(3, map.size()); + Assert.assertNull(DesignerAppUtils.popPluginInfoMap("template1")); + } + + @Test + public void testInvalidatePlugins() { + TemplateIOErrorContextHolder.registerPluginNameMap(new HashMap() {{ + put("2", "好用的插件"); + }},new HashSet<>()); + TemplateIOErrorContextHolder.addNeedEnablePlugin(PluginMarkerAdapter.create("1", "1.0", "1插件")); + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("2", "1.0")); + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("3", "1.0")); + String log = DesignerAppUtils.dealWithErrorDetailMultiLineAndCache("template1"); + Assert.assertTrue(log.contains("1插件")); + Assert.assertTrue(log.contains("好用的插件")); + Assert.assertTrue(log.contains("3")); + DesignerAppUtils.invalidatePlugins("template1"); + Assert.assertNull(DesignerAppUtils.popPluginInfoMap("template1")); + } + + @Test + public void testRearrange(){ + // 远程插件模拟注册 + PluginRemoteSync pluginRemoteSync = EasyMock.createMock(PluginRemoteSync.class); + EasyMock.expect(pluginRemoteSync.getPluginRemoteStatusByIdIndex()).andReturn(new HashMap(){{ + put("com.fr.plugin1", Reflect.on(PluginRemoteSync.PluginStatus.class).call("create","com.fr.plugin1","1",true).get()); + put("com.fr.plugin2", Reflect.on(PluginRemoteSync.PluginStatus.class).call("create","com.fr.plugin2","1",true).get()); + put("com.fr.plugin3", Reflect.on(PluginRemoteSync.PluginStatus.class).call("create","com.fr.plugin3","1",false).get()); + put("com.fr.plugin4", Reflect.on(PluginRemoteSync.PluginStatus.class).call("create","com.fr.plugin4","1",false).get()); + }}).anyTimes(); + EasyMock.replay(pluginRemoteSync); + PowerMock.mockStaticPartial(PluginRemoteSync.class, "getInstance"); + EasyMock.expect(PluginRemoteSync.getInstance()).andReturn(pluginRemoteSync).anyTimes(); + PowerMock.replay(PluginRemoteSync.class); + + // 本地插件模拟检查 + TemplateIOErrorContextHolder.registerPluginNameMap(new HashMap() {{ + put("com.fr.plugin1", "好用的插件1"); + put("com.fr.plugin2", "好用的插件2"); + put("com.fr.plugin3", "好用的插件3"); + put("com.fr.plugin4", "好用的插件4"); + put("com.fr.plugin5", "好用的插件5"); + }},new HashSet<>()); + // unknown + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("com.fr.plugin7", "1")); + // disable + TemplateIOErrorContextHolder.addNeedEnablePlugin(PluginMarkerAdapter.create("com.fr.plugin5", "1", "plugin5")); + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("com.fr.plugin3", "1")); + // not install + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("com.fr.plugin1", "1")); + TemplateIOErrorContextHolder.addNeedInstallPlugin(PluginMarker.create("com.fr.plugin4", "1")); + + Multimap pendingPlugins = TemplateIOErrorContextHolder.getPendingPlugin(); + + Reflect.on(DesignerAppUtils.class).call("rearrange",pendingPlugins).get(); + Assert.assertEquals(1,pendingPlugins.get(TemplateIOErrorContextHolder.UNKNOWN_PLUGIN).size()); + Collection pluginMarkerAdapters = pendingPlugins.get(TemplateIOErrorContextHolder.DISABLE_PLUGIN); + Assert.assertEquals(2, pluginMarkerAdapters.size()); + pluginMarkerAdapters.contains(PluginMarker.create("com.fr.plugin3", "1")); + pluginMarkerAdapters.contains(PluginMarker.create("com.fr.plugin4", "1")); + Collection pluginMarkerAdapters1 = pendingPlugins.get(TemplateIOErrorContextHolder.NOT_INSTALLED_PLUGIN); + Assert.assertEquals(1, pluginMarkerAdapters1.size()); + pluginMarkerAdapters1.contains(PluginMarker.create("com.fr.plugin5","1")); + } +}