forked from fanruan/design
Browse Source
* commit '4f8aa5a21c4334a944db5de9e21774ff1ab07e80': REPORT-53016 插件缺失提醒-设计改进-白名单和远程提醒 REPORT-53007 组件复用-合入主版本-事件允许重命名,需要支持一下cpt单元格的控件事件@kerry REPORT-51683 【10.0.17】智能联动被修改位置 update REPORT-52819 依赖修改 REPORT-51683 【10.0.17】智能联动被修改位置 REPORT-51678 移植加密组件剪切复制粘贴的逻辑persist/11.0
superman
3 years ago
45 changed files with 2111 additions and 482 deletions
@ -0,0 +1,35 @@
|
||||
package com.fr.design.base.clipboard; |
||||
|
||||
public interface ClipboardHandler<T> { |
||||
/** |
||||
* 剪切 |
||||
* |
||||
* @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); |
||||
} |
@ -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<String, ListWrapperPane> 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<NameObject> 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<String, List<NameObject>> map) { |
||||
isPopulating = true; // 加一个标识位,避免切换单元格时,触发 saveSettings
|
||||
Iterator<Map.Entry<String, List<NameObject>>> iterator = map.entrySet().iterator(); |
||||
while (iterator.hasNext()) { |
||||
Map.Entry<String, List<NameObject>> entry = iterator.next(); |
||||
List<NameObject> 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<Map.Entry<String, ListWrapperPane>> iterator = nameEdListMap.entrySet().iterator(); |
||||
while (iterator.hasNext()) { |
||||
Map.Entry<String, ListWrapperPane> 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<Map.Entry<String, ListWrapperPane>> iterator = nameEdListMap.entrySet().iterator(); |
||||
while (iterator.hasNext()) { |
||||
Map.Entry<String, ListWrapperPane> 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<Map.Entry<String, ListWrapperPane>> iterator = nameEdListMap.entrySet().iterator(); |
||||
while (iterator.hasNext()) { |
||||
Map.Entry<String, ListWrapperPane> 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<Nameable> res = new java.util.ArrayList<Nameable>(); |
||||
getControlUpdatePane().update(); |
||||
Iterator<Map.Entry<String, ListWrapperPane>> iterator = nameEdListMap.entrySet().iterator(); |
||||
while (iterator.hasNext()) { |
||||
Map.Entry<String, ListWrapperPane> 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; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
} |
@ -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<T> { |
||||
|
||||
/** |
||||
* 标识内容替换类型 |
||||
* |
||||
* @return |
||||
*/ |
||||
String type(); |
||||
|
||||
/** |
||||
* 替换详情信息 |
||||
* |
||||
* @return |
||||
*/ |
||||
Map<ChangeItem, ContentReplacer<T>> changeInfo(); |
||||
|
||||
} |
@ -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<String, Set<Object>> objectMap; |
||||
|
||||
private final Set<String> 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<String> filter) { |
||||
objectMap = ClassHelper.searchObject(ob, set, filter); |
||||
} |
||||
|
||||
public void searchObject(Object ob, Set<String> set, Filter<String> filter) { |
||||
objectMap = ClassHelper.searchObject(ob, set, filter); |
||||
} |
||||
public void clearObject() { |
||||
objectMap = null; |
||||
} |
||||
|
||||
@Nullable |
||||
public Map<String, Set<Object>> getObjectMap() { |
||||
return objectMap; |
||||
} |
||||
|
||||
} |
@ -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 + "\""; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,13 @@
|
||||
package com.fr.design.mod; |
||||
|
||||
/** |
||||
* |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/5/27 |
||||
*/ |
||||
public interface ContentReplacer<T> { |
||||
|
||||
void replace(T t, String oldName, String newName); |
||||
|
||||
} |
@ -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<ContentChange> contentChangeList = new ArrayList<>(); |
||||
private List<ContentChangeItem> items = new ArrayList<>(); |
||||
|
||||
private ContentReplacerCenter() { |
||||
|
||||
EventDispatcher.listen(WidgetNameModifyEvent.INSTANCE, new Listener<ContentChangeItem>() { |
||||
@Override |
||||
public void on(Event event, ContentChangeItem param) { |
||||
if (param.getChangeMap().isEmpty()) { |
||||
return; |
||||
} |
||||
items.add(param); |
||||
} |
||||
}); |
||||
|
||||
EventDispatcher.listen(TableDataModifyEvent.INSTANCE, new Listener<ContentChangeItem>() { |
||||
@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<ContentChangeItem> 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<ContentChangeItem> contentChangeItemList, List<ContentChange> contentChangeList) { |
||||
Map<String, Set<Object>> objectMap = ContentObjectManager.getInstance().getObjectMap(); |
||||
if (objectMap != null) { |
||||
long start = System.currentTimeMillis(); |
||||
for (ContentChange contentChange : contentChangeList) { |
||||
Set<Object> 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<ContentChangeItem> itemList) { |
||||
// 当前两项存在两项: 数据集名称和组件名称
|
||||
for (ContentChangeItem contentChangeItem : itemList) { |
||||
Map<ChangeItem, ContentReplacer> map = contentChange.changeInfo(); |
||||
if (map.containsKey(contentChangeItem.getChangeItem())) { |
||||
// 具体重命名取决于复用组件存在多少个组件或数据集
|
||||
for (Map.Entry<String, String> entry : contentChangeItem.getChangeMap().entrySet()) { |
||||
map.get(contentChangeItem.getChangeItem()).replace(o, entry.getKey(), entry.getValue()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -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<String> { |
||||
|
||||
private static final Set<String> FILTER_SET = new HashSet<>(); |
||||
|
||||
private static final Filter<String> INSTANCE = new ModClassFilter(); |
||||
|
||||
public static Filter<String> 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); |
||||
} |
||||
} |
@ -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 |
||||
|
||||
} |
@ -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<String, String> changeMap; |
||||
private final ChangeItem changeItem; |
||||
private final Object object; |
||||
|
||||
public ContentChangeItem(Map<String, String> changeMap,Object object, ChangeItem changeItem) { |
||||
this.changeMap = changeMap; |
||||
this.changeItem = changeItem; |
||||
this.object = object; |
||||
} |
||||
|
||||
public Map<String, String> getChangeMap() { |
||||
return changeMap; |
||||
} |
||||
|
||||
public ChangeItem getChangeItem() { |
||||
return changeItem; |
||||
} |
||||
|
||||
public Object getObject() { |
||||
return object; |
||||
} |
||||
} |
@ -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<ContentChangeItem> { |
||||
|
||||
} |
@ -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(); |
||||
|
||||
} |
@ -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(); |
||||
|
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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<ChartHyperRelateLink> { |
||||
|
||||
private final Map<ChangeItem, ContentReplacer<ChartHyperRelateLink>> map; |
||||
|
||||
public ChartHyperRelateLinkContentChange() { |
||||
this.map = new HashMap<>(); |
||||
map.put(ChangeItem.WIDGET_NAME, new ChartHyperRelateLink4WidgetNameContentReplacer()); |
||||
} |
||||
|
||||
@Override |
||||
public Map<ChangeItem, ContentReplacer<ChartHyperRelateLink>> changeInfo() { |
||||
return map; |
||||
} |
||||
|
||||
} |
@ -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<Formula> { |
||||
|
||||
private final Map<ChangeItem, ContentReplacer<Formula>> 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<ChangeItem, ContentReplacer<Formula>> changeInfo() { |
||||
return map; |
||||
} |
||||
|
||||
} |
@ -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<JavaScriptImpl> { |
||||
|
||||
private final Map<ChangeItem, ContentReplacer<JavaScriptImpl>> 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<ChangeItem, ContentReplacer<JavaScriptImpl>> changeInfo() { |
||||
return map; |
||||
} |
||||
|
||||
} |
@ -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<VanChartHtmlLabel> { |
||||
|
||||
private final Map<ChangeItem, ContentReplacer<VanChartHtmlLabel>> 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<ChangeItem, ContentReplacer<VanChartHtmlLabel>> changeInfo() { |
||||
return map; |
||||
} |
||||
} |
@ -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<ChartHyperRelateLink> { |
||||
|
||||
@Override |
||||
public void replace(ChartHyperRelateLink chartHyperRelateLink, String oldName, String newName) { |
||||
if (ComparatorUtils.equals(chartHyperRelateLink.getRelateCCName(), oldName)) { |
||||
chartHyperRelateLink.setRelateCCName(newName); |
||||
} |
||||
} |
||||
|
||||
} |
@ -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<Formula> { |
||||
|
||||
@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())); |
||||
} |
||||
|
||||
} |
@ -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<Formula> { |
||||
|
||||
@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())); |
||||
} |
||||
} |
@ -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<JavaScriptImpl> { |
||||
|
||||
@Override |
||||
public void replace(JavaScriptImpl javaScript, String oldName, String newName) { |
||||
if (StringUtils.isNotEmpty(javaScript.getContent())) { |
||||
javaScript.setContent(ContentReplaceUtil.replaceContent(javaScript.getContent(), oldName, newName)); |
||||
} |
||||
} |
||||
|
||||
} |
@ -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<VanChartHtmlLabel> { |
||||
|
||||
@Override |
||||
public void replace(VanChartHtmlLabel vanChartHtmlLabel, String oldName, String newName) { |
||||
if (StringUtils.isNotEmpty(vanChartHtmlLabel.getCustomText())) { |
||||
vanChartHtmlLabel.setCustomText( |
||||
ContentReplaceUtil.replaceContent(vanChartHtmlLabel.getCustomText(), oldName, newName)); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,62 @@
|
||||
package com.fr.design.mainframe.share.encrypt.clipboard; |
||||
|
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import java.util.concurrent.atomic.AtomicReference; |
||||
|
||||
/** |
||||
* 跨模版禁用 |
||||
* <p> |
||||
* created by Harrison on 2020/05/14 |
||||
**/ |
||||
public abstract class AbstractCrossClipBoardState implements CrossClipboardState { |
||||
private final AtomicReference<String> 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(); |
||||
} |
@ -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<T> extends AbstractClipboardHandlerProvider<T> { |
||||
|
||||
private List<CrossClipboardState> 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; |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
|
||||
|
@ -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<String, Boolean> 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<AbstractBorderStyleWidget>() { |
||||
@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; |
||||
} |
||||
|
||||
} |
@ -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; |
||||
|
||||
/** |
||||
* 创建,删除的时候要初始化部分状态 |
||||
* <p> |
||||
* 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]; |
||||
} |
||||
} |
@ -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; |
||||
|
||||
/** |
||||
* 只需要看是否跨布局去粘贴。 |
||||
* <p> |
||||
* created by Harrison on 2020/06/04 |
||||
**/ |
||||
public class CrossLayoutClipBoardState extends AbstractCrossClipBoardState { |
||||
|
||||
@Override |
||||
protected String currentId() { |
||||
//默认id
|
||||
final AtomicReference<String> 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; |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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<AbstractBorderStyleWidget>() { |
||||
@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]; |
||||
} |
||||
} |
@ -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; |
||||
|
||||
/** |
||||
* 组件选择 |
||||
* <p> |
||||
* created by Harrison on 2020/05/18 |
||||
**/ |
||||
public class EncryptSelectionClipboardHandler extends CrossClipboardHandler<FormSelection> { |
||||
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; |
||||
} |
||||
} |
@ -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; |
||||
|
||||
/** |
||||
* 单元格 |
||||
* <p> |
||||
* created by Harrison on 2020/05/18 |
||||
**/ |
||||
public class EncryptTransferableClipboardHandler extends CrossClipboardHandler<Transferable> { |
||||
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; |
||||
} |
||||
} |
@ -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()); |
||||
} |
||||
} |
||||
|
@ -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<String, String>() {{ |
||||
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<String, PluginMarkerAdapter> map = DesignerAppUtils.popPluginInfoMap("template1"); |
||||
Assert.assertEquals(3, map.size()); |
||||
Assert.assertNull(DesignerAppUtils.popPluginInfoMap("template1")); |
||||
} |
||||
|
||||
@Test |
||||
public void testInvalidatePlugins() { |
||||
TemplateIOErrorContextHolder.registerPluginNameMap(new HashMap<String, String>() {{ |
||||
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<String, PluginRemoteSync.PluginStatus>(){{ |
||||
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<String, String>() {{ |
||||
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<String, PluginMarkerAdapter> pendingPlugins = TemplateIOErrorContextHolder.getPendingPlugin(); |
||||
|
||||
Reflect.on(DesignerAppUtils.class).call("rearrange",pendingPlugins).get(); |
||||
Assert.assertEquals(1,pendingPlugins.get(TemplateIOErrorContextHolder.UNKNOWN_PLUGIN).size()); |
||||
Collection<PluginMarkerAdapter> 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<PluginMarkerAdapter> pluginMarkerAdapters1 = pendingPlugins.get(TemplateIOErrorContextHolder.NOT_INSTALLED_PLUGIN); |
||||
Assert.assertEquals(1, pluginMarkerAdapters1.size()); |
||||
pluginMarkerAdapters1.contains(PluginMarker.create("com.fr.plugin5","1")); |
||||
} |
||||
} |
Loading…
Reference in new issue