xiqiu
1 year ago
412 changed files with 14830 additions and 1794 deletions
@ -0,0 +1,12 @@
|
||||
package com.fr.common.exception; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/12/27 |
||||
*/ |
||||
public interface ThrowableHandler { |
||||
|
||||
boolean process(Throwable e); |
||||
|
||||
} |
@ -0,0 +1,51 @@
|
||||
package com.fr.common.listener; |
||||
|
||||
import com.fr.design.data.DesignTableDataManager; |
||||
import javax.swing.event.AncestorEvent; |
||||
import javax.swing.event.AncestorListener; |
||||
import javax.swing.event.ChangeListener; |
||||
|
||||
/** |
||||
* 管理数据集相关监听的注册 |
||||
* |
||||
* 原本的监听生命周期注册与销毁: |
||||
* |
||||
* 创建时组件时进行注册,在模板关闭时进行销毁 |
||||
* 但是在模板未关闭的这段时间,如果不断的打开和关闭某些弹窗,次数达到一定程度,会导致出现大量内存占用,除非此时关闭模板 |
||||
* |
||||
* 改成以下模式: |
||||
* |
||||
* 当组件可见或者被添加到某个大组件 注册相关监听 |
||||
* 当组件不可见或者被移除时 立即移除相关监听 |
||||
* 及时清理无效监听,减少实时内存占用 |
||||
* |
||||
* |
||||
* @author hades |
||||
* @version 11.0 |
||||
* Created by hades on 2022/2/14 |
||||
*/ |
||||
public class ManageDsListenerRegisterListener implements AncestorListener { |
||||
|
||||
private ChangeListener changeListener; |
||||
|
||||
public ManageDsListenerRegisterListener(ChangeListener changeListener) { |
||||
this.changeListener = changeListener; |
||||
} |
||||
|
||||
@Override |
||||
public void ancestorAdded(AncestorEvent event) { |
||||
DesignTableDataManager.addDsChangeListener(changeListener); |
||||
// 添加后 fire一下 更新数据
|
||||
changeListener.stateChanged(null); |
||||
} |
||||
|
||||
@Override |
||||
public void ancestorRemoved(AncestorEvent event) { |
||||
DesignTableDataManager.removeDsChangeLister(changeListener); |
||||
} |
||||
|
||||
@Override |
||||
public void ancestorMoved(AncestorEvent event) { |
||||
// do nothing
|
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
package com.fr.design.actions.community; |
||||
|
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.login.AbstractDesignerSSO; |
||||
import com.fr.general.CloudCenter; |
||||
|
||||
public class StudyPlanAction extends AbstractDesignerSSO { |
||||
public StudyPlanAction() { |
||||
this.setName(Toolkit.i18nText("Fine-Design_Study_Plan")); |
||||
this.setSmallIcon("/com/fr/design/images/bbs/studyPlan"); |
||||
} |
||||
|
||||
@Override |
||||
public String getJumpUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind("bbs.studyPlan", "https://edu.fanruan.com/studypath/finereport"); |
||||
} |
||||
} |
@ -0,0 +1,200 @@
|
||||
package com.fr.design.actions.help.alphafine; |
||||
|
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.json.JSONArray; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 云端变量统一管理 |
||||
* |
||||
* @author Link |
||||
* @version 11.0 |
||||
* Created by Link on 2022/9/28 |
||||
*/ |
||||
public class AlphaFineCloudConstants { |
||||
|
||||
private static final String PLUGIN_SEARCH_API = "plugin.searchAPI"; |
||||
private static final String PLUGIN_ALL_SEARCH_API = "plugin.all.searchAPI"; |
||||
private static final String AF_PLUGIN_INFO = "af.pluginInfo"; |
||||
private static final String AF_REUSE_INFO = "af.reuseInfo"; |
||||
private static final String AF_DOC_VIEW = "af.doc_view"; |
||||
private static final String AF_DOC_SEARCH = "af.doc_search"; |
||||
private static final String AF_DOC_INFO = "af.doc_info"; |
||||
private static final String AF_PLUGIN_IMAGE = "af.plugin_image"; |
||||
private static final String AF_RECORD = "af.record"; |
||||
private static final String AF_CLOUD_SEARCH = "af.cloud_search"; |
||||
private static final String AF_SIMILAR_SEARCH = "af.similar_search"; |
||||
private static final String AF_ADVICE_SEARCH = "af.advice_search"; |
||||
private static final String AF_HOT_SEARCH = "af.hot_search"; |
||||
private static final String AF_GO_FORUM = "af.go_fourm"; |
||||
private static final String AF_GO_WEB = "af.go_web"; |
||||
private static final String AF_PREVIEW = "af.preview"; |
||||
private static final String AF_CID_NEW = "af.cid.new"; |
||||
private static final String AF_CID_USER_GROUP_INFO = "af.cid.user.group.info"; |
||||
private static final String AF_HELP_QUICK_START = "af.help.quick.start"; |
||||
private static final String AF_HELP_REPORT_LEARNING_PATH = "af.help.report.learning.path"; |
||||
private static final String AF_HELP_PARAM_LEARNING_PATH = "af.help.param.learning.path"; |
||||
private static final String AF_HELP_FILL_LEARNING_PATH = "af.help.fill.learning.path"; |
||||
private static final String AF_HELP_API_SUMMARY = "af.help.api.summary"; |
||||
private static final String AF_HELP_MONTHLY_DOCUMENT = "af.help.monthly.document"; |
||||
private static final String AF_RECOMMEND = "af.recommend"; |
||||
|
||||
private static final String LINK_NAME = "name"; |
||||
private static final String LINK_URL = "link"; |
||||
|
||||
/** |
||||
* 获取插件搜索api |
||||
*/ |
||||
public static String getPluginSearchUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(PLUGIN_SEARCH_API); |
||||
}; |
||||
|
||||
/** |
||||
* 帆软市场里全部插件api |
||||
*/ |
||||
public static String getSearchAllPluginUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(PLUGIN_ALL_SEARCH_API); |
||||
} |
||||
|
||||
/** |
||||
* 获取插件信息api |
||||
*/ |
||||
public static String getPluginUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_PLUGIN_INFO); |
||||
} |
||||
|
||||
/** |
||||
* 获取组件信息api |
||||
*/ |
||||
public static String getReuseUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_REUSE_INFO); |
||||
} |
||||
|
||||
/** |
||||
* 获取帮助文档url |
||||
*/ |
||||
public static String getDocumentDocUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_DOC_VIEW); |
||||
} |
||||
|
||||
/** |
||||
* 帮助文档搜索api |
||||
*/ |
||||
public static String getDocumentSearchUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_DOC_SEARCH); |
||||
} |
||||
|
||||
/** |
||||
* 帮助文档信息api |
||||
*/ |
||||
public static String getDocumentInformationUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_DOC_INFO); |
||||
} |
||||
|
||||
/** |
||||
* 插件图片api |
||||
*/ |
||||
public static String getPluginImageUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_PLUGIN_IMAGE); |
||||
} |
||||
|
||||
/** |
||||
* 获取云端接口,用于上传alphafine搜索记录 |
||||
*/ |
||||
public static String getCloudServerUrl() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_RECORD); |
||||
} |
||||
|
||||
/** |
||||
* 获取搜索api,输入搜索词,返回fr的相关功能 |
||||
*/ |
||||
public static String getSearchApi() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_CLOUD_SEARCH); |
||||
} |
||||
|
||||
/** |
||||
* 获取模糊搜索api前缀,输入搜索词,返回alphaFine相关内容,插件,文档,功能等 |
||||
*/ |
||||
public static String getSimilarSearchUrlPrefix() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_SIMILAR_SEARCH); |
||||
} |
||||
|
||||
/** |
||||
* 补全建议搜索结果 api,与AF_SIMILAR_SEARCH接口类似,但是返回的信息更全 |
||||
*/ |
||||
public static String getComplementAdviceSearchUrlPrefix() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_ADVICE_SEARCH); |
||||
} |
||||
|
||||
/** |
||||
* 获取热门问题 |
||||
*/ |
||||
public static String getAlphaHotSearch() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_HOT_SEARCH); |
||||
} |
||||
|
||||
/** |
||||
* 跳转论坛url |
||||
*/ |
||||
public static String getAlphaGoToForum() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_GO_FORUM); |
||||
} |
||||
|
||||
/** |
||||
* 推荐搜索api,输入搜索词,返回猜你想搜的内容(html格式) |
||||
*/ |
||||
public static String getAlphaGoToWeb() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_GO_WEB); |
||||
} |
||||
|
||||
/** |
||||
* 帆软智能客服页面url |
||||
*/ |
||||
public static String getAlphaPreview() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_PREVIEW); |
||||
} |
||||
|
||||
/** |
||||
* cid系统的产品动态api |
||||
*/ |
||||
public static String getAlphaCid() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_CID_NEW); |
||||
} |
||||
|
||||
/** |
||||
* cid系统的 用户组信息api |
||||
*/ |
||||
public static String getAlphaCidUserGroupInfo() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_CID_USER_GROUP_INFO); |
||||
} |
||||
|
||||
private static String getDefaultRecommend() { |
||||
String[][] links = new String[][]{ |
||||
{Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Quick_Start"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_QUICK_START)}, |
||||
{Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Report_Learning"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_REPORT_LEARNING_PATH)}, |
||||
{Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Parameter_Learning"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_PARAM_LEARNING_PATH)}, |
||||
{Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Fill_Learning"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_FILL_LEARNING_PATH)}, |
||||
{Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Api_Summary"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_API_SUMMARY)}, |
||||
{Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Monthly_Document"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_MONTHLY_DOCUMENT)} |
||||
}; |
||||
JSONArray jsonArray = new JSONArray(); |
||||
for (String[] link : links) { |
||||
Map<String, String> map = new HashMap<>(); |
||||
map.put(LINK_NAME, link[0]); |
||||
map.put(LINK_URL, link[1]); |
||||
jsonArray.put(map); |
||||
} |
||||
|
||||
return jsonArray.toString(); |
||||
} |
||||
|
||||
/** |
||||
* 获取默认推荐帮助文档url |
||||
*/ |
||||
public static String getAlphaHelpRecommend() { |
||||
return CloudCenter.getInstance().acquireUrlByKind(AF_RECOMMEND, getDefaultRecommend()); |
||||
} |
||||
} |
@ -0,0 +1,44 @@
|
||||
package com.fr.design.actions.help.alphafine; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 11.0 |
||||
* Created by hades on 2022/4/26 |
||||
*/ |
||||
public class AlphaFineShortCutUtil { |
||||
|
||||
private static final String TYPE = "pressed"; |
||||
private static final String DISPLAY_TYPE = "+"; |
||||
private static final String BACK_SLASH = "BACK_SLASH"; |
||||
private static final String DISPLAY_BACK_SLASH = "\\"; |
||||
private static final String SLASH = "SLASH"; |
||||
private static final String DISPLAY_SLASH = "/"; |
||||
private static final String CONTROL = "CONTROL"; |
||||
private static final String DISPLAY_CONTROL = "ctrl"; |
||||
private static final String OPEN_BRACKET = "OPEN_BRACKET"; |
||||
private static final String DISPLAY_OPEN_BRACKET = "{"; |
||||
private static final String CLOSE_BRACKET = "CLOSE_BRACKET"; |
||||
private static final String DISPLAY_CLOSE_BRACKET = "}"; |
||||
private static final String COMMA = "COMMA"; |
||||
private static final String DISPLAY_COMMA = ","; |
||||
private static final String PERIOD = "PERIOD"; |
||||
private static final String DISPLAY_PERIOD = "."; |
||||
private static final String SEMICOLON = "SEMICOLON"; |
||||
private static final String DISPLAY_SEMICOLON = ";"; |
||||
private static final String QUOTE = "QUOTE"; |
||||
private static final String DISPLAY_QUOTE = "'"; |
||||
private static final String EQUALS = "EQUALS"; |
||||
private static final String DISPLAY_EQUALS = "+"; |
||||
private static final String MINUS = "MINUS"; |
||||
private static final String DISPLAY_MINUS = "-"; |
||||
private static final String COMMAND = "META"; |
||||
private static final String SMALL_COMMAND = "meta"; |
||||
private static final String DISPLAY_COMMAND = "\u2318"; |
||||
|
||||
public static String getDisplayShortCut(String shortCut) { |
||||
return shortCut.replace(TYPE, DISPLAY_TYPE).replace(BACK_SLASH, DISPLAY_BACK_SLASH).replace(SLASH, DISPLAY_SLASH) |
||||
.replace(CONTROL, DISPLAY_CONTROL).replace(OPEN_BRACKET, DISPLAY_OPEN_BRACKET).replace(CLOSE_BRACKET, DISPLAY_CLOSE_BRACKET) |
||||
.replace(COMMA, DISPLAY_COMMA).replace(PERIOD, DISPLAY_PERIOD).replace(SEMICOLON, DISPLAY_SEMICOLON).replace(QUOTE, DISPLAY_QUOTE) |
||||
.replace(EQUALS, DISPLAY_EQUALS).replace(MINUS, DISPLAY_MINUS).replace(COMMAND, DISPLAY_COMMAND).replace(SMALL_COMMAND, DISPLAY_COMMAND); |
||||
} |
||||
} |
@ -0,0 +1,30 @@
|
||||
package com.fr.design.actions.help.alphafine; |
||||
|
||||
import java.util.Stack; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 11.0 |
||||
* Created by hades on 2022/4/23 |
||||
*/ |
||||
public class SizedStack<T> extends Stack<T> { |
||||
|
||||
private final int maxSize; |
||||
|
||||
public SizedStack(int size) { |
||||
super(); |
||||
this.maxSize = size; |
||||
} |
||||
|
||||
@Override |
||||
public T push(T object) { |
||||
while (this.size() >= maxSize) { |
||||
this.remove(0); |
||||
} |
||||
// 不重复
|
||||
if (this.contains(object)) { |
||||
return object; |
||||
} |
||||
return super.push(object); |
||||
} |
||||
} |
@ -0,0 +1,229 @@
|
||||
package com.fr.design.actions.help.alphafine.component; |
||||
|
||||
import com.fr.base.svg.IconUtils; |
||||
import com.fr.design.actions.help.alphafine.AlphaFineConfigPane; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.icheckbox.UICheckBox; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.SwingUtilities; |
||||
import javax.swing.plaf.PanelUI; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Color; |
||||
import java.awt.Component; |
||||
import java.awt.Dimension; |
||||
import java.awt.FlowLayout; |
||||
import java.util.ArrayList; |
||||
import java.util.Comparator; |
||||
import java.util.HashMap; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.function.Function; |
||||
|
||||
/** |
||||
* alphafine设置 - 搜索范围 - 自定义排序 - 弹出面板 |
||||
* |
||||
* @author Link |
||||
* @version 11.0 |
||||
* Created by Link on 2022/9/18 |
||||
*/ |
||||
public class CustomSortPane extends JPanel { |
||||
|
||||
|
||||
private static final int WIDTH = 147; |
||||
private static final int ITEM_HEIGHT = 23; |
||||
private static final int GAP = 1; |
||||
private static final Color BACKGROUND_COLOR = new Color(0xdadadd); |
||||
|
||||
private UIButton top; |
||||
private UIButton bottom; |
||||
private UIButton up; |
||||
private UIButton down; |
||||
private JPanel toolbarPane; |
||||
private MenuLabelPane sortItemPane; |
||||
private List<UICheckBox> sortItems; |
||||
private MenuLabel selectedLabel; |
||||
private AlphaFineConfigPane parentPane; |
||||
|
||||
public CustomSortPane(List<UICheckBox> items, AlphaFineConfigPane parentPane) { |
||||
this.sortItems = items; |
||||
this.parentPane = parentPane; |
||||
setLayout(new BorderLayout(GAP, GAP)); |
||||
int height = (sortItems.size() + 1) * (ITEM_HEIGHT + GAP) + GAP; |
||||
setPreferredSize(new Dimension(WIDTH, height)); |
||||
initComponent(); |
||||
add(toolbarPane, BorderLayout.NORTH); |
||||
add(sortItemPane, BorderLayout.CENTER); |
||||
revalidate(); |
||||
this.setVisible(true); |
||||
} |
||||
|
||||
@Override |
||||
public void setUI(PanelUI ui) { |
||||
super.setUI(ui); |
||||
setBackground(BACKGROUND_COLOR); |
||||
|
||||
} |
||||
|
||||
private void initComponent() { |
||||
createToolbarPane(); |
||||
createSortItemPane(); |
||||
} |
||||
|
||||
private void createToolbarPane() { |
||||
top = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/top.svg"), false); |
||||
bottom = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/bottom.svg"), false); |
||||
up = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/up.svg"), false); |
||||
down = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/down.svg"), false); |
||||
top.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/top_disable.svg")); |
||||
bottom.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/bottom_disable.svg")); |
||||
up.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/up_disable.svg")); |
||||
down.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/down_disable.svg")); |
||||
top.addActionListener(e -> { |
||||
SwingUtilities.invokeLater(() -> { |
||||
sortItemPane.setComponentZOrder(selectedLabel, 0); |
||||
setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); |
||||
CustomSortPane.this.revalidate(); |
||||
CustomSortPane.this.repaint(); |
||||
refreshCurrentOrder(); |
||||
}); |
||||
|
||||
}); |
||||
bottom.addActionListener(e -> { |
||||
SwingUtilities.invokeLater(() -> { |
||||
sortItemPane.setComponentZOrder(selectedLabel, sortItemPane.getComponentCount() - 1); |
||||
setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); |
||||
CustomSortPane.this.revalidate(); |
||||
CustomSortPane.this.repaint(); |
||||
refreshCurrentOrder(); |
||||
}); |
||||
|
||||
}); |
||||
up.addActionListener(e -> { |
||||
SwingUtilities.invokeLater(() -> { |
||||
sortItemPane.setComponentZOrder(selectedLabel, sortItemPane.getComponentZOrder(selectedLabel) - 1); |
||||
setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); |
||||
CustomSortPane.this.revalidate(); |
||||
CustomSortPane.this.repaint(); |
||||
refreshCurrentOrder(); |
||||
}); |
||||
|
||||
}); |
||||
down.addActionListener(e -> { |
||||
SwingUtilities.invokeLater(() -> { |
||||
sortItemPane.setComponentZOrder(selectedLabel, sortItemPane.getComponentZOrder(selectedLabel) + 1); |
||||
setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); |
||||
CustomSortPane.this.revalidate(); |
||||
CustomSortPane.this.repaint(); |
||||
refreshCurrentOrder(); |
||||
}); |
||||
|
||||
}); |
||||
toolbarPane = new JPanel(new FlowLayout(FlowLayout.TRAILING, GAP, GAP)); |
||||
toolbarPane.setBorder(BorderFactory.createEmptyBorder()); |
||||
toolbarPane.add(top); |
||||
toolbarPane.add(bottom); |
||||
toolbarPane.add(up); |
||||
toolbarPane.add(down); |
||||
} |
||||
|
||||
private void createSortItemPane() { |
||||
String[] currentTabOrder = parentPane.getCurrentOrder(); |
||||
Map<String, Integer> sortMap = new HashMap<>(); |
||||
for (int i = 0; i < currentTabOrder.length; i++) { |
||||
sortMap.put(currentTabOrder[i], i); |
||||
} |
||||
List<MenuLabel> sortLabels = new ArrayList<>(); |
||||
for (UICheckBox item : sortItems) { |
||||
MenuLabel label = new MenuLabel(item.getText(), (Function<MenuLabel, Object>) o -> { |
||||
selectedLabel = o; |
||||
disableButton(); |
||||
return null; |
||||
}); |
||||
sortLabels.add(label); |
||||
} |
||||
sortLabels.sort(Comparator.comparingInt(tab -> sortMap.get(tab.getText()))); |
||||
sortItemPane = new MenuLabelPane(sortLabels); |
||||
} |
||||
|
||||
/** |
||||
* 如果选中第一个和最后一个,则置灰向上和向下的按钮 |
||||
*/ |
||||
private void disableButton() { |
||||
int order = sortItemPane.getComponentZOrder(selectedLabel); |
||||
if (order == 0) { |
||||
setToolbarEnable(false, false, true, true); |
||||
} else if (order == sortItemPane.getComponentCount() - 1) { |
||||
setToolbarEnable(true, true, false, false); |
||||
} else { |
||||
setToolbarEnable(true, true, true, true); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 设置 置顶,上移,下移,置底 按钮的状态 |
||||
* true:启用 |
||||
* false:关闭 |
||||
*/ |
||||
private void setToolbarEnable(boolean top, boolean up, boolean down, boolean bottom) { |
||||
this.top.setEnabled(top); |
||||
this.up.setEnabled(up); |
||||
this.down.setEnabled(down); |
||||
this.bottom.setEnabled(bottom); |
||||
} |
||||
|
||||
/** |
||||
* 根据选项当前位置以及菜单大小设置 置顶,上移,下移,置底 按钮的状态 |
||||
*/ |
||||
private void setToolbarEnable(int order, int maxOrder) { |
||||
this.top.setEnabled(true); |
||||
this.up.setEnabled(true); |
||||
this.down.setEnabled(true); |
||||
this.bottom.setEnabled(true); |
||||
// 选项处于顶端,则置灰上移和置顶按钮
|
||||
if (order == 0) { |
||||
this.top.setEnabled(false); |
||||
this.up.setEnabled(false); |
||||
} |
||||
// 选项处于底端,则置灰下移和置底按钮
|
||||
if (order == maxOrder - 1) { |
||||
this.down.setEnabled(false); |
||||
this.bottom.setEnabled(false); |
||||
} |
||||
} |
||||
|
||||
private void refreshCurrentOrder() { |
||||
String[] currentTabOrder = parentPane.getCurrentOrder(); |
||||
HashSet<String> selectedTab = new HashSet<>(); |
||||
for (UICheckBox item : sortItems) { |
||||
selectedTab.add(item.getText()); |
||||
} |
||||
|
||||
// 未选中的tab,保持原排序不变
|
||||
Map<String, Integer> exTab = new HashMap<>(); |
||||
for (int i = 0; i < currentTabOrder.length; i++) { |
||||
if (!selectedTab.contains(currentTabOrder[i])) { |
||||
exTab.put(currentTabOrder[i], i); |
||||
} |
||||
} |
||||
|
||||
// 计算当前排序
|
||||
String[] newOrder = new String[currentTabOrder.length]; |
||||
Component[] components = sortItemPane.getComponents(); |
||||
for (String s : exTab.keySet()) { |
||||
newOrder[exTab.get(s)] = s; |
||||
} |
||||
|
||||
int t = 0; |
||||
for (int i = 0; i < newOrder.length; i++) { |
||||
if (StringUtils.isEmpty(newOrder[i])) { |
||||
newOrder[i] = ((MenuLabel) components[t++]).getText(); |
||||
} |
||||
} |
||||
parentPane.setCurrentOrder(newOrder); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,96 @@
|
||||
package com.fr.design.actions.help.alphafine.component; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.utils.DesignUtils; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.plaf.LabelUI; |
||||
import java.awt.Color; |
||||
import java.awt.Dimension; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
import java.awt.event.MouseListener; |
||||
import java.util.function.Function; |
||||
|
||||
/** |
||||
* 菜单选项label |
||||
* |
||||
* @author Link |
||||
* @version 11.0 |
||||
* Created by Link on 2022/9/18 |
||||
*/ |
||||
public class MenuLabel extends UILabel { |
||||
|
||||
private static final Color BACKGROUND_COLOR = Color.white; |
||||
private static final Color SELECTED_COLOR = new Color(0x419BF9); |
||||
private static final Color HOVERED_COLOR = new Color(0xd9ebfe); |
||||
private static final int HEIGHT = 23; |
||||
private static final int WIDTH = 147; |
||||
|
||||
private MenuLabelPane parentMenu; |
||||
private final Function function; |
||||
private boolean selected; |
||||
|
||||
public MenuLabel(String text, Function function) { |
||||
super(text); |
||||
this.function = function; |
||||
setOpaque(true); |
||||
addMouseListener(createMouseListener()); |
||||
} |
||||
|
||||
public void setParentMenu(MenuLabelPane menu) { |
||||
this.parentMenu = menu; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setUI(LabelUI ui) { |
||||
super.setUI(ui); |
||||
this.setBackground(BACKGROUND_COLOR); |
||||
this.setBorder(BorderFactory.createEmptyBorder(2, 10, 1, 10)); |
||||
this.setPreferredSize(new Dimension(WIDTH, HEIGHT)); |
||||
this.setFont(DesignUtils.getDefaultGUIFont().applySize(12)); |
||||
} |
||||
|
||||
public boolean isSelected() { |
||||
return selected; |
||||
} |
||||
|
||||
public void setSelected(boolean selected) { |
||||
if (selected) { |
||||
parentMenu.setNoneSelected(); |
||||
setBackground(SELECTED_COLOR); |
||||
function.apply(this); |
||||
this.selected = true; |
||||
} else { |
||||
setBackground(BACKGROUND_COLOR); |
||||
this.selected = false; |
||||
} |
||||
} |
||||
|
||||
MouseListener createMouseListener() { |
||||
return new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
super.mouseClicked(e); |
||||
setSelected(true); |
||||
} |
||||
|
||||
@Override |
||||
public void mouseEntered(MouseEvent e) { |
||||
super.mouseEntered(e); |
||||
if (!selected) { |
||||
setBackground(HOVERED_COLOR); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void mouseExited(MouseEvent e) { |
||||
super.mouseExited(e); |
||||
if (!selected) { |
||||
setBackground(BACKGROUND_COLOR); |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
package com.fr.design.actions.help.alphafine.component; |
||||
|
||||
import javax.swing.JPanel; |
||||
import java.awt.FlowLayout; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 简单菜单面板 |
||||
* |
||||
* @author Link |
||||
* @version 11.0 |
||||
* Created by Link on 2022/9/18 |
||||
*/ |
||||
public class MenuLabelPane extends JPanel { |
||||
|
||||
private static final int GAP = 1; |
||||
|
||||
private List<MenuLabel> labels; |
||||
|
||||
public MenuLabelPane(List<MenuLabel> labels) { |
||||
this.labels = labels; |
||||
setLayout(new FlowLayout(FlowLayout.CENTER, GAP, GAP)); |
||||
for (MenuLabel label : labels) { |
||||
label.setParentMenu(this); |
||||
add(label); |
||||
} |
||||
} |
||||
|
||||
public void setNoneSelected() { |
||||
for (MenuLabel label : labels) { |
||||
label.setSelected(false); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,11 @@
|
||||
package com.fr.design.beans; |
||||
|
||||
import javax.swing.JComponent; |
||||
|
||||
public interface ErrorMsgTextFieldAdapter { |
||||
void setText(String str); |
||||
|
||||
String getText(); |
||||
|
||||
JComponent getErrorMsgTextField(); |
||||
} |
@ -0,0 +1,46 @@
|
||||
package com.fr.design.beans; |
||||
|
||||
import com.fr.design.gui.itextfield.UITextField; |
||||
|
||||
import javax.swing.JComponent; |
||||
import javax.swing.event.DocumentEvent; |
||||
import javax.swing.event.DocumentListener; |
||||
|
||||
public class UITextFieldAdapter implements ErrorMsgTextFieldAdapter { |
||||
private final UITextField uiTextField = new UITextField(); |
||||
|
||||
public UITextFieldAdapter(){ |
||||
addDocumentListener(); |
||||
} |
||||
@Override |
||||
public void setText(String str) { |
||||
uiTextField.setText(str); |
||||
} |
||||
|
||||
@Override |
||||
public String getText() { |
||||
return uiTextField.getText(); |
||||
} |
||||
|
||||
public void addDocumentListener() { |
||||
uiTextField.getDocument().addDocumentListener(new DocumentListener() { |
||||
|
||||
public void changedUpdate(DocumentEvent e) { |
||||
uiTextField.setToolTipText(uiTextField.getText()); |
||||
} |
||||
|
||||
public void insertUpdate(DocumentEvent e) { |
||||
uiTextField.setToolTipText(uiTextField.getText()); |
||||
} |
||||
|
||||
public void removeUpdate(DocumentEvent e) { |
||||
uiTextField.setToolTipText(uiTextField.getText()); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public JComponent getErrorMsgTextField() { |
||||
return uiTextField; |
||||
} |
||||
} |
@ -0,0 +1,5 @@
|
||||
package com.fr.design.constants; |
||||
|
||||
public class TableDataConstants { |
||||
public static final String SEPARATOR = "_"; |
||||
} |
@ -0,0 +1,93 @@
|
||||
package com.fr.design.data; |
||||
|
||||
import org.jetbrains.annotations.NotNull; |
||||
|
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author rinoux |
||||
* @version 10.0 |
||||
* Created by rinoux on 2022/3/28 |
||||
*/ |
||||
public final class MapCompareUtils { |
||||
|
||||
|
||||
/** |
||||
* 对比两个map 查找出相比orig,other中有哪些是新增的、删除的或者被修改的,并分别进行处理 |
||||
* |
||||
* 对比时默认用equals方法来判断是否为 EntryEventKind#UPDATED |
||||
* |
||||
* @param orig 原始map |
||||
* @param other 参考的新map |
||||
* @param eventHandler 有区别时的事件处理器 |
||||
* @param <K> K |
||||
* @param <V> V |
||||
*/ |
||||
public static <K, V> void contrastMapEntries(@NotNull Map<K, V> orig, @NotNull Map<K, V> other, @NotNull EventHandler<K, V> eventHandler) { |
||||
|
||||
contrastMapEntries(orig, other, eventHandler, UpdateRule.DEFAULT); |
||||
} |
||||
|
||||
/** |
||||
* 对比两个map 查找出相比orig,other中有哪些是新增的、删除的或者被修改的,并分别进行处理 |
||||
* |
||||
* 对比时用自定义的规则来判断是否为 EntryEventKind#UPDATED |
||||
* |
||||
* @param orig 原始map |
||||
* @param other 参考的新map |
||||
* @param eventHandler 有区别时的事件处理器 |
||||
* @param updateRule 自定义的Update事件判定规则 |
||||
* @param <K> |
||||
* @param <V> |
||||
*/ |
||||
public static <K, V> void contrastMapEntries(@NotNull Map<K, V> orig, @NotNull Map<K, V> other, @NotNull EventHandler<K, V> eventHandler, @NotNull UpdateRule<K, V> updateRule) { |
||||
|
||||
Map<K, V> copiedOrig = new LinkedHashMap<>(orig); |
||||
|
||||
other.forEach((k, v) -> { |
||||
V existedV = copiedOrig.remove(k); |
||||
if (existedV != null) { |
||||
if (updateRule.needUpdate(existedV, v)) { |
||||
eventHandler.on(EntryEventKind.UPDATED, k, v); |
||||
} |
||||
} else { |
||||
eventHandler.on(EntryEventKind.ADDED, k, v); |
||||
} |
||||
}); |
||||
|
||||
copiedOrig.forEach((k, v) -> eventHandler.on(EntryEventKind.REMOVED, k, v)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 事件处理器,对应比较后的三种结果的事件处理 |
||||
* @param <K> |
||||
* @param <V> |
||||
*/ |
||||
public interface EventHandler<K, V> { |
||||
void on(EntryEventKind entryEventKind, K k, V v); |
||||
} |
||||
|
||||
/** |
||||
* 判定 数据被修改 的判定规则 |
||||
* @param <K> |
||||
* @param <V> |
||||
*/ |
||||
public interface UpdateRule<K, V> { |
||||
|
||||
EntryEventKind eventKind = EntryEventKind.UPDATED; |
||||
|
||||
UpdateRule DEFAULT = new UpdateRule() {}; |
||||
|
||||
default boolean needUpdate(V origin, V v) { |
||||
return !v.equals(origin); |
||||
} |
||||
} |
||||
|
||||
public enum EntryEventKind { |
||||
ADDED, |
||||
REMOVED, |
||||
UPDATED; |
||||
} |
||||
} |
@ -0,0 +1,57 @@
|
||||
package com.fr.design.data.datapane.auth; |
||||
|
||||
import com.fr.base.TableData; |
||||
import com.fr.data.impl.Connection; |
||||
import com.fr.data.impl.DBTableData; |
||||
import com.fr.data.impl.NameDatabaseConnection; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.server.connection.DBConnectAuth; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
|
||||
/** |
||||
* 数据连接权限相关的工具类 |
||||
* @author Yvan |
||||
*/ |
||||
public class TableDataAuthHelper { |
||||
|
||||
/** |
||||
* 编辑数据集时是否需要检查权限 |
||||
* @param tableData |
||||
* @return |
||||
*/ |
||||
public static boolean needCheckAuthWhenEdit(TableData tableData) { |
||||
// 远程设计下,编辑DBTableData时需要判断权限
|
||||
return !WorkContext.getCurrent().isLocal() && tableData instanceof DBTableData; |
||||
} |
||||
|
||||
/** |
||||
* 获取无权限数据连接集合 |
||||
* 远程下需要调用RPC,为耗时操作,谨慎使用 |
||||
* @return |
||||
*/ |
||||
public static Collection<String> getNoAuthConnections() { |
||||
// 获取无权限连接集合
|
||||
Collection<String> noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections(); |
||||
return noAuthConnections == null ? Collections.emptyList() : noAuthConnections; |
||||
} |
||||
|
||||
/** |
||||
* 通过数据集获取其数据连接的名称 |
||||
* |
||||
* 注意: |
||||
* 1. Connection接口本身是不提供名称的,只有我们内部为了使用方便,将其包装成了NameDataBaseConnection |
||||
* 如果不是NameDataBaseConnection类型,则无名称,因此这里只能用判断类型的方式获取名称 |
||||
* 2. 仅支持DBTableData获取连接名 |
||||
* @return |
||||
*/ |
||||
public static String getConnectionNameByDBTableData(DBTableData tableData) { |
||||
Connection database = tableData.getDatabase(); |
||||
if (database instanceof NameDatabaseConnection) { |
||||
return ((NameDatabaseConnection) database).getName(); |
||||
} |
||||
return StringUtils.EMPTY; |
||||
} |
||||
} |
@ -0,0 +1,23 @@
|
||||
package com.fr.design.data.tabledata.tabledatapane.loading; |
||||
|
||||
|
||||
|
||||
/** |
||||
* 可切换的DBTableData对应的数据集面板,需要使用CardLayout布局 |
||||
* 主要是给插件适配用的 |
||||
* @author Yvan |
||||
*/ |
||||
public interface SwitchableTableDataPane { |
||||
|
||||
/** Loading面板 */ |
||||
String LOADING_PANE_NAME = "Loading"; |
||||
/** 内容面板 */ |
||||
String CONTENT_PANE_NAME = "Content"; |
||||
|
||||
/** |
||||
* 根据面板名称切换面板 |
||||
* @param paneName 面板名称 |
||||
*/ |
||||
void switchTo(String paneName); |
||||
|
||||
} |
@ -0,0 +1,54 @@
|
||||
package com.fr.design.data.tabledata.tabledatapane.loading; |
||||
|
||||
import com.fr.design.dialog.BasicPane; |
||||
import com.fr.design.i18n.Toolkit; |
||||
|
||||
import javax.swing.JPanel; |
||||
import java.awt.CardLayout; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
*/ |
||||
public class TableDataLoadingPane extends BasicPane { |
||||
|
||||
/** Loading面板 */ |
||||
public static final String LOADING_PANE_NAME = "Loading"; |
||||
/** 无权限提示面板 */ |
||||
public static final String NO_AUTH_PANE_NAME = "NoAuthority"; |
||||
/** 错误提示面板 */ |
||||
public static final String ERROR_NAME = "Error"; |
||||
|
||||
private CardLayout card; |
||||
|
||||
/** 加载中面板 */ |
||||
private JPanel loadingPane; |
||||
/** 错误提示面板 */ |
||||
private JPanel errorPane; |
||||
/** 数据连接无权限面板 */ |
||||
private JPanel noAuthorityPane; |
||||
|
||||
public TableDataLoadingPane() { |
||||
initPanes(); |
||||
} |
||||
|
||||
private void initPanes() { |
||||
card = new CardLayout(); |
||||
this.setLayout(card); |
||||
loadingPane = new TipsPane(true); |
||||
errorPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Error")); |
||||
noAuthorityPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_No_Auth")); |
||||
add(LOADING_PANE_NAME, loadingPane); |
||||
add(NO_AUTH_PANE_NAME, noAuthorityPane); |
||||
add(ERROR_NAME, errorPane); |
||||
switchTo(LOADING_PANE_NAME); |
||||
} |
||||
|
||||
public void switchTo(String panelName) { |
||||
card.show(this, panelName); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return Toolkit.i18nText("Fine-Design_Basic_DS-Database_Query"); |
||||
} |
||||
} |
@ -0,0 +1,45 @@
|
||||
package com.fr.design.data.tabledata.tabledatapane.loading; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
|
||||
import javax.swing.JPanel; |
||||
import javax.swing.JProgressBar; |
||||
import javax.swing.SwingConstants; |
||||
import java.awt.BorderLayout; |
||||
|
||||
/** |
||||
* 提示面板,支持自定义提示,支持进度条配置可选 |
||||
* @author Yvan |
||||
*/ |
||||
public class TipsPane extends JPanel { |
||||
|
||||
/** |
||||
* 默认提示 |
||||
*/ |
||||
private static final String LOADING = Toolkit.i18nText("Fine-Design_Basic_Loading_And_Waiting"); |
||||
|
||||
public TipsPane () { |
||||
this(LOADING, false); |
||||
} |
||||
|
||||
public TipsPane (String tip) { |
||||
this(tip, false); |
||||
} |
||||
|
||||
public TipsPane (boolean needProgressBar) { |
||||
this(LOADING, needProgressBar); |
||||
} |
||||
|
||||
public TipsPane (String tips, boolean needProgressBar) { |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
UILabel tipsLabel = new UILabel(tips, SwingConstants.CENTER); |
||||
this.add(tipsLabel, BorderLayout.CENTER); |
||||
if (needProgressBar) { |
||||
JProgressBar progressBar = new JProgressBar(); |
||||
progressBar.setIndeterminate(true); |
||||
this.add(progressBar, BorderLayout.SOUTH); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,70 @@
|
||||
package com.fr.design.extra.exe.callback.handle; |
||||
|
||||
import com.fr.design.dialog.FineJOptionPane; |
||||
import com.fr.design.dialog.link.MessageWithLink; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.plugin.error.PluginErrorCode; |
||||
import com.fr.plugin.manage.control.PluginTaskResult; |
||||
|
||||
/** |
||||
* 帮助处理插件操作(安装、更新等)的弹窗 |
||||
* @author Yvan |
||||
*/ |
||||
public class PluginCallBackHelper { |
||||
|
||||
private static final String NEW_LINE_TAG = "<br/>"; |
||||
private static final String REFERENCE = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_Reference"); |
||||
private static final String HELP_DOCUMENT_NAME = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_NAME"); |
||||
private static final String CONNECTOR = "-"; |
||||
private static final String HELP_DOCUMENT_LINK = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_LINK"); |
||||
|
||||
|
||||
/** |
||||
* 展示插件操作失败后的提示弹窗 |
||||
* @param result |
||||
* @param pluginInfo |
||||
*/ |
||||
public static void showErrorMessage(PluginTaskResult result, String pluginInfo) { |
||||
// 单独处理下插件完整性校验失败的提示
|
||||
if (PluginCallBackHelper.needHandleInvalidatePackage(result)) { |
||||
MessageWithLink messageWithLink = PluginCallBackHelper.generate4InvalidatePackage(pluginInfo); |
||||
PluginTaskResultErrorDialog resultDialog = new PluginTaskResultErrorDialog(null, messageWithLink); |
||||
resultDialog.showResult(); |
||||
} else { |
||||
FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 判断是否需要处理 插件安装包校验失败 导致的安装失败任务 |
||||
* @param result |
||||
* @return |
||||
*/ |
||||
private static boolean needHandleInvalidatePackage(PluginTaskResult result) { |
||||
return !result.isSuccess() && result.getCode() == PluginErrorCode.InstallPackageValidateFailed; |
||||
} |
||||
|
||||
/** |
||||
* 根据插件原始报错信息,构建MessageWithLink |
||||
* @param originInfo |
||||
* @return |
||||
*/ |
||||
private static MessageWithLink generate4InvalidatePackage(String originInfo) { |
||||
|
||||
return new MessageWithLink(getSupplementaryMessage(originInfo), HELP_DOCUMENT_NAME, HELP_DOCUMENT_LINK); |
||||
} |
||||
|
||||
/** |
||||
* 根据插件原始报错信息,获取增加了补充说明后的信息 |
||||
* @param originInfo |
||||
* @return |
||||
*/ |
||||
private static String getSupplementaryMessage(String originInfo) { |
||||
return new StringBuilder() |
||||
.append(originInfo) |
||||
.append(NEW_LINE_TAG) |
||||
.append(REFERENCE) |
||||
.append(CONNECTOR) |
||||
.toString(); |
||||
} |
||||
} |
@ -0,0 +1,86 @@
|
||||
package com.fr.design.extra.exe.callback.handle; |
||||
|
||||
import com.fr.base.svg.IconUtils; |
||||
import com.fr.design.dialog.link.MessageWithLink; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.layout.VerticalFlowLayout; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JDialog; |
||||
import javax.swing.JPanel; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Dimension; |
||||
import java.awt.Frame; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
|
||||
/** |
||||
* 当前仅处理Error提示,之后有需要再扩展 |
||||
* @author Yvan |
||||
*/ |
||||
public class PluginTaskResultErrorDialog extends JDialog { |
||||
|
||||
private static final Dimension LABEL = new Dimension(60, 90); |
||||
|
||||
private JPanel contentPane; |
||||
|
||||
private UILabel errorLabel; |
||||
|
||||
private UIButton confirmButton; |
||||
|
||||
private MessageWithLink messageWithLink; |
||||
|
||||
public PluginTaskResultErrorDialog(Frame parent, MessageWithLink messageWithLink) { |
||||
super(parent, true); |
||||
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning")); |
||||
this.messageWithLink = messageWithLink; |
||||
|
||||
initContentPane(); |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
this.setResizable(false); |
||||
this.add(contentPane, BorderLayout.CENTER); |
||||
this.setSize(new Dimension( 380, 160)); |
||||
GUICoreUtils.centerWindow(this); |
||||
} |
||||
|
||||
/** |
||||
* 初始化内容面板 |
||||
*/ |
||||
private void initContentPane() { |
||||
this.contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
// error图标
|
||||
errorLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/error_tips.svg")); |
||||
errorLabel.setPreferredSize(LABEL); |
||||
errorLabel.setBorder(BorderFactory.createEmptyBorder(10, 20, 40, 20)); |
||||
// 提示内容
|
||||
JPanel messagePane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
messagePane.add(errorLabel, BorderLayout.WEST); |
||||
messagePane.add(messageWithLink, BorderLayout.CENTER); |
||||
messagePane.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); |
||||
this.contentPane.add(messagePane, BorderLayout.CENTER); |
||||
// 确定按钮
|
||||
confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Button_OK")); |
||||
confirmButton.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
hideResult(); |
||||
} |
||||
}); |
||||
JPanel confirmPane = new JPanel(new VerticalFlowLayout()); |
||||
confirmPane.add(confirmButton); |
||||
confirmPane.setBorder(BorderFactory.createEmptyBorder(0, 160, 10, 0)); |
||||
this.contentPane.add(confirmPane, BorderLayout.SOUTH); |
||||
} |
||||
|
||||
public void showResult() { |
||||
this.setVisible(true); |
||||
} |
||||
|
||||
public void hideResult() { |
||||
this.setVisible(false); |
||||
} |
||||
} |
@ -0,0 +1,11 @@
|
||||
package com.fr.design.fun; |
||||
|
||||
import com.fr.design.gui.frpane.RegFieldPane; |
||||
import com.fr.stable.fun.mark.Immutable; |
||||
|
||||
public interface RegPaneProvider extends Immutable { |
||||
int CURRENT_LEVEL = 1; |
||||
String XML_TAG = "RegPaneProvider"; |
||||
|
||||
RegFieldPane createRegPane(); |
||||
} |
@ -0,0 +1,11 @@
|
||||
package com.fr.design.fun; |
||||
|
||||
import com.fr.design.beans.ErrorMsgTextFieldAdapter; |
||||
import com.fr.stable.fun.mark.Immutable; |
||||
|
||||
public interface TextFieldAdapterProvider extends Immutable { |
||||
String XML_TAG = "TextFieldAdapterProvider"; |
||||
int CURRENT_LEVEL = 1; |
||||
|
||||
ErrorMsgTextFieldAdapter createTextFieldAdapter(); |
||||
} |
@ -0,0 +1,22 @@
|
||||
package com.fr.design.fun.impl; |
||||
|
||||
import com.fr.design.fun.RegPaneProvider; |
||||
import com.fr.stable.fun.mark.API; |
||||
|
||||
/** |
||||
* @author Joe |
||||
* 2021/10/8 15:19 |
||||
*/ |
||||
@API(level = RegPaneProvider.CURRENT_LEVEL) |
||||
public abstract class AbstractRegPaneProvider implements RegPaneProvider { |
||||
|
||||
@Override |
||||
public int currentAPILevel() { |
||||
return CURRENT_LEVEL; |
||||
} |
||||
|
||||
@Override |
||||
public int layerIndex() { |
||||
return DEFAULT_LAYER_INDEX; |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
package com.fr.design.fun.impl; |
||||
|
||||
import com.fr.design.fun.TextFieldAdapterProvider; |
||||
import com.fr.stable.fun.mark.API; |
||||
|
||||
/** |
||||
* @author Joe |
||||
* 2021/10/8 15:17 |
||||
*/ |
||||
@API(level = TextFieldAdapterProvider.CURRENT_LEVEL) |
||||
public abstract class AbstractTextFieldAdapterProvider implements TextFieldAdapterProvider { |
||||
|
||||
@Override |
||||
public int currentAPILevel() { |
||||
return CURRENT_LEVEL; |
||||
} |
||||
|
||||
@Override |
||||
public int layerIndex() { |
||||
return DEFAULT_LAYER_INDEX; |
||||
} |
||||
} |
@ -1,77 +0,0 @@
|
||||
package com.fr.design.gui.icombobox; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
|
||||
import javax.swing.JTree; |
||||
import javax.swing.SwingWorker; |
||||
import javax.swing.tree.TreeCellRenderer; |
||||
import java.util.concurrent.FutureTask; |
||||
|
||||
/** |
||||
* 模糊搜索前需执行完前置任务的TreeComboBox |
||||
* @author Lucian.Chen |
||||
* @version 10.0 |
||||
* Created by Lucian.Chen on 2021/4/14 |
||||
*/ |
||||
public class SearchPreTaskTreeComboBox extends FRTreeComboBox { |
||||
|
||||
/** |
||||
* 模糊搜索前任务 |
||||
*/ |
||||
private FutureTask<Void> preSearchTask; |
||||
|
||||
public SearchPreTaskTreeComboBox(JTree tree, TreeCellRenderer renderer, boolean editable) { |
||||
super(tree, renderer, editable); |
||||
} |
||||
|
||||
public FutureTask<Void> getPreSearchTask() { |
||||
return preSearchTask; |
||||
} |
||||
|
||||
public void setPreSearchTask(FutureTask<Void> preSearchTask) { |
||||
this.preSearchTask = preSearchTask; |
||||
} |
||||
|
||||
protected UIComboBoxEditor createEditor() { |
||||
return new SearchPreTaskComboBoxEditor(this); |
||||
} |
||||
|
||||
private class SearchPreTaskComboBoxEditor extends FrTreeSearchComboBoxEditor { |
||||
|
||||
public SearchPreTaskComboBoxEditor(FRTreeComboBox comboBox) { |
||||
super(comboBox); |
||||
} |
||||
|
||||
protected void changeHandler() { |
||||
if (isSetting()) { |
||||
return; |
||||
} |
||||
setPopupVisible(true); |
||||
new SwingWorker<Void, Void>() { |
||||
@Override |
||||
protected Void doInBackground() { |
||||
FutureTask<Void> task = getPreSearchTask(); |
||||
try { |
||||
// 确保模糊搜索前任务执行完成后,再进行模糊搜索
|
||||
if (task != null) { |
||||
task.get(); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
if (task != null) { |
||||
// 任务执行后置空,否则会被别的操作重复触发
|
||||
setPreSearchTask(null); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected void done() { |
||||
// 模糊搜索
|
||||
search(); |
||||
} |
||||
}.execute(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,236 @@
|
||||
package com.fr.design.gui.icombobox; |
||||
|
||||
import com.fr.concurrent.NamedThreadFactory; |
||||
import com.fr.data.core.DataCoreUtils; |
||||
import com.fr.data.core.db.TableProcedure; |
||||
import com.fr.data.impl.Connection; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.design.data.datapane.ChoosePane; |
||||
import com.fr.design.dialog.FineJOptionPane; |
||||
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.module.ModuleContext; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.Filter; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.JOptionPane; |
||||
import javax.swing.JTree; |
||||
import javax.swing.SwingWorker; |
||||
import javax.swing.event.PopupMenuEvent; |
||||
import javax.swing.event.PopupMenuListener; |
||||
import javax.swing.tree.DefaultMutableTreeNode; |
||||
import javax.swing.tree.DefaultTreeModel; |
||||
import javax.swing.tree.TreeCellRenderer; |
||||
import javax.swing.tree.TreeNode; |
||||
import javax.swing.tree.TreePath; |
||||
import java.util.Enumeration; |
||||
import java.util.concurrent.ExecutorService; |
||||
|
||||
/** |
||||
* 实现模糊搜索表名的FRTreeComboBox |
||||
* FRTreeComboBox:搜索后滚动到首个匹配节点 |
||||
* SearchFRTreeComboBox:显示所有匹配的节点 |
||||
* |
||||
* @author Lucian.Chen |
||||
* @version 10.0 |
||||
* Created by Lucian.Chen on 2021/4/14 |
||||
*/ |
||||
public class TableSearchTreeComboBox extends FRTreeComboBox { |
||||
// 持有父容器,需要实时获取其他组件值
|
||||
private final ChoosePane parent; |
||||
/** |
||||
* 保证模糊搜索的原子性操作 |
||||
*/ |
||||
private final ExecutorService singleExecutor = ModuleContext.getExecutor().newSingleThreadScheduledExecutor(new NamedThreadFactory("TableSearchTreeComboBox")); |
||||
|
||||
public TableSearchTreeComboBox(ChoosePane parent, JTree tree, TreeCellRenderer renderer) { |
||||
super(tree, renderer); |
||||
this.parent = parent; |
||||
initPopupListener(); |
||||
} |
||||
|
||||
protected UIComboBoxEditor createEditor() { |
||||
return new TableSearchComboBoxEditor(this); |
||||
} |
||||
|
||||
@Override |
||||
protected String pathToString(TreePath path) { |
||||
Object obj = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject(); |
||||
if (obj instanceof TableProcedure) { |
||||
return ((TableProcedure) obj).getName(); |
||||
} |
||||
return super.pathToString(path); |
||||
} |
||||
|
||||
@Override |
||||
public void setSelectedItemString(String _name) { |
||||
super.setSelectedItemString(_name); |
||||
// 会因为连续两次选中的值一致,导致未触发编辑框联动
|
||||
this.getEditor().setItem(_name); |
||||
} |
||||
|
||||
/** |
||||
* 执行模糊搜索 |
||||
*/ |
||||
private void searchExecute() { |
||||
UIComboBoxEditor searchEditor = (UIComboBoxEditor) this.getEditor(); |
||||
String searchText = (String) searchEditor.getItem(); |
||||
singleExecutor.execute(new SwingWorker<Void, Void>() { |
||||
@Override |
||||
protected Void doInBackground() { |
||||
processTableDataNames( |
||||
parent.getDSName(), |
||||
parent.getConnection(), |
||||
parent.getSchema(), |
||||
createFilter(searchText)); |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected void done() { |
||||
expandTree(); |
||||
// 输入框获取焦点
|
||||
searchEditor.getEditorComponent().requestFocus(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private TableNameFilter createFilter(String text) { |
||||
return StringUtils.isEmpty(text) ? EMPTY_FILTER : new TableNameFilter(text); |
||||
} |
||||
|
||||
/** |
||||
* 查询数据库表,并构建节点目录 |
||||
* |
||||
* @param databaseName 数据库名 |
||||
* @param connection 数据连接 |
||||
* @param schema 模式 |
||||
* @param filter 模糊搜索过滤器 |
||||
*/ |
||||
private void processTableDataNames(String databaseName, Connection connection, String schema, TableNameFilter filter) { |
||||
if (tree == null) { |
||||
return; |
||||
} |
||||
DefaultMutableTreeNode rootTreeNode = (DefaultMutableTreeNode) tree.getModel().getRoot(); |
||||
rootTreeNode.removeAllChildren(); |
||||
|
||||
if (connection == null) { |
||||
return; |
||||
} |
||||
try { |
||||
schema = StringUtils.isEmpty(schema) ? null : schema; |
||||
TableProcedure[] sqlTableArray = DataCoreUtils.getTables(connection, TableProcedure.TABLE, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); |
||||
if (ArrayUtils.isNotEmpty(sqlTableArray)) { |
||||
ExpandMutableTreeNode tableTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); |
||||
rootTreeNode.add(tableTreeNode); |
||||
addArrayNode(tableTreeNode, sqlTableArray, filter); |
||||
} |
||||
TableProcedure[] sqlViewArray = DataCoreUtils.getTables(connection, TableProcedure.VIEW, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); |
||||
if (ArrayUtils.isNotEmpty(sqlViewArray)) { |
||||
ExpandMutableTreeNode viewTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); |
||||
rootTreeNode.add(viewTreeNode); |
||||
addArrayNode(viewTreeNode, sqlViewArray, filter); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"), |
||||
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Failed"), JOptionPane.ERROR_MESSAGE); |
||||
} |
||||
} |
||||
|
||||
private void addArrayNode(ExpandMutableTreeNode rootNode, TableProcedure[] sqlArray, TableNameFilter filter) { |
||||
if (sqlArray != null) { |
||||
for (TableProcedure procedure : sqlArray) { |
||||
if (filter.accept(procedure)) { |
||||
ExpandMutableTreeNode viewChildTreeNode = new ExpandMutableTreeNode(procedure); |
||||
rootNode.add(viewChildTreeNode); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 展开节点 |
||||
*/ |
||||
private void expandTree() { |
||||
((DefaultTreeModel) tree.getModel()).reload(); |
||||
// daniel 展开所有tree
|
||||
TreeNode root = (TreeNode) tree.getModel().getRoot(); |
||||
TreePath parent = new TreePath(root); |
||||
TreeNode node = (TreeNode) parent.getLastPathComponent(); |
||||
for (Enumeration e = node.children(); e.hasMoreElements(); ) { |
||||
TreeNode n = (TreeNode) e.nextElement(); |
||||
TreePath path = parent.pathByAddingChild(n); |
||||
tree.expandPath(path); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 表名模糊搜索实现 |
||||
*/ |
||||
private static class TableNameFilter implements Filter<TableProcedure> { |
||||
private String searchFilter; |
||||
|
||||
public TableNameFilter() { |
||||
} |
||||
|
||||
public TableNameFilter(String searchFilter) { |
||||
this.searchFilter = searchFilter.toLowerCase().trim(); |
||||
} |
||||
|
||||
// 表名匹配
|
||||
@Override |
||||
public boolean accept(TableProcedure procedure) { |
||||
return procedure.getName().toLowerCase().contains(searchFilter); |
||||
} |
||||
} |
||||
|
||||
private static final TableNameFilter EMPTY_FILTER = new TableNameFilter() { |
||||
public boolean accept(TableProcedure procedure) { |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
private void initPopupListener() { |
||||
// 点击下拉时触发模糊搜索
|
||||
this.addPopupMenuListener(new PopupMenuListener() { |
||||
|
||||
@Override |
||||
public void popupMenuWillBecomeVisible(PopupMenuEvent e) { |
||||
searchExecute(); |
||||
} |
||||
|
||||
@Override |
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void popupMenuCanceled(PopupMenuEvent e) { |
||||
|
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 重写输入框编辑器,实现输入框模糊搜索逻辑 |
||||
*/ |
||||
private class TableSearchComboBoxEditor extends FrTreeSearchComboBoxEditor { |
||||
|
||||
public TableSearchComboBoxEditor(FRTreeComboBox comboBox) { |
||||
super(comboBox); |
||||
} |
||||
|
||||
@Override |
||||
protected void changeHandler() { |
||||
if (isSetting()) { |
||||
return; |
||||
} |
||||
setPopupVisible(true); |
||||
this.item = textField.getText(); |
||||
searchExecute(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
package com.fr.design.gui.ifilechooser; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/12/29 |
||||
*/ |
||||
public class ExtensionFilter { |
||||
|
||||
private final String des; |
||||
private final String[] extensions; |
||||
|
||||
public ExtensionFilter(String des, String... extensions) { |
||||
this.des = des; |
||||
this.extensions = extensions; |
||||
} |
||||
|
||||
public String getDes() { |
||||
return des; |
||||
} |
||||
|
||||
public String[] getExtensions() { |
||||
return extensions; |
||||
} |
||||
} |
@ -0,0 +1,109 @@
|
||||
package com.fr.design.gui.ifilechooser; |
||||
|
||||
/** |
||||
* 文件选择器可设置的参数集合 |
||||
* |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/12/21 |
||||
*/ |
||||
public class FileChooserArgs { |
||||
|
||||
private final FileSelectionMode fileSelectionMode; |
||||
private final String filterDes; |
||||
private final String[] extensions; |
||||
private final String selectedPath; |
||||
private final ExtensionFilter[] filters; |
||||
private final String tipText; |
||||
private final boolean multiSelectionEnabled; |
||||
|
||||
public static Builder newBuilder() { |
||||
return new Builder(); |
||||
} |
||||
|
||||
private FileChooserArgs(Builder builder) { |
||||
this.fileSelectionMode = builder.fileSelectionMode; |
||||
this.filterDes = builder.filterDes; |
||||
this.extensions = builder.extensions; |
||||
this.selectedPath = builder.selectedPath; |
||||
this.filters = builder.filters; |
||||
this.tipText = builder.tipText; |
||||
this.multiSelectionEnabled = builder.multiSelectionEnabled; |
||||
} |
||||
|
||||
public FileSelectionMode getFileSelectionMode() { |
||||
return fileSelectionMode; |
||||
} |
||||
|
||||
public String getFilterDes() { |
||||
return filterDes; |
||||
} |
||||
|
||||
public String[] getExtensions() { |
||||
return extensions; |
||||
} |
||||
|
||||
public String getSelectedPath() { |
||||
return selectedPath; |
||||
} |
||||
|
||||
public ExtensionFilter[] getFilters() { |
||||
return filters; |
||||
} |
||||
|
||||
public String getTipText() { |
||||
return tipText; |
||||
} |
||||
|
||||
public boolean isMultiSelectionEnabled() { |
||||
return multiSelectionEnabled; |
||||
} |
||||
|
||||
public static class Builder { |
||||
|
||||
private FileSelectionMode fileSelectionMode; |
||||
private String filterDes; |
||||
private String[] extensions; |
||||
private String selectedPath; |
||||
private ExtensionFilter[] filters = new ExtensionFilter[0]; |
||||
private String tipText; |
||||
private boolean multiSelectionEnabled; |
||||
|
||||
public Builder setFileSelectionMode(FileSelectionMode fileSelectionMode) { |
||||
this.fileSelectionMode = fileSelectionMode; |
||||
return this; |
||||
} |
||||
|
||||
public Builder setFilter(String filterDes, String... extensions) { |
||||
this.filterDes = filterDes; |
||||
this.extensions = extensions; |
||||
return this; |
||||
} |
||||
|
||||
public Builder setSelectedPath(String selectedPath) { |
||||
this.selectedPath = selectedPath; |
||||
return this; |
||||
} |
||||
|
||||
public Builder setFilters(ExtensionFilter[] filters) { |
||||
this.filters = filters; |
||||
return this; |
||||
} |
||||
|
||||
public Builder setTipText(String tipText) { |
||||
this.tipText = tipText; |
||||
return this; |
||||
} |
||||
|
||||
public Builder setMultiSelectionEnabled(boolean multiSelectionEnabled) { |
||||
this.multiSelectionEnabled = multiSelectionEnabled; |
||||
return this; |
||||
} |
||||
|
||||
public FileChooserArgs build() { |
||||
return new FileChooserArgs(this); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,44 @@
|
||||
package com.fr.design.gui.ifilechooser; |
||||
|
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.os.impl.SupportOSImpl; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/12/21 |
||||
*/ |
||||
public class FileChooserFactory { |
||||
|
||||
public static FileChooserProvider createFileChooser(FileChooserArgs fileChooserArgs) { |
||||
if (SupportOSImpl.OLD_STYLE_CHOOSER.support()) { |
||||
return new SwingFileChooser.Builder(). |
||||
setFileSelectionMode(fileChooserArgs.getFileSelectionMode()). |
||||
setFileFilter(fileChooserArgs.getFilterDes(), fileChooserArgs.getExtensions()). |
||||
setSelectedFile(fileChooserArgs.getSelectedPath()). |
||||
setMultiSelectionEnabled(fileChooserArgs.isMultiSelectionEnabled()). |
||||
setTipText(fileChooserArgs.getTipText()). |
||||
setFileFilter(fileChooserArgs.getFilters()).build(); |
||||
} else { |
||||
return new JavaFxNativeFileChooser.Builder(). |
||||
fileSelectionMode(fileChooserArgs.getFileSelectionMode()). |
||||
filter(fileChooserArgs.getFilterDes(), fileChooserArgs.getExtensions()). |
||||
currentDirectory(fileChooserArgs.getSelectedPath()). |
||||
title(fileChooserArgs.getTipText()). |
||||
filters(fileChooserArgs.getFilters()).build(); |
||||
} |
||||
} |
||||
|
||||
public static FileChooserProvider createImageFileChooser() { |
||||
if (SupportOSImpl.OLD_STYLE_CHOOSER.support()) { |
||||
return new SwingImageFileChooser(); |
||||
} else { |
||||
return new JavaFxNativeFileChooser.Builder(). |
||||
fileSelectionMode(FileSelectionMode.FILE). |
||||
title(Toolkit.i18nText("Fine-Design_Basic_Open")). |
||||
filter(Toolkit.i18nText("Fine-Design_Basic_Image_Image_Files"), "*.jpg", "*.gif", "*.png", "*.bmp"). |
||||
build(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,134 @@
|
||||
package com.fr.design.gui.ifilechooser; |
||||
|
||||
import com.fr.common.annotations.Negative; |
||||
import com.fr.design.upm.UpmUtils; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import java.awt.Component; |
||||
import java.io.File; |
||||
import javax.swing.JFileChooser; |
||||
import javax.swing.filechooser.FileFilter; |
||||
import javax.swing.filechooser.FileNameExtensionFilter; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/12/21 |
||||
*/ |
||||
@Negative(until = "2022-6-1") |
||||
class SwingFileChooser implements FileChooserProvider { |
||||
|
||||
private final JFileChooser fileChooser; |
||||
private final Builder builder; |
||||
|
||||
private SwingFileChooser(Builder builder) { |
||||
fileChooser = new JFileChooser(); |
||||
fileChooser.setFileSelectionMode(builder.fileSelectionMode); |
||||
fileChooser.setFileFilter(builder.fileFilter); |
||||
fileChooser.setSelectedFile(builder.selectedFile); |
||||
fileChooser.setMultiSelectionEnabled(builder.multiSelectionEnabled); |
||||
this.builder = builder; |
||||
} |
||||
|
||||
@Override |
||||
public File[] getSelectedFiles() { |
||||
if (ArrayUtils.isNotEmpty(fileChooser.getSelectedFiles())) { |
||||
return fileChooser.getSelectedFiles(); |
||||
} else { |
||||
return new File[]{fileChooser.getSelectedFile()}; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public File getSelectedFile() { |
||||
return fileChooser.getSelectedFile(); |
||||
} |
||||
|
||||
@Override |
||||
public int showDialog(Component parent) { |
||||
if (StringUtils.isEmpty(builder.tipText)) { |
||||
return fileChooser.showOpenDialog(parent); |
||||
} else { |
||||
return fileChooser.showDialog(parent, builder.tipText); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int showOpenDialog(Component parent, String approveButtonText) { |
||||
return fileChooser.showDialog(parent, approveButtonText); |
||||
} |
||||
|
||||
@Override |
||||
public void setCurrentDirectory(File file) { |
||||
fileChooser.setCurrentDirectory(file); |
||||
} |
||||
|
||||
@Override |
||||
public void setMultiSelectionEnabled(boolean multiple) { |
||||
fileChooser.setMultiSelectionEnabled(multiple); |
||||
} |
||||
|
||||
/** |
||||
* 和一般builder不同的是 setXXX还做参数转换逻辑 |
||||
*/ |
||||
public static class Builder { |
||||
|
||||
private int fileSelectionMode = JFileChooser.FILES_ONLY; |
||||
private FileFilter fileFilter; |
||||
private File selectedFile; |
||||
private boolean multiSelectionEnabled; |
||||
private String tipText; |
||||
|
||||
public Builder setFileSelectionMode(FileSelectionMode fileSelectionMode) { |
||||
if (FileSelectionMode.DIR.equals(fileSelectionMode)) { |
||||
this.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY; |
||||
} else if (FileSelectionMode.FILE.equals(fileSelectionMode)) { |
||||
this.fileSelectionMode = JFileChooser.FILES_ONLY; |
||||
} else if (FileSelectionMode.MULTIPLE_FILE.equals(fileSelectionMode)) { |
||||
this.fileSelectionMode = JFileChooser.FILES_AND_DIRECTORIES; |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public Builder setFileFilter(String des, String... extension) { |
||||
if (StringUtils.isNotEmpty(des) && ArrayUtils.isNotEmpty(extension)) { |
||||
this.fileFilter = new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(extension)); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public Builder setFileFilter(ExtensionFilter[] extensionFilters) { |
||||
StringBuilder desBuilder = new StringBuilder(); |
||||
String[] extensions = new String[0]; |
||||
for (ExtensionFilter extensionFilter : extensionFilters) { |
||||
desBuilder.append(extensionFilter.getDes()).append(" "); |
||||
extensions = ArrayUtils.addAll(extensions, UpmUtils.findMatchedExtension(extensionFilter.getExtensions())); |
||||
} |
||||
if (ArrayUtils.isNotEmpty(extensionFilters)) { |
||||
this.fileFilter = new FileNameExtensionFilter(desBuilder.toString().trim(), extensions); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public Builder setSelectedFile(String selectedPath) { |
||||
if (StringUtils.isNotEmpty(selectedPath)) { |
||||
this.selectedFile = new File(selectedPath); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public Builder setMultiSelectionEnabled(boolean multiSelectionEnabled) { |
||||
this.multiSelectionEnabled = multiSelectionEnabled; |
||||
return this; |
||||
} |
||||
|
||||
public Builder setTipText(String tipText) { |
||||
this.tipText = tipText; |
||||
return this; |
||||
} |
||||
|
||||
public SwingFileChooser build() { |
||||
return new SwingFileChooser(this); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,276 @@
|
||||
package com.fr.design.gui.ifilechooser; |
||||
|
||||
import com.fr.base.BaseUtils; |
||||
import com.fr.common.annotations.Negative; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.design.style.ChooseFileView; |
||||
import com.fr.design.style.background.image.ExpandFileChooser; |
||||
import java.awt.Component; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
import java.io.File; |
||||
import java.util.Enumeration; |
||||
import java.util.Hashtable; |
||||
import javax.swing.filechooser.FileFilter; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/12/30 |
||||
*/ |
||||
@Negative(until = "2022-6-1") |
||||
class SwingImageFileChooser extends ExpandFileChooser implements FileChooserProvider { |
||||
|
||||
public SwingImageFileChooser() { |
||||
super(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image_Compress"),com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Open")); |
||||
ExampleFileFilter bothFilter = new ExampleFileFilter( |
||||
new String[]{"jpg", "gif", "png", "bmp"}, |
||||
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image_Image_Files")); |
||||
bothFilter.setExtensionListInDescription(true); |
||||
this.addChoosableFileFilter(bothFilter); |
||||
this.setAcceptAllFileFilterUsed(false); |
||||
|
||||
// Create Custom FileView
|
||||
ChooseFileView fileView = new ChooseFileView(); |
||||
fileView.putIcon("jpg", BaseUtils.readIcon("/com/fr/base/images/dialog/file/jpgFile.gif")); |
||||
fileView.putIcon("gif", BaseUtils.readIcon("/com/fr/base/images/dialog/file/gifFile.gif")); |
||||
fileView.putIcon("png", BaseUtils.readIcon("/com/fr/base/images/dialog/file/pngFile.png")); |
||||
fileView.putIcon("bmp", BaseUtils.readIcon("/com/fr/base/images/dialog/file/bmpFile.gif")); |
||||
|
||||
this.setFileView(fileView); |
||||
} |
||||
|
||||
@Override |
||||
public int showDialog(Component parent, String approveButtonText) { |
||||
return super.showDialog(parent, approveButtonText); |
||||
} |
||||
|
||||
@Override |
||||
public ActionListener checkAction() { |
||||
return new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
DesignerEnvManager.getEnvManager().setImageCompress(isCheckSelected()); |
||||
DesignerEnvManager.getEnvManager().saveXMLFile(); |
||||
} |
||||
}; |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public int showDialog(Component parent) { |
||||
return showOpenDialog(parent); |
||||
} |
||||
|
||||
/** |
||||
* A convenience implementation of FileFilter that filters out |
||||
* all files except for those type extensions that it knows about. |
||||
* <p/>D:\finereport\develop\code\test\TestCase\WEB-INF\reportlets\TestCase\01903.cpt |
||||
* <p> |
||||
* Extensions are of the type ".foo", which is typically found on |
||||
* Windows and Unix boxes, but not on Macinthosh. Case is ignored. |
||||
* <p/> |
||||
* Example - create a new filter that filerts out all files |
||||
* but gif and jpg image files: |
||||
* <p/> |
||||
* JFileChooser chooser = new JFileChooser(); |
||||
* ExampleFileFilter filter = new ExampleFileFilter( |
||||
* new String{"gif", "jpg"}, "JPEG & GIF Images") |
||||
* chooser.addChoosableFileFilter(filter); |
||||
* chooser.showOpenDialog(this); |
||||
* |
||||
* @author Jeff Dinkins |
||||
* @version 1.12 12/03/01 |
||||
*/ |
||||
class ExampleFileFilter extends FileFilter { |
||||
private Hashtable filters = null; |
||||
private String description = null; |
||||
private String fullDescription = null; |
||||
private boolean useExtensionsInDescription = true; |
||||
|
||||
/** |
||||
* Creates a file filter. If no filters are added, then all |
||||
* files are accepted. |
||||
* |
||||
* @see #addExtension |
||||
*/ |
||||
public ExampleFileFilter() { |
||||
this.filters = new Hashtable(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a file filter that accepts files with the given extension. |
||||
* Example: new ExampleFileFilter("jpg"); |
||||
* |
||||
* @see #addExtension |
||||
*/ |
||||
public ExampleFileFilter(String extension) { |
||||
this(extension, null); |
||||
} |
||||
|
||||
/** |
||||
* Creates a file filter that accepts the given file type. |
||||
* Example: new ExampleFileFilter("jpg", "JPEG Image Images"); |
||||
* <p/> |
||||
* Note that the "." before the extension is not needed. If |
||||
* provided, it will be ignored. |
||||
* |
||||
* @see #addExtension |
||||
*/ |
||||
public ExampleFileFilter(String extension, String description) { |
||||
this(); |
||||
if (extension != null) addExtension(extension); |
||||
if (description != null) setDescription(description); |
||||
} |
||||
|
||||
/** |
||||
* Creates a file filter from the given string array. |
||||
* Example: new ExampleFileFilter(String {"gif", "jpg"}); |
||||
* <p/> |
||||
* Note that the "." before the extension is not needed adn |
||||
* will be ignored. |
||||
* |
||||
* @see #addExtension |
||||
*/ |
||||
public ExampleFileFilter(String[] filters) { |
||||
this(filters, null); |
||||
} |
||||
|
||||
/** |
||||
* Creates a file filter from the given string array and description. |
||||
* Example: new ExampleFileFilter(String {"gif", "jpg"}, "Gif and JPG Images"); |
||||
* <p/> |
||||
* Note that the "." before the extension is not needed and will be ignored. |
||||
* |
||||
* @see #addExtension |
||||
*/ |
||||
public ExampleFileFilter(String[] filters, String description) { |
||||
this(); |
||||
for (int i = 0; i < filters.length; i++) { |
||||
// add filters one by one
|
||||
addExtension(filters[i]); |
||||
} |
||||
if (description != null) setDescription(description); |
||||
} |
||||
|
||||
/** |
||||
* Return true if this file should be shown in the directory pane, |
||||
* false if it shouldn't. |
||||
* <p/> |
||||
* Files that begin with "." are ignored. |
||||
* |
||||
* @see #getExtension |
||||
*/ |
||||
@Override |
||||
public boolean accept(File f) { |
||||
if (f != null) { |
||||
if (f.isDirectory()) { |
||||
return true; |
||||
} |
||||
String extension = getExtension(f); |
||||
if (extension != null && filters.get(getExtension(f)) != null) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Return the extension portion of the file's name . |
||||
* |
||||
* @see #getExtension |
||||
* @see FileFilter#accept |
||||
*/ |
||||
public String getExtension(File f) { |
||||
if (f != null) { |
||||
String filename = f.getName(); |
||||
int i = filename.lastIndexOf('.'); |
||||
if (i > 0 && i < filename.length() - 1) { |
||||
return filename.substring(i + 1).toLowerCase(); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Adds a filetype "dot" extension to filter against. |
||||
* <p/> |
||||
* For example: the following code will create a filter that filters |
||||
* out all files except those that end in ".jpg" and ".tif": |
||||
* <p/> |
||||
* ExampleFileFilter filter = new ExampleFileFilter(); |
||||
* filter.addExtension("jpg"); |
||||
* filter.addExtension("tif"); |
||||
* <p/> |
||||
* Note that the "." before the extension is not needed and will be ignored. |
||||
*/ |
||||
public void addExtension(String extension) { |
||||
if (filters == null) { |
||||
filters = new Hashtable(5); |
||||
} |
||||
filters.put(extension.toLowerCase(), this); |
||||
fullDescription = null; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Returns the human readable description of this filter. For |
||||
* example: "JPEG and GIF Image Files (*.jpg, *.gif)" |
||||
* |
||||
* @see FileFilter#getDescription |
||||
*/ |
||||
@Override |
||||
public String getDescription() { |
||||
if (fullDescription == null) { |
||||
if (description == null || isExtensionListInDescription()) { |
||||
fullDescription = description == null ? "(" : description + " ("; |
||||
// build the description from the extension list
|
||||
Enumeration extensions = filters.keys(); |
||||
if (extensions != null) { |
||||
fullDescription += "." + extensions.nextElement(); |
||||
while (extensions.hasMoreElements()) { |
||||
fullDescription += ", ." + extensions.nextElement(); |
||||
} |
||||
} |
||||
fullDescription += ")"; |
||||
} else { |
||||
fullDescription = description; |
||||
} |
||||
} |
||||
return fullDescription; |
||||
} |
||||
|
||||
/** |
||||
* Sets the human readable description of this filter. For |
||||
* example: filter.setDescription("Gif and JPG Images"); |
||||
*/ |
||||
public void setDescription(String description) { |
||||
this.description = description; |
||||
fullDescription = null; |
||||
} |
||||
|
||||
/** |
||||
* Determines whether the extension list (.jpg, .gif, etc) should |
||||
* show up in the human readable description. |
||||
* <p/> |
||||
* Only relevent if a description was provided in the constructor |
||||
* or using setDescription(); |
||||
*/ |
||||
public void setExtensionListInDescription(boolean b) { |
||||
useExtensionsInDescription = b; |
||||
fullDescription = null; |
||||
} |
||||
|
||||
/** |
||||
* Returns whether the extension list (.jpg, .gif, etc) should |
||||
* show up in the human readable description. |
||||
* <p/> |
||||
* Only relevent if a description was provided in the constructor |
||||
* or using setDescription(); |
||||
*/ |
||||
public boolean isExtensionListInDescription() { |
||||
return useExtensionsInDescription; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,26 @@
|
||||
package com.fr.design.locale.impl; |
||||
|
||||
import com.fr.general.GeneralContext; |
||||
import com.fr.general.locale.LocaleMark; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
|
||||
public class ShowOnlineWidgetMark implements LocaleMark<Boolean> { |
||||
private Map<Locale, Boolean> map = new HashMap<>(); |
||||
|
||||
public ShowOnlineWidgetMark() { |
||||
map.put(Locale.CHINA, true); |
||||
map.put(Locale.TAIWAN, true); |
||||
map.put(Locale.US, false); |
||||
map.put(Locale.KOREA, false); |
||||
map.put(Locale.JAPAN, false); |
||||
} |
||||
|
||||
@Override |
||||
public Boolean getValue() { |
||||
Boolean result = map.get(GeneralContext.getLocale()); |
||||
return result == null ? false : result; |
||||
} |
||||
} |
@ -0,0 +1,48 @@
|
||||
package com.fr.design.login.config; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.Properties; |
||||
|
||||
/** |
||||
* @author Lanlan |
||||
* @version 10.0 |
||||
* Created by Lanlan on 2022/6/20 |
||||
*/ |
||||
public class DefaultLoginKeys { |
||||
|
||||
private static final String FILENAME = "com/fr/design/config/default"; |
||||
|
||||
private static final DefaultLoginKeys INSTANCE = new DefaultLoginKeys(); |
||||
|
||||
public static DefaultLoginKeys getInstance() { |
||||
return INSTANCE; |
||||
} |
||||
|
||||
private final Map<String, String> keys = new HashMap<>(); |
||||
|
||||
private DefaultLoginKeys() { |
||||
Properties properties = load(); |
||||
for (Map.Entry<Object, Object> entry : properties.entrySet()) { |
||||
String name = entry.getKey().toString(); |
||||
keys.put(name, entry.getValue().toString()); |
||||
} |
||||
} |
||||
|
||||
public String getKey(String name) { |
||||
return keys.get(name); |
||||
} |
||||
|
||||
private Properties load() { |
||||
Properties properties = new Properties(); |
||||
try (InputStream inputStream = DefaultLoginKeys.class.getClassLoader().getResourceAsStream(FILENAME)) { |
||||
properties.load(inputStream); |
||||
} catch (IOException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return properties; |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue