Browse Source
【问题原因】rt 【改动方案】rt 【review建议】详见开发文档:https://kms.fineres.com/pages/viewpage.action?pageId=340985192feature/x
Yvan
3 years ago
35 changed files with 2272 additions and 90 deletions
@ -0,0 +1,68 @@ |
|||||||
|
package com.fr.design.data.datapane.management.clip; |
||||||
|
|
||||||
|
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper; |
||||||
|
import com.fr.general.NameObject; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* 用于数据集的复制粘贴 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataTreeClipboard { |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据集名称 - 数据集Wrapper |
||||||
|
*/ |
||||||
|
private Map<String, AbstractTableDataWrapper> clip = new HashMap<>(); |
||||||
|
|
||||||
|
private static class Holder { |
||||||
|
private static final TableDataTreeClipboard INSTANCE = new TableDataTreeClipboard(); |
||||||
|
} |
||||||
|
|
||||||
|
private TableDataTreeClipboard() { |
||||||
|
} |
||||||
|
|
||||||
|
public static TableDataTreeClipboard getInstance() { |
||||||
|
return Holder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 添加选中的数据集数据到剪切板,覆盖原本剪切板内数据 |
||||||
|
* |
||||||
|
* @param copyMap |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public void addToClip(Map<String, AbstractTableDataWrapper> copyMap) { |
||||||
|
this.clip = copyMap; |
||||||
|
} |
||||||
|
|
||||||
|
public Map<String, AbstractTableDataWrapper> transferNameObjectArray2Map(NameObject[] selectedNameObjects) { |
||||||
|
Map<String, AbstractTableDataWrapper> resultMap = new HashMap<>(); |
||||||
|
if (selectedNameObjects == null) { |
||||||
|
return resultMap; |
||||||
|
} |
||||||
|
for (NameObject selectedNameObject : selectedNameObjects) { |
||||||
|
resultMap.put(selectedNameObject.getName(), (AbstractTableDataWrapper) selectedNameObject.getObject()); |
||||||
|
} |
||||||
|
return resultMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 取出剪切板内的所有数据集数据,剪切板不清空 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Map<String, AbstractTableDataWrapper> takeFromClip() { |
||||||
|
return clip; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 清空剪切板 |
||||||
|
*/ |
||||||
|
public void reset() { |
||||||
|
clip.clear(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,268 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search; |
||||||
|
|
||||||
|
import com.fr.data.TableDataSource; |
||||||
|
import com.fr.data.impl.storeproc.StoreProcedure; |
||||||
|
import com.fr.design.DesignModelAdapter; |
||||||
|
import com.fr.design.data.datapane.TableDataTree; |
||||||
|
import com.fr.design.data.datapane.TableDataTreePane; |
||||||
|
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeEvent; |
||||||
|
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeListener; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus; |
||||||
|
import com.fr.design.data.datapane.management.search.time.TableDataSearchTimer; |
||||||
|
import com.fr.design.data.datapane.management.search.view.TreeSearchRendererHelper; |
||||||
|
import com.fr.design.data.tabledata.wrapper.TableDataWrapper; |
||||||
|
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; |
||||||
|
import com.fr.general.NameObject; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
|
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据集树搜索管理器 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataTreeSearchManager { |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据集树搜索器 |
||||||
|
*/ |
||||||
|
private TableDataTreeSearcher treeSearcher; |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索任务的状态 |
||||||
|
*/ |
||||||
|
private TreeSearchStatus treeSearchStatus; |
||||||
|
|
||||||
|
/** |
||||||
|
* 缓存上次搜索文本,避免重复搜索 |
||||||
|
*/ |
||||||
|
private String lastSearchText; |
||||||
|
|
||||||
|
/** |
||||||
|
* 存储与复原 原本数据集树的UI |
||||||
|
*/ |
||||||
|
private TreeSearchRendererHelper rendererHelper; |
||||||
|
|
||||||
|
/** |
||||||
|
* 取数计数器 |
||||||
|
*/ |
||||||
|
private AtomicInteger count; |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索状态变化监听 |
||||||
|
*/ |
||||||
|
private List<TreeSearchStatusChangeListener> listeners = new ArrayList<>(); |
||||||
|
|
||||||
|
private TableDataTreeSearchManager() { |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
private void init() { |
||||||
|
this.treeSearchStatus = TreeSearchStatus.SEARCH_NOT_BEGIN; |
||||||
|
} |
||||||
|
|
||||||
|
private static class Holder { |
||||||
|
private static final TableDataTreeSearchManager INSTANCE = new TableDataTreeSearchManager(); |
||||||
|
} |
||||||
|
|
||||||
|
public static TableDataTreeSearchManager getInstance() { |
||||||
|
return Holder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
public TreeSearchStatus getTreeSearchStatus() { |
||||||
|
return treeSearchStatus; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) { |
||||||
|
this.treeSearchStatus = treeSearchStatus; |
||||||
|
// 每次设置搜索状态,都触发下监听,让页面跟随变化
|
||||||
|
SwingUtilities.invokeLater(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
for (TreeSearchStatusChangeListener listener : listeners) { |
||||||
|
listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus)); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) { |
||||||
|
listeners.add(listener); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 工具栏处切换到搜索面板 |
||||||
|
* |
||||||
|
* @param searchMode |
||||||
|
* @param tableDataSource |
||||||
|
*/ |
||||||
|
public void switchToSearch(TableDataSearchMode searchMode, TableDataSource tableDataSource) { |
||||||
|
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); |
||||||
|
rendererHelper = new TreeSearchRendererHelper(); |
||||||
|
rendererHelper.save(getCurrentTableDataTree()); |
||||||
|
treeSearcher = new TableDataTreeSearcher(); |
||||||
|
treeSearcher.beforeSearch(searchMode, tableDataSource); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取当前的tableDataTree |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private TableDataTree getCurrentTableDataTree() { |
||||||
|
DesignModelAdapter<?, ?> currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter(); |
||||||
|
TableDataTreePane tableDataTreePane = (TableDataTreePane) TableDataTreePane.getInstance(currentModelAdapter); |
||||||
|
return tableDataTreePane.getDataTree(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMatchSetsEmpty() { |
||||||
|
return treeSearcher.isMatchSetsEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 开始搜索 |
||||||
|
* |
||||||
|
* @param searchText |
||||||
|
*/ |
||||||
|
public void startSearch(String searchText) { |
||||||
|
if (isRepeatSearch(searchText)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
setTreeSearchStatus(TreeSearchStatus.SEARCHING); |
||||||
|
rendererHelper.replaceTreeRenderer(getCurrentTableDataTree(), searchText); |
||||||
|
count = new AtomicInteger(treeSearcher.getNotCalculatedSetsSize()); |
||||||
|
System.out.println("count = " + count.intValue()); |
||||||
|
// 计时开始
|
||||||
|
TableDataSearchTimer.getInstance().startClock(); |
||||||
|
treeSearcher.startSearch(searchText); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 计数-1 |
||||||
|
*/ |
||||||
|
public void decreaseCount() { |
||||||
|
if (count == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
int cunrrentCount = count.decrementAndGet(); |
||||||
|
// 减到0后判断状态
|
||||||
|
if (cunrrentCount == 0 && getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { |
||||||
|
completeSearch(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isRepeatSearch(String searchText) { |
||||||
|
if (StringUtils.isEmpty(lastSearchText)) { |
||||||
|
lastSearchText = searchText; |
||||||
|
return false; |
||||||
|
} |
||||||
|
return StringUtils.equals(lastSearchText, searchText); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 刷新树,更新搜索的结果 |
||||||
|
*/ |
||||||
|
public void updateTableDataTree() { |
||||||
|
getCurrentTableDataTree().refresh4TreeSearch(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 中断搜索 |
||||||
|
*/ |
||||||
|
public void stopSearch() { |
||||||
|
setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED); |
||||||
|
TableDataSearchTimer.getInstance().stopClock(); |
||||||
|
count = null; |
||||||
|
treeSearcher.stopSearch(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索完成 |
||||||
|
*/ |
||||||
|
public void completeSearch() { |
||||||
|
setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED); |
||||||
|
TableDataSearchTimer.getInstance().stopClock(); |
||||||
|
count = null; |
||||||
|
treeSearcher.completeSearch(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 切换回工具栏 |
||||||
|
*/ |
||||||
|
public void switchBackToolBar() { |
||||||
|
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); |
||||||
|
lastSearchText = null; |
||||||
|
treeSearcher.afterSearch(); |
||||||
|
rendererHelper.restore(getCurrentTableDataTree()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 节点是否应该添加到搜索结果树的根节点中 |
||||||
|
* 只针对数据集节点 |
||||||
|
* |
||||||
|
* @param treeNode 数据集节点 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public boolean nodeMatches(ExpandMutableTreeNode treeNode) { |
||||||
|
String nodeName = treeNode.getUserObject().toString(); |
||||||
|
return treeSearcher.nodeMatches(nodeName); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 节点是否应该展开 |
||||||
|
* |
||||||
|
* @param treeNode |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public boolean nodeCanExpand(ExpandMutableTreeNode treeNode) { |
||||||
|
String dsName = treeNode.getUserObject().toString(); |
||||||
|
return treeSearcher.nodeCanExpand(dsName); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理节点的展开,如果此节点是存储过程,还会处理其子表节点的展开 |
||||||
|
* 只针对数据集节点 |
||||||
|
* |
||||||
|
* @param treeNode |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public ExpandMutableTreeNode dealWithNodeExpand(ExpandMutableTreeNode treeNode) { |
||||||
|
String tableDataName = treeNode.getUserObject().toString(); |
||||||
|
// 主要还是处理存储过程
|
||||||
|
if (isTreeNodeStoreProcedure(treeNode)) { |
||||||
|
int childCount = treeNode.getChildCount(); |
||||||
|
for (int i = 0; i < childCount; i++) { |
||||||
|
ExpandMutableTreeNode child = (ExpandMutableTreeNode) treeNode.getChildAt(i); |
||||||
|
if (treeSearcher.nodeCanExpand(tableDataName + "_" + child.getUserObject().toString())) { |
||||||
|
child.setExpanded(true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (nodeCanExpand(treeNode)) { |
||||||
|
treeNode.setExpanded(true); |
||||||
|
} |
||||||
|
return treeNode; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断此节点是否为存储过程 |
||||||
|
* |
||||||
|
* @param treeNode |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public boolean isTreeNodeStoreProcedure(ExpandMutableTreeNode treeNode) { |
||||||
|
Object userObject = treeNode.getUserObject(); |
||||||
|
if (userObject instanceof NameObject) { |
||||||
|
NameObject nameObject = (NameObject) userObject; |
||||||
|
TableDataWrapper tableDataWrapper = (TableDataWrapper) nameObject.getObject(); |
||||||
|
return tableDataWrapper.getTableData() instanceof StoreProcedure; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearcher; |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索任务回调 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public interface TreeSearchCallback { |
||||||
|
|
||||||
|
void done(TreeSearchResult treeSearchResult); |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public interface TreeSearchResult { |
||||||
|
|
||||||
|
/** |
||||||
|
* 任务结果是否成功 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
boolean isSuccess(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据集名称匹配或者列名匹配时,需要将数据集名称添加到匹配结果集中 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
List<String> getAddToMatch(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据集有列名匹配时,需要添加到展开结果集中 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
List<String> getAddToExpand(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据集完成计算后,需要添加到完成结果集中 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
List<String> getAddToCalculated(); |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public interface TreeSearchTask extends Runnable { |
||||||
|
|
||||||
|
@Override |
||||||
|
void run(); |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control.common; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; |
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback; |
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchResult; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus; |
||||||
|
|
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataSearchCallBack implements TreeSearchCallback { |
||||||
|
|
||||||
|
protected TableDataTreeSearcher treeSearcher; |
||||||
|
|
||||||
|
public TableDataSearchCallBack(TableDataTreeSearcher treeSearcher) { |
||||||
|
this.treeSearcher = treeSearcher; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void done(TreeSearchResult treeSearchResult) { |
||||||
|
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (treeSearchResult.isSuccess()) { |
||||||
|
// 添加结果
|
||||||
|
addToTreeSearcher(treeSearchResult); |
||||||
|
// 处理UI
|
||||||
|
updateTableDataTree(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void updateTableDataTree() { |
||||||
|
SwingUtilities.invokeLater(() -> { |
||||||
|
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { |
||||||
|
return; |
||||||
|
} |
||||||
|
TableDataTreeSearchManager.getInstance().updateTableDataTree(); |
||||||
|
// todo 没想清楚为啥会这么快结束,暂时取消搜索计数
|
||||||
|
// TableDataTreeSearchManager.getInstance().decreaseCount();
|
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
protected void addToTreeSearcher(TreeSearchResult treeSearchResult) { |
||||||
|
// 添加到已计算结果集
|
||||||
|
treeSearcher.addToCalculatedSets(treeSearchResult.getAddToCalculated()); |
||||||
|
// 添加到匹配结果集
|
||||||
|
treeSearcher.addToMatchSets(treeSearchResult.getAddToMatch()); |
||||||
|
// 添加到展开结果集
|
||||||
|
treeSearcher.addToCanExpandSets(treeSearchResult.getAddToExpand()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,105 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control.common; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchResult; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataSearchResult implements TreeSearchResult { |
||||||
|
|
||||||
|
private boolean success; |
||||||
|
|
||||||
|
private List<String> addToMatch; |
||||||
|
|
||||||
|
private List<String> addToExpand; |
||||||
|
|
||||||
|
private List<String> addToCalculated; |
||||||
|
|
||||||
|
protected TableDataSearchResult(Builder builder) { |
||||||
|
this.success = builder.success; |
||||||
|
this.addToMatch = builder.addToMatch; |
||||||
|
this.addToExpand = builder.addToExpand; |
||||||
|
this.addToCalculated = builder.addToCalculated; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSuccess(boolean success) { |
||||||
|
this.success = success; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAddToMatch(List<String> addToMatch) { |
||||||
|
this.addToMatch = addToMatch; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAddToExpand(List<String> addToExpand) { |
||||||
|
this.addToExpand = addToExpand; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAddToCalculated(List<String> addToCalculated) { |
||||||
|
this.addToCalculated = addToCalculated; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isSuccess() { |
||||||
|
return this.success; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> getAddToMatch() { |
||||||
|
return this.addToMatch; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> getAddToExpand() { |
||||||
|
return this.addToExpand; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> getAddToCalculated() { |
||||||
|
return this.addToCalculated; |
||||||
|
} |
||||||
|
|
||||||
|
public static class Builder { |
||||||
|
|
||||||
|
private boolean success; |
||||||
|
|
||||||
|
private List<String> addToMatch; |
||||||
|
|
||||||
|
private List<String> addToExpand; |
||||||
|
|
||||||
|
private List<String> addToCalculated; |
||||||
|
|
||||||
|
public Builder() { |
||||||
|
this.success = false; |
||||||
|
this.addToMatch = new ArrayList<>(); |
||||||
|
this.addToExpand = new ArrayList<>(); |
||||||
|
this.addToCalculated = new ArrayList<>(); |
||||||
|
} |
||||||
|
|
||||||
|
public Builder buildSuccess(boolean success) { |
||||||
|
this.success = success; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder buildAddToMatch(List<String> addToMatch) { |
||||||
|
this.addToMatch = addToMatch; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder buildAddToExpand(List<String> addToExpand) { |
||||||
|
this.addToExpand = addToExpand; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder buildAddToCalculated(List<String> addToCalculated) { |
||||||
|
this.addToCalculated = addToCalculated; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public TableDataSearchResult build() { |
||||||
|
return new TableDataSearchResult(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,147 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control.common; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; |
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback; |
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchResult; |
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchTask; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus; |
||||||
|
import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper; |
||||||
|
import com.fr.design.data.tabledata.wrapper.TableDataWrapper; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataSearchTask implements TreeSearchTask { |
||||||
|
|
||||||
|
/** |
||||||
|
* 用户搜索的文本 |
||||||
|
*/ |
||||||
|
private String searchText; |
||||||
|
|
||||||
|
private TableDataWrapper tableDataWrapper; |
||||||
|
|
||||||
|
private TreeSearchCallback callback; |
||||||
|
|
||||||
|
public TableDataSearchTask(String searchText, TableDataWrapper tableDataWrapper, TreeSearchCallback callback) { |
||||||
|
this.searchText = searchText; |
||||||
|
this.tableDataWrapper = tableDataWrapper; |
||||||
|
this.callback = callback; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
TreeSearchResult result; |
||||||
|
try { |
||||||
|
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (isTableDataStoreProcedure(tableDataWrapper)) { |
||||||
|
dealWithStoreProcedureTableDataWrapper((StoreProcedureDataWrapper) tableDataWrapper); |
||||||
|
} else { |
||||||
|
dealWithCommonTableDataWrapper(tableDataWrapper); |
||||||
|
} |
||||||
|
} catch (Throwable e) { |
||||||
|
FineLoggerFactory.getLogger().error(e, e.getMessage()); |
||||||
|
dealWithErrorTableDataWrapper(tableDataWrapper); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理错误情况 |
||||||
|
* |
||||||
|
* @param tableDataWrapper |
||||||
|
*/ |
||||||
|
private void dealWithErrorTableDataWrapper(TableDataWrapper tableDataWrapper) { |
||||||
|
callback.done(new TableDataSearchResult.Builder().buildSuccess(false).build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理普通数据集的搜索与匹配 |
||||||
|
* |
||||||
|
* @param tableDataWrapper |
||||||
|
*/ |
||||||
|
private void dealWithCommonTableDataWrapper(TableDataWrapper tableDataWrapper) { |
||||||
|
String tableDataName = tableDataWrapper.getTableDataName(); |
||||||
|
boolean isTableDataNameMatch = isMatchSearch(tableDataName, searchText); |
||||||
|
List<String> columnNameList = tableDataWrapper.calculateColumnNameList(); |
||||||
|
boolean isColumnMatch = columnNameList.stream().anyMatch(columnName -> isMatchSearch(columnName, searchText)); |
||||||
|
TableDataSearchResult result = new TableDataSearchResult.Builder() |
||||||
|
.buildSuccess(true) |
||||||
|
.buildAddToMatch(isTableDataNameMatch || isColumnMatch ? Arrays.asList(tableDataName) : new ArrayList<>()) |
||||||
|
.buildAddToExpand(isColumnMatch ? Arrays.asList(tableDataName) : new ArrayList<>()) |
||||||
|
.buildAddToCalculated(Arrays.asList(tableDataName)) |
||||||
|
.build(); |
||||||
|
callback.done(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理存储过程的搜索与匹配 |
||||||
|
* |
||||||
|
* @param procedureDataWrapper |
||||||
|
*/ |
||||||
|
private void dealWithStoreProcedureTableDataWrapper(StoreProcedureDataWrapper procedureDataWrapper) { |
||||||
|
// 存储过程数据集名称,例如 Proc1_Table1
|
||||||
|
String tableDataName = procedureDataWrapper.getTableDataName(); |
||||||
|
// 存储过程名称,例如 Proc1
|
||||||
|
String storeProcedureName = procedureDataWrapper.getStoreprocedureName(); |
||||||
|
// 存储过程子表名称,例如 Table1
|
||||||
|
String tableName = tableDataName.replaceFirst(storeProcedureName, StringUtils.EMPTY).replaceFirst("_", StringUtils.EMPTY); |
||||||
|
boolean isStoreProcedureNameMatch = isMatchSearch(storeProcedureName, searchText); |
||||||
|
boolean isTableNameMatch = isMatchSearch(tableName, searchText); |
||||||
|
// 再处理子表的columns
|
||||||
|
List<String> columnNameList = tableDataWrapper.calculateColumnNameList(); |
||||||
|
boolean isColumnMatch = columnNameList.stream().anyMatch(columnName -> isMatchSearch(columnName, searchText)); |
||||||
|
Set<String> addToMatch = new HashSet<>(); |
||||||
|
Set<String> addToExpand = new HashSet<>(); |
||||||
|
Set<String> addToCalculated = new HashSet<>(); |
||||||
|
if (isStoreProcedureNameMatch) { |
||||||
|
addToMatch.add(storeProcedureName); |
||||||
|
} |
||||||
|
if (isTableNameMatch) { |
||||||
|
addToMatch.add(storeProcedureName); |
||||||
|
addToExpand.add(storeProcedureName); |
||||||
|
} |
||||||
|
if (isColumnMatch) { |
||||||
|
addToMatch.add(storeProcedureName); |
||||||
|
addToExpand.add(storeProcedureName); |
||||||
|
// 这里有重名风险,所以要添加 “Proc1_Table1”,在结果树展示的时候再去处理
|
||||||
|
addToExpand.add(tableDataName); |
||||||
|
} |
||||||
|
addToCalculated.add(tableDataName); |
||||||
|
TableDataSearchResult result = new TableDataSearchResult.Builder() |
||||||
|
.buildSuccess(true) |
||||||
|
.buildAddToMatch(new ArrayList<>(addToMatch)) |
||||||
|
.buildAddToExpand(new ArrayList<>(addToExpand)) |
||||||
|
.buildAddToCalculated(new ArrayList<>(addToCalculated)) |
||||||
|
.build(); |
||||||
|
callback.done(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断TableDataWrapper内的TableData是否为存储过程 |
||||||
|
* |
||||||
|
* @param tableDataWrapper |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private boolean isTableDataStoreProcedure(TableDataWrapper tableDataWrapper) { |
||||||
|
return tableDataWrapper instanceof StoreProcedureDataWrapper; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断是否匹配搜索文本,不区分大小写 |
||||||
|
* |
||||||
|
* @param str |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private boolean isMatchSearch(String str, String searchText) { |
||||||
|
return str.toUpperCase().contains(searchText.toUpperCase()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control.pre; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchCallBack; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher; |
||||||
|
|
||||||
|
/** |
||||||
|
* 预取数任务回调 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataPreSearchCallBack extends TableDataSearchCallBack { |
||||||
|
|
||||||
|
|
||||||
|
public TableDataPreSearchCallBack(TableDataTreeSearcher treeSearcher) { |
||||||
|
super(treeSearcher); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control.pre; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchResult; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* 预取数任务结果,不需要回调,因此空实现即可 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataPreSearchResult implements TreeSearchResult { |
||||||
|
|
||||||
|
private boolean success; |
||||||
|
|
||||||
|
public TableDataPreSearchResult(boolean success) { |
||||||
|
this.success = success; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isSuccess() { |
||||||
|
return this.success; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> getAddToMatch() { |
||||||
|
return new ArrayList<>(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> getAddToExpand() { |
||||||
|
return new ArrayList<>(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> getAddToCalculated() { |
||||||
|
return new ArrayList<>(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.control.pre; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchTask; |
||||||
|
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchResult; |
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback; |
||||||
|
import com.fr.design.data.datapane.management.search.control.TreeSearchResult; |
||||||
|
import com.fr.design.data.tabledata.wrapper.TableDataWrapper; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* 预取数任务 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataPreSearchTask implements TreeSearchTask { |
||||||
|
|
||||||
|
private TreeSearchCallback callback; |
||||||
|
|
||||||
|
private TableDataWrapper tableDataWrapper; |
||||||
|
|
||||||
|
public TableDataPreSearchTask(TreeSearchCallback callback, TableDataWrapper tableDataWrapper) { |
||||||
|
this.callback = callback; |
||||||
|
this.tableDataWrapper = tableDataWrapper; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
TreeSearchResult result; |
||||||
|
try { |
||||||
|
tableDataWrapper.calculateColumnNameList(); |
||||||
|
result = new TableDataSearchResult.Builder() |
||||||
|
.buildSuccess(true) |
||||||
|
.build(); |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e, "calculate table data {} failed", tableDataWrapper.getTableDataName()); |
||||||
|
result = new TableDataSearchResult.Builder() |
||||||
|
.buildSuccess(false) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
callback.done(result); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.event; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus; |
||||||
|
|
||||||
|
import java.util.EventObject; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TreeSearchStatusChangeEvent extends EventObject { |
||||||
|
|
||||||
|
private TreeSearchStatus status; |
||||||
|
|
||||||
|
public TreeSearchStatusChangeEvent(Object source) { |
||||||
|
super(source); |
||||||
|
this.status = (TreeSearchStatus) source; |
||||||
|
} |
||||||
|
|
||||||
|
public TreeSearchStatus getTreeSearchStatus() { |
||||||
|
return status; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.event; |
||||||
|
|
||||||
|
import java.util.EventListener; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public interface TreeSearchStatusChangeListener extends EventListener { |
||||||
|
|
||||||
|
void updateTreeSearchChange(TreeSearchStatusChangeEvent event); |
||||||
|
} |
@ -0,0 +1,212 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.pane; |
||||||
|
|
||||||
|
import com.fr.base.svg.IconUtils; |
||||||
|
import com.fr.design.constants.UIConstants; |
||||||
|
import com.fr.design.data.datapane.TableDataTree; |
||||||
|
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; |
||||||
|
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeEvent; |
||||||
|
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeListener; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus; |
||||||
|
import com.fr.design.gui.icontainer.UIScrollPane; |
||||||
|
import com.fr.design.gui.ilable.UILabel; |
||||||
|
import com.fr.design.i18n.Toolkit; |
||||||
|
import com.fr.design.layout.FRGUIPaneFactory; |
||||||
|
|
||||||
|
import javax.swing.BorderFactory; |
||||||
|
import javax.swing.JPanel; |
||||||
|
import javax.swing.SwingConstants; |
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.CardLayout; |
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.FlowLayout; |
||||||
|
import java.awt.event.MouseAdapter; |
||||||
|
import java.awt.event.MouseEvent; |
||||||
|
import java.awt.event.MouseListener; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener { |
||||||
|
|
||||||
|
private RemindPane remindPane; |
||||||
|
private TreePane treePane; |
||||||
|
|
||||||
|
public TableDataSearchRemindPane(TableDataTree tableDataTree) { |
||||||
|
this.setLayout(new BorderLayout()); |
||||||
|
remindPane = new RemindPane(); |
||||||
|
treePane = new TreePane(tableDataTree); |
||||||
|
// 初始状态
|
||||||
|
this.add(remindPane, BorderLayout.NORTH); |
||||||
|
this.add(treePane, BorderLayout.CENTER); |
||||||
|
TableDataTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 根据搜索状态变化,来调整自身面板的显示 |
||||||
|
* |
||||||
|
* @param event |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { |
||||||
|
TreeSearchStatus status = event.getTreeSearchStatus(); |
||||||
|
if (status == TreeSearchStatus.SEARCH_NOT_BEGIN) { |
||||||
|
remindPane.onNotBegin(); |
||||||
|
treePane.onNotBegin(); |
||||||
|
} else if (status == TreeSearchStatus.SEARCHING) { |
||||||
|
remindPane.onInSearching(); |
||||||
|
treePane.onInSearching(); |
||||||
|
} else if (status == TreeSearchStatus.SEARCH_STOPPED) { |
||||||
|
remindPane.onStoppedSearching(); |
||||||
|
treePane.onStoppedSearching(); |
||||||
|
} else { |
||||||
|
boolean matchSetsEmpty = TableDataTreeSearchManager.getInstance().isMatchSetsEmpty(); |
||||||
|
// 代表是否搜索出结果
|
||||||
|
remindPane.onDoneSearching(matchSetsEmpty); |
||||||
|
treePane.onDoneSearching(matchSetsEmpty); |
||||||
|
} |
||||||
|
this.revalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
private interface TreeSearchStatusChange { |
||||||
|
|
||||||
|
void onNotBegin(); |
||||||
|
|
||||||
|
void onInSearching(); |
||||||
|
|
||||||
|
void onStoppedSearching(); |
||||||
|
|
||||||
|
void onDoneSearching(boolean matchSetsEmpty); |
||||||
|
} |
||||||
|
|
||||||
|
private class TreePane extends JPanel implements TreeSearchStatusChange { |
||||||
|
|
||||||
|
private UIScrollPane scrollPane; |
||||||
|
|
||||||
|
private JPanel notFoundPane; |
||||||
|
|
||||||
|
private CardLayout cardLayout; |
||||||
|
|
||||||
|
private static final String SCROLL_PANE = "scrollPane"; |
||||||
|
|
||||||
|
private static final String NOT_FOUND_PANE = "notFoundPane"; |
||||||
|
|
||||||
|
public TreePane(TableDataTree tableDataTree) { |
||||||
|
init(tableDataTree); |
||||||
|
} |
||||||
|
|
||||||
|
private void init(TableDataTree tableDataTree) { |
||||||
|
|
||||||
|
scrollPane = new UIScrollPane(tableDataTree); |
||||||
|
scrollPane.setBorder(null); |
||||||
|
|
||||||
|
notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5); |
||||||
|
UILabel emptyPicLabel = new UILabel(); |
||||||
|
emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png")); |
||||||
|
emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER); |
||||||
|
emptyPicLabel.setPreferredSize(new Dimension(240, 100)); |
||||||
|
UILabel textLabel = new UILabel(Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER); |
||||||
|
textLabel.setForeground(Color.gray); |
||||||
|
textLabel.setHorizontalAlignment(SwingConstants.CENTER); |
||||||
|
textLabel.setPreferredSize(new Dimension(240, 20)); |
||||||
|
notFoundPane.add(emptyPicLabel); |
||||||
|
notFoundPane.add(textLabel); |
||||||
|
notFoundPane.setBorder(BorderFactory.createEmptyBorder(80, 0, 0, 0)); |
||||||
|
|
||||||
|
cardLayout = new CardLayout(); |
||||||
|
this.setLayout(cardLayout); |
||||||
|
this.add(scrollPane, SCROLL_PANE); |
||||||
|
this.add(notFoundPane, NOT_FOUND_PANE); |
||||||
|
cardLayout.show(this, SCROLL_PANE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onNotBegin() { |
||||||
|
switchPane(SCROLL_PANE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onInSearching() { |
||||||
|
switchPane(SCROLL_PANE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onStoppedSearching() { |
||||||
|
switchPane(SCROLL_PANE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDoneSearching(boolean matchSetsEmpty) { |
||||||
|
if (matchSetsEmpty) { |
||||||
|
switchPane(NOT_FOUND_PANE); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void switchPane(String paneName) { |
||||||
|
cardLayout.show(this, paneName); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class RemindPane extends JPanel implements TreeSearchStatusChange { |
||||||
|
|
||||||
|
private static final String IN_SEARCHING = "Fine-Design_Tree_Search_In_Searching"; |
||||||
|
private static final String STOP_SEARCHING = "Fine-Design_Tree_Search_Stop_Search"; |
||||||
|
private static final String SEARCHING_STOPPED = "Fine-Design_Tree_Search_Search_Stopped"; |
||||||
|
private static final String DONE_SEARCHING = "Fine-Design_Tree_Search_Search_Completed"; |
||||||
|
|
||||||
|
private UILabel textLabel; |
||||||
|
|
||||||
|
private UILabel stopLabel; |
||||||
|
|
||||||
|
private MouseListener stopSearch; |
||||||
|
|
||||||
|
public RemindPane() { |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
private void init() { |
||||||
|
this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); |
||||||
|
// 初始情况下为Not_Begin
|
||||||
|
textLabel = new UILabel(); |
||||||
|
stopLabel = new UILabel(); |
||||||
|
stopLabel.setForeground(UIConstants.NORMAL_BLUE); |
||||||
|
stopSearch = new MouseAdapter() { |
||||||
|
@Override |
||||||
|
public void mouseClicked(MouseEvent e) { |
||||||
|
TableDataTreeSearchManager.getInstance().stopSearch(); |
||||||
|
} |
||||||
|
}; |
||||||
|
stopLabel.addMouseListener(stopSearch); |
||||||
|
this.add(textLabel); |
||||||
|
this.add(stopLabel); |
||||||
|
onNotBegin(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onNotBegin() { |
||||||
|
this.setVisible(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onInSearching() { |
||||||
|
this.textLabel.setText(IN_SEARCHING); |
||||||
|
this.stopLabel.setText(STOP_SEARCHING); |
||||||
|
this.stopLabel.setVisible(true); |
||||||
|
this.setVisible(true); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onStoppedSearching() { |
||||||
|
this.textLabel.setText(SEARCHING_STOPPED); |
||||||
|
this.stopLabel.setVisible(false); |
||||||
|
this.setVisible(true); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDoneSearching(boolean matchSetsEmpty) { |
||||||
|
this.textLabel.setText(DONE_SEARCHING); |
||||||
|
this.stopLabel.setVisible(false); |
||||||
|
this.setVisible(true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,192 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.pane; |
||||||
|
|
||||||
|
import com.fr.base.svg.IconUtils; |
||||||
|
import com.fr.design.DesignModelAdapter; |
||||||
|
import com.fr.design.constants.UIConstants; |
||||||
|
import com.fr.design.data.datapane.TableDataTreePane; |
||||||
|
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus; |
||||||
|
import com.fr.design.gui.ilable.UILabel; |
||||||
|
import com.fr.design.gui.itextfield.UITextField; |
||||||
|
import com.fr.design.gui.itoolbar.UIToolbar; |
||||||
|
import com.fr.design.i18n.Toolkit; |
||||||
|
import com.fr.design.layout.FRGUIPaneFactory; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
|
||||||
|
import javax.swing.BorderFactory; |
||||||
|
import javax.swing.JPanel; |
||||||
|
import javax.swing.event.DocumentEvent; |
||||||
|
import javax.swing.event.DocumentListener; |
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.CardLayout; |
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.Panel; |
||||||
|
import java.awt.event.FocusEvent; |
||||||
|
import java.awt.event.FocusListener; |
||||||
|
import java.awt.event.KeyAdapter; |
||||||
|
import java.awt.event.KeyEvent; |
||||||
|
import java.awt.event.MouseAdapter; |
||||||
|
import java.awt.event.MouseEvent; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TreeSearchToolbarPane extends Panel { |
||||||
|
|
||||||
|
public static final String TOOLBAR_PANE = "toolbarPane"; |
||||||
|
|
||||||
|
public static final String SEARCH_PANE = "searchPane"; |
||||||
|
|
||||||
|
/** |
||||||
|
* 工具栏 |
||||||
|
*/ |
||||||
|
private UIToolbar toolbar; |
||||||
|
|
||||||
|
/** |
||||||
|
* 工具栏面板 |
||||||
|
*/ |
||||||
|
private JPanel toolbarPane; |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索面板 |
||||||
|
*/ |
||||||
|
private JPanel searchPane; |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索输入框 |
||||||
|
*/ |
||||||
|
private UITextField searchTextField; |
||||||
|
|
||||||
|
/** |
||||||
|
* 内容面板 |
||||||
|
*/ |
||||||
|
private JPanel contentPane; |
||||||
|
|
||||||
|
/** |
||||||
|
* 卡片布局管理器 |
||||||
|
*/ |
||||||
|
private CardLayout cardLayout; |
||||||
|
|
||||||
|
private final KeyAdapter enterPressed = new KeyAdapter() { |
||||||
|
@Override |
||||||
|
public void keyPressed(KeyEvent e) { |
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ENTER) { |
||||||
|
TableDataTreeSearchManager.getInstance().startSearch(searchTextField.getText()); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public TreeSearchToolbarPane(UIToolbar toolbar) { |
||||||
|
this.toolbar = toolbar; |
||||||
|
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||||
|
initToolbarPane(); |
||||||
|
initSearchPane(); |
||||||
|
initContentPane(); |
||||||
|
add(contentPane, BorderLayout.CENTER); |
||||||
|
setPreferredSize(new Dimension(240, 30)); |
||||||
|
} |
||||||
|
|
||||||
|
private void initContentPane() { |
||||||
|
cardLayout = new CardLayout(); |
||||||
|
contentPane = new JPanel(cardLayout); |
||||||
|
contentPane.add(searchPane, SEARCH_PANE); |
||||||
|
contentPane.add(toolbarPane, TOOLBAR_PANE); |
||||||
|
cardLayout.show(contentPane, TOOLBAR_PANE); |
||||||
|
} |
||||||
|
|
||||||
|
private void initSearchPane() { |
||||||
|
searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); |
||||||
|
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); |
||||||
|
searchPane.setBackground(Color.WHITE); |
||||||
|
// 左侧搜索图标
|
||||||
|
UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); |
||||||
|
searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 0)); |
||||||
|
searchLabel.addMouseListener(new MouseAdapter() { |
||||||
|
@Override |
||||||
|
public void mouseClicked(MouseEvent e) { |
||||||
|
// do nothing
|
||||||
|
} |
||||||
|
}); |
||||||
|
// 中间输入框
|
||||||
|
searchTextField = new UITextField(); |
||||||
|
searchTextField.setBorderPainted(false); |
||||||
|
searchTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Tree_Search_Press_Enter_For_Search")); |
||||||
|
searchTextField.addFocusListener(new FocusListener() { |
||||||
|
@Override |
||||||
|
public void focusGained(FocusEvent e) { |
||||||
|
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE)); |
||||||
|
searchPane.repaint(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void focusLost(FocusEvent e) { |
||||||
|
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); |
||||||
|
searchPane.repaint(); |
||||||
|
} |
||||||
|
}); |
||||||
|
this.searchTextField.getDocument().addDocumentListener(new DocumentListener() { |
||||||
|
@Override |
||||||
|
public void insertUpdate(DocumentEvent e) { |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void removeUpdate(DocumentEvent e) { |
||||||
|
dealWithTextChange(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void changedUpdate(DocumentEvent e) { |
||||||
|
} |
||||||
|
}); |
||||||
|
// 右侧返回图标
|
||||||
|
UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/clear")); |
||||||
|
returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return")); |
||||||
|
returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); |
||||||
|
returnLabel.addMouseListener(new MouseAdapter() { |
||||||
|
@Override |
||||||
|
public void mouseClicked(MouseEvent e) { |
||||||
|
searchTextField.setText(StringUtils.EMPTY); |
||||||
|
TableDataTreeSearchManager.getInstance().switchBackToolBar(); |
||||||
|
switchPane(TOOLBAR_PANE); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
searchPane.add(searchLabel, BorderLayout.WEST); |
||||||
|
searchPane.add(searchTextField, BorderLayout.CENTER); |
||||||
|
searchPane.add(returnLabel, BorderLayout.EAST); |
||||||
|
} |
||||||
|
|
||||||
|
private void dealWithTextChange() { |
||||||
|
// 判断搜索是否正在进行
|
||||||
|
if (StringUtils.isEmpty(searchTextField.getText()) && TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCH_NOT_BEGIN) { |
||||||
|
TableDataTreeSearchManager.getInstance().setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); |
||||||
|
DesignModelAdapter<?, ?> currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter(); |
||||||
|
TableDataTreePane tableDataTreePane = (TableDataTreePane) TableDataTreePane.getInstance(currentModelAdapter); |
||||||
|
tableDataTreePane.refreshDockingView(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void initToolbarPane() { |
||||||
|
toolbarPane = new JPanel(); |
||||||
|
toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||||
|
toolbarPane.add(toolbar, BorderLayout.CENTER); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 交换当前面板层级 |
||||||
|
*/ |
||||||
|
public void switchPane(String name) { |
||||||
|
if (StringUtils.equals(name, TOOLBAR_PANE)) { |
||||||
|
searchTextField.removeKeyListener(enterPressed); |
||||||
|
searchTextField.setText(StringUtils.EMPTY); |
||||||
|
} else if (StringUtils.equals(name, SEARCH_PANE)) { |
||||||
|
searchTextField.addKeyListener(enterPressed); |
||||||
|
} |
||||||
|
cardLayout.show(contentPane, name); |
||||||
|
} |
||||||
|
|
||||||
|
public void setPlaceHolder(String placeHolder) { |
||||||
|
this.searchTextField.setPlaceholder(placeHolder); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.searcher; |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索模式 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public enum TableDataSearchMode { |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索模板数据集 |
||||||
|
*/ |
||||||
|
TEMPLATE_TABLE_DATA(0), |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索服务器数据集 |
||||||
|
*/ |
||||||
|
SERVER_TABLE_DATA(1); |
||||||
|
|
||||||
|
private final int mode; |
||||||
|
|
||||||
|
TableDataSearchMode(int mode) { |
||||||
|
this.mode = mode; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMode() { |
||||||
|
return mode; |
||||||
|
} |
||||||
|
|
||||||
|
public static TableDataSearchMode match(int mode) { |
||||||
|
for (TableDataSearchMode searchMode : TableDataSearchMode.values()) { |
||||||
|
if (searchMode.getMode() == mode) { |
||||||
|
return searchMode; |
||||||
|
} |
||||||
|
} |
||||||
|
return TEMPLATE_TABLE_DATA; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,174 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.searcher; |
||||||
|
|
||||||
|
import com.fr.concurrent.NamedThreadFactory; |
||||||
|
import com.fr.data.TableDataSource; |
||||||
|
import com.fr.design.data.DesignTableDataManager; |
||||||
|
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; |
||||||
|
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchCallBack; |
||||||
|
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchTask; |
||||||
|
import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchCallBack; |
||||||
|
import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchTask; |
||||||
|
import com.fr.design.data.tabledata.wrapper.TableDataWrapper; |
||||||
|
|
||||||
|
import javax.swing.event.ChangeEvent; |
||||||
|
import javax.swing.event.ChangeListener; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
import java.util.concurrent.ExecutorService; |
||||||
|
import java.util.concurrent.Executors; |
||||||
|
import java.util.function.Consumer; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataTreeSearcher implements TreeSearcher { |
||||||
|
|
||||||
|
private ExecutorService executorService; |
||||||
|
|
||||||
|
private Map<String, TableDataWrapper> allWrappers = new ConcurrentHashMap<>(); |
||||||
|
|
||||||
|
private final Set<String> calculatedSets = new HashSet<>(); |
||||||
|
|
||||||
|
private final Set<String> notCalculatedSets = new HashSet<>(); |
||||||
|
|
||||||
|
private final Set<String> matchSets = new HashSet<>(); |
||||||
|
|
||||||
|
private final Set<String> canExpandSets = new HashSet<>(); |
||||||
|
|
||||||
|
public TableDataTreeSearcher() { |
||||||
|
initListener(); |
||||||
|
} |
||||||
|
|
||||||
|
private void initListener() { |
||||||
|
DesignTableDataManager.addDsChangeListener(new ChangeListener() { |
||||||
|
@Override |
||||||
|
public void stateChanged(ChangeEvent e) { |
||||||
|
allWrappers.keySet().stream().filter(DesignTableDataManager::isDsNameChanged).forEach(new Consumer<String>() { |
||||||
|
@Override |
||||||
|
public void accept(String key) { |
||||||
|
TableDataWrapper oldWrapper = allWrappers.remove(key); |
||||||
|
calculatedSets.remove(key); |
||||||
|
notCalculatedSets.remove(key); |
||||||
|
matchSets.remove(key); |
||||||
|
canExpandSets.remove(key); |
||||||
|
String newName = DesignTableDataManager.getChangedDsNameByOldDsName(key); |
||||||
|
TableDataWrapper newWrapper = DesignTableDataManager.getAllEditingDataSet(DesignTableDataManager.getEditingTableDataSource()).get(newName); |
||||||
|
allWrappers.put(newName, newWrapper); |
||||||
|
notCalculatedSets.add(newName); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMatchSetsEmpty() { |
||||||
|
return matchSets.isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getNotCalculatedSetsSize() { |
||||||
|
return notCalculatedSets.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void addToCalculatedSets(List<String> tableDataNames) { |
||||||
|
for (String tableDataName : tableDataNames) { |
||||||
|
TableDataWrapper tableDataWrapper = allWrappers.get(tableDataName); |
||||||
|
if (tableDataWrapper == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
notCalculatedSets.remove(tableDataName); |
||||||
|
calculatedSets.add(tableDataName); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void addToMatchSets(List<String> matchNodeNames) { |
||||||
|
matchSets.addAll(matchNodeNames); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void addToCanExpandSets(List<String> canExpandNodeNames) { |
||||||
|
canExpandSets.addAll(canExpandNodeNames); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 正式搜索前,预加载一下数据集列名 |
||||||
|
* |
||||||
|
* @param searchMode |
||||||
|
* @param tableDataSource |
||||||
|
*/ |
||||||
|
public void beforeSearch(TableDataSearchMode searchMode, TableDataSource tableDataSource) { |
||||||
|
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TableDataTreeSearchManager.class)); |
||||||
|
collectTableDataWrappers(searchMode, tableDataSource); |
||||||
|
preCalculateColumns(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 预先对数据集进行取列名的操作,提升用户搜索体验 |
||||||
|
*/ |
||||||
|
private void preCalculateColumns() { |
||||||
|
for (String notCalculatedSet : notCalculatedSets) { |
||||||
|
TableDataWrapper tableDataWrapper = allWrappers.get(notCalculatedSet); |
||||||
|
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN) { |
||||||
|
executorService.execute(new TableDataPreSearchTask(new TableDataPreSearchCallBack(this), tableDataWrapper)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 收集下此次搜索需要进行取数的TableDataWrapper |
||||||
|
* |
||||||
|
* @param searchSubject |
||||||
|
* @param tableDataSource |
||||||
|
*/ |
||||||
|
private void collectTableDataWrappers(TableDataSearchMode searchSubject, TableDataSource tableDataSource) { |
||||||
|
Map<String, TableDataWrapper> dataSet = searchSubject == TableDataSearchMode.TEMPLATE_TABLE_DATA ? |
||||||
|
DesignTableDataManager.getTemplateDataSet(tableDataSource) : |
||||||
|
DesignTableDataManager.getGlobalDataSet(); |
||||||
|
// 转化一下存储过程
|
||||||
|
Map<String, TableDataWrapper> setIncludingProcedure = DesignTableDataManager.getAllDataSetIncludingProcedure(dataSet); |
||||||
|
notCalculatedSets.addAll(setIncludingProcedure.keySet()); |
||||||
|
allWrappers.putAll(setIncludingProcedure); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void startSearch(String searchText) { |
||||||
|
for (String notCalculatedSet : notCalculatedSets) { |
||||||
|
TableDataWrapper tableDataWrapper = allWrappers.get(notCalculatedSet); |
||||||
|
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { |
||||||
|
executorService.execute(new TableDataSearchTask(searchText, tableDataWrapper, new TableDataSearchCallBack(this))); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void stopSearch() { |
||||||
|
reset(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void completeSearch() { |
||||||
|
reset(); |
||||||
|
} |
||||||
|
|
||||||
|
private void reset() { |
||||||
|
matchSets.clear(); |
||||||
|
canExpandSets.clear(); |
||||||
|
calculatedSets.clear(); |
||||||
|
notCalculatedSets.addAll(allWrappers.keySet()); |
||||||
|
} |
||||||
|
|
||||||
|
public void afterSearch() { |
||||||
|
allWrappers.clear(); |
||||||
|
executorService.shutdownNow(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean nodeMatches(String dsName) { |
||||||
|
return matchSets.contains(dsName); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean nodeCanExpand(String dsName) { |
||||||
|
return canExpandSets.contains(dsName); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.searcher; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public enum TreeSearchStatus { |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索未开始 |
||||||
|
*/ |
||||||
|
SEARCH_NOT_BEGIN, |
||||||
|
/** |
||||||
|
* 搜索中 |
||||||
|
*/ |
||||||
|
SEARCHING, |
||||||
|
/** |
||||||
|
* 搜索已停止 |
||||||
|
*/ |
||||||
|
SEARCH_STOPPED, |
||||||
|
/** |
||||||
|
* 搜索已完成 |
||||||
|
*/ |
||||||
|
SEARCH_COMPLETED; |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.searcher; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 用于搜索RefreshableJTree数据的搜索器 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public interface TreeSearcher { |
||||||
|
|
||||||
|
/** |
||||||
|
* 开始搜索 |
||||||
|
* |
||||||
|
* @param text |
||||||
|
*/ |
||||||
|
void startSearch(String text); |
||||||
|
|
||||||
|
/** |
||||||
|
* 停止搜索 |
||||||
|
*/ |
||||||
|
void stopSearch(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索完成 |
||||||
|
*/ |
||||||
|
void completeSearch(); |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.time; |
||||||
|
|
||||||
|
import com.fr.concurrent.NamedThreadFactory; |
||||||
|
|
||||||
|
import java.util.concurrent.Executors; |
||||||
|
import java.util.concurrent.ScheduledExecutorService; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
/** |
||||||
|
* 搜索任务定时器 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataSearchTimer { |
||||||
|
|
||||||
|
/** |
||||||
|
* 定时器 |
||||||
|
*/ |
||||||
|
private ScheduledExecutorService scheduler; |
||||||
|
|
||||||
|
/** |
||||||
|
* 定时任务 |
||||||
|
*/ |
||||||
|
private TableDataSearchTimerTask timeTask; |
||||||
|
|
||||||
|
/** |
||||||
|
* 最大单次startSearch的时间 |
||||||
|
*/ |
||||||
|
public static final long MAX_SEARCH_TIME = 5000; |
||||||
|
|
||||||
|
private TableDataSearchTimer() { |
||||||
|
} |
||||||
|
|
||||||
|
private static class Holder { |
||||||
|
private static final TableDataSearchTimer INSTANCE = new TableDataSearchTimer(); |
||||||
|
} |
||||||
|
|
||||||
|
public static TableDataSearchTimer getInstance() { |
||||||
|
return Holder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
public void startClock() { |
||||||
|
this.scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory(TableDataSearchTimer.class)); |
||||||
|
this.timeTask = new TableDataSearchTimerTask(); |
||||||
|
scheduler.schedule(timeTask, MAX_SEARCH_TIME, TimeUnit.MILLISECONDS); |
||||||
|
} |
||||||
|
|
||||||
|
public void stopClock() { |
||||||
|
this.timeTask = null; |
||||||
|
if (this.scheduler != null) { |
||||||
|
this.scheduler.shutdownNow(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.time; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; |
||||||
|
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataSearchTimerTask implements Runnable { |
||||||
|
|
||||||
|
public TableDataSearchTimerTask() { |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
// 最大单次搜索时间过后,将结束搜索
|
||||||
|
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { |
||||||
|
TableDataTreeSearchManager.getInstance().completeSearch(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
package com.fr.design.data.datapane.management.search.view; |
||||||
|
|
||||||
|
import com.fr.design.data.datapane.TableDataTree; |
||||||
|
|
||||||
|
import javax.swing.JTree; |
||||||
|
import javax.swing.tree.DefaultTreeCellRenderer; |
||||||
|
import javax.swing.tree.TreeCellRenderer; |
||||||
|
import java.awt.Component; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TreeSearchRendererHelper { |
||||||
|
|
||||||
|
/** |
||||||
|
* 缓存下原来的渲染器 |
||||||
|
*/ |
||||||
|
private TreeCellRenderer originTreeCellRenderer; |
||||||
|
|
||||||
|
public TreeSearchRendererHelper() { |
||||||
|
} |
||||||
|
|
||||||
|
public TreeCellRenderer getOriginTreeCellRenderer() { |
||||||
|
return originTreeCellRenderer; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOriginTreeCellRenderer(TreeCellRenderer originTreeCellRenderer) { |
||||||
|
this.originTreeCellRenderer = originTreeCellRenderer; |
||||||
|
} |
||||||
|
|
||||||
|
public void replaceTreeRenderer(TableDataTree tableDataTree, String searchText) { |
||||||
|
tableDataTree.setCellRenderer(getNewTreeCellRenderer(searchText)); |
||||||
|
} |
||||||
|
|
||||||
|
public void save(TableDataTree tableDataTree) { |
||||||
|
if (getOriginTreeCellRenderer() == null) { |
||||||
|
setOriginTreeCellRenderer(tableDataTree.getTableDataTreeCellRenderer()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void restore(TableDataTree tableDataTree) { |
||||||
|
if (getOriginTreeCellRenderer() != null) { |
||||||
|
tableDataTree.setCellRenderer(getOriginTreeCellRenderer()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取新树渲染器,也就是搜索结果树的TreeCellRenderer,主要是为了文本高亮 |
||||||
|
* |
||||||
|
* @param searchText |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private TreeCellRenderer getNewTreeCellRenderer(String searchText) { |
||||||
|
return new DefaultTreeCellRenderer() { |
||||||
|
@Override |
||||||
|
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { |
||||||
|
Component treeCellRendererComponent = getOriginTreeCellRenderer().getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); |
||||||
|
if (treeCellRendererComponent instanceof DefaultTreeCellRenderer) { |
||||||
|
DefaultTreeCellRenderer defaultTreeCellRenderer = (DefaultTreeCellRenderer) treeCellRendererComponent; |
||||||
|
String text = defaultTreeCellRenderer.getText(); |
||||||
|
defaultTreeCellRenderer.setText(getHighlightText(text, searchText)); |
||||||
|
} |
||||||
|
return treeCellRendererComponent; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
private String getHighlightText(String text, String textToHighlight) { |
||||||
|
String highLightTemplate = "<font color=\"blue\">$1</font>"; |
||||||
|
if (textToHighlight.length() == 0) { |
||||||
|
return text; |
||||||
|
} |
||||||
|
try { |
||||||
|
text = text.replaceAll("(?i)(" + Pattern.quote(textToHighlight) + ")", highLightTemplate); |
||||||
|
} catch (Exception e) { |
||||||
|
return text; |
||||||
|
} |
||||||
|
text = "<html>" + text + "</html>"; |
||||||
|
return text; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
package com.fr.design.data.tabledata.paste; |
||||||
|
|
||||||
|
import com.fr.base.TableData; |
||||||
|
import com.fr.data.TableDataSource; |
||||||
|
import com.fr.design.DesignModelAdapter; |
||||||
|
import com.fr.design.data.DesignTableDataManager; |
||||||
|
import com.fr.design.data.datapane.TableDataTreePane; |
||||||
|
import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; |
||||||
|
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper; |
||||||
|
import com.fr.design.data.tabledata.wrapper.TableDataWrapper; |
||||||
|
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; |
||||||
|
import com.fr.form.ui.DictionaryContainer; |
||||||
|
import com.fr.form.ui.Widget; |
||||||
|
import com.fr.report.cell.tabledata.ElementUsedTableDataProvider; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据集跟随复制粘贴的工具类 |
||||||
|
* |
||||||
|
* @author Yvan |
||||||
|
*/ |
||||||
|
public class TableDataFollowingPasteUtils { |
||||||
|
|
||||||
|
/** |
||||||
|
* 粘贴所有Map中的tabledata到当前模板 |
||||||
|
* |
||||||
|
* @param tableDataWrapperMap |
||||||
|
*/ |
||||||
|
public static void paste(Map<String, TableData> tableDataWrapperMap) { |
||||||
|
if (tableDataWrapperMap == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
// 获取当前的TableDataTreePane
|
||||||
|
DesignModelAdapter<?, ?> currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter(); |
||||||
|
TableDataTreePane tableDataTreePane = (TableDataTreePane) TableDataTreePane.getInstance(currentModelAdapter); |
||||||
|
// 粘贴(添加)数据集
|
||||||
|
for (Map.Entry<String, TableData> dataWrapperEntry : tableDataWrapperMap.entrySet()) { |
||||||
|
String oldName = dataWrapperEntry.getKey(); |
||||||
|
// 处理名称重复情况
|
||||||
|
String dsName = tableDataTreePane.getNoRepeatedDsName4Paste(oldName); |
||||||
|
AbstractTableDataWrapper tableDataWrapper = new TemplateTableDataWrapper(dataWrapperEntry.getValue(), dsName); |
||||||
|
AbstractTableDataPane<?> tableDataPane = tableDataWrapper.creatTableDataPane(); |
||||||
|
tableDataTreePane.addDataPane(tableDataPane, dsName); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理 ElementUsedTableDataProvider,从中获取数据集名称 - 数据集Wrapper 的Map |
||||||
|
* |
||||||
|
* @param providers |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Map<String, TableData> transferProvider2TableDataMap(ElementUsedTableDataProvider... providers) { |
||||||
|
if (providers == null) { |
||||||
|
return new HashMap<>(); |
||||||
|
} |
||||||
|
// 获取当前的所有模板数据集
|
||||||
|
Map<String, TableDataWrapper> templateTableData = getCurrentTemplateTableDataWrapper(); |
||||||
|
Map<String, TableData> resultMap = new HashMap<>(); |
||||||
|
for (ElementUsedTableDataProvider tableDataProvider : providers) { |
||||||
|
Set<String> usedTableDataNames = tableDataProvider.getElementUsedTableDataNames(); |
||||||
|
for (String usedTableDataName : usedTableDataNames) { |
||||||
|
if (templateTableData.containsKey(usedTableDataName)) { |
||||||
|
resultMap.put(usedTableDataName, templateTableData.get(usedTableDataName).getTableData()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return resultMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 提取控件内使用的数据集,转化成Map返回 |
||||||
|
* |
||||||
|
* @param widgets |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Map<String, TableData> transferWidgetArray2TableDataMap(Widget... widgets) { |
||||||
|
if (widgets == null) { |
||||||
|
return new HashMap<>(); |
||||||
|
} |
||||||
|
// 获取当前的所有模板数据集
|
||||||
|
Map<String, TableDataWrapper> templateTableData = getCurrentTemplateTableDataWrapper(); |
||||||
|
Map<String, TableData> resultMap = new HashMap<>(); |
||||||
|
for (Widget widget : widgets) { |
||||||
|
if (widget instanceof DictionaryContainer) { |
||||||
|
Set<String> usedTableDataSets = ((DictionaryContainer) widget).getUsedTableDataSets(); |
||||||
|
for (String usedTableDataSet : usedTableDataSets) { |
||||||
|
if (templateTableData.containsKey(usedTableDataSet)) { |
||||||
|
resultMap.put(usedTableDataSet, templateTableData.get(usedTableDataSet).getTableData()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return resultMap; |
||||||
|
} |
||||||
|
|
||||||
|
private static Map<String, TableDataWrapper> getCurrentTemplateTableDataWrapper() { |
||||||
|
TableDataSource tableDataSource = DesignTableDataManager.getEditingTableDataSource(); |
||||||
|
List<Map<String, TableDataWrapper>> editingDataSet = DesignTableDataManager.getEditingDataSet(tableDataSource); |
||||||
|
return editingDataSet.get(0); |
||||||
|
} |
||||||
|
|
||||||
|
} |
After Width: | Height: | Size: 861 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 970 B |
Loading…
Reference in new issue