renekton
4 months ago
3 changed files with 19 additions and 337 deletions
@ -1,310 +0,0 @@ |
|||||||
package com.fr.design.gui.frpane; |
|
||||||
|
|
||||||
import com.fine.swing.ui.layout.Row; |
|
||||||
import com.fine.theme.utils.FineUIScale; |
|
||||||
import com.fine.theme.utils.FineUIStyle; |
|
||||||
import com.fine.theme.utils.FineUIUtils; |
|
||||||
import com.finebi.cbb.utils.StringUtils; |
|
||||||
import com.fr.design.gui.ibutton.UIButton; |
|
||||||
import com.fr.design.gui.ilable.UILabel; |
|
||||||
import com.fr.file.FILE; |
|
||||||
import com.fr.general.ComparatorUtils; |
|
||||||
|
|
||||||
import javax.swing.BorderFactory; |
|
||||||
import java.awt.Component; |
|
||||||
import java.awt.Dimension; |
|
||||||
import java.awt.Insets; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Renekton |
|
||||||
* @since 2024/08/08 |
|
||||||
* @param <T> |
|
||||||
*/ |
|
||||||
public class FineBreadcrumbPane <T> extends Row { |
|
||||||
|
|
||||||
private static final int SEP_HEIGHT = 20; |
|
||||||
|
|
||||||
private static final int BUTTON_HEIGHT = 20; |
|
||||||
|
|
||||||
private static final int MAX_BUTTON_WIDTH = FineUIScale.scale(150); |
|
||||||
|
|
||||||
private static final String DEFAULT_SEP = "/"; |
|
||||||
|
|
||||||
private BreadcrumbButton currentCrumb; |
|
||||||
|
|
||||||
private List<Component> breadcrumbs; |
|
||||||
|
|
||||||
private int componentWidth; |
|
||||||
|
|
||||||
private int hidingIndex; |
|
||||||
|
|
||||||
private String sep; |
|
||||||
|
|
||||||
public FineBreadcrumbPane() { |
|
||||||
this(DEFAULT_SEP); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 可传入分隔符号 |
|
||||||
*/ |
|
||||||
public FineBreadcrumbPane(String sep) { |
|
||||||
this.sep = sep; |
|
||||||
this.breadcrumbs = new ArrayList<>(); |
|
||||||
this.componentWidth = 0; |
|
||||||
this.hidingIndex = -1; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 初始化节点 |
|
||||||
* @param data 节点数据 |
|
||||||
* @param backListener 节点点击关联动作 |
|
||||||
*/ |
|
||||||
public void init(T data, final BreadcrumbBackListener<T> backListener) { |
|
||||||
if (currentCrumb != null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (data instanceof FILE) { |
|
||||||
FILE file = (FILE) data; |
|
||||||
List<FILE> files = new ArrayList<>(); |
|
||||||
while (file != null) { |
|
||||||
|
|
||||||
if (StringUtils.isEmpty(file.getName())) { |
|
||||||
break; |
|
||||||
} |
|
||||||
if (file.isDirectory()) { |
|
||||||
files.add(file); |
|
||||||
} |
|
||||||
file = file.getParent(); |
|
||||||
} |
|
||||||
int size = files.size(); |
|
||||||
currentCrumb = new BreadcrumbButton<>(getRootdata((T) files.get(size-1)), files.get(size-1)); |
|
||||||
add(currentCrumb); |
|
||||||
currentCrumb.setSelected(true); |
|
||||||
currentCrumb.setForeground(FineUIUtils.getUIColor("Button.breadcrumbSelectedForeground", "Button.breadcrumbSelectedForeground")); |
|
||||||
final int index = getComponentCount(); |
|
||||||
addBreadcrumbListener(currentCrumb, index, backListener); |
|
||||||
for (int i = size-2; i >= 0; i--) { |
|
||||||
addCrumb((T) files.get(i), backListener); |
|
||||||
} |
|
||||||
} else if (data instanceof String) { |
|
||||||
currentCrumb = new BreadcrumbButton<>(getRootdata(data), data); |
|
||||||
add(currentCrumb); |
|
||||||
final int index = getComponentCount(); |
|
||||||
addBreadcrumbListener(currentCrumb, index, backListener); |
|
||||||
} |
|
||||||
repaint(); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根节点重置 |
|
||||||
* @param data 节点内容 |
|
||||||
* @param backListener |
|
||||||
*/ |
|
||||||
public void reset(T data, final BreadcrumbBackListener<T> backListener) { |
|
||||||
if (currentCrumb != null && ComparatorUtils.equals(data, currentCrumb.getContent())) { |
|
||||||
return; |
|
||||||
} |
|
||||||
clear(); |
|
||||||
init(data, backListener); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 添加节点 |
|
||||||
* @param data |
|
||||||
* @param backListener |
|
||||||
*/ |
|
||||||
public void addCrumb(final T data, final BreadcrumbBackListener<T> backListener) { |
|
||||||
|
|
||||||
if (currentCrumb != null) { |
|
||||||
currentCrumb.setSelected(false); |
|
||||||
currentCrumb.setForeground(FineUIUtils.getUIColor("Button.breadcrumbForeground", "Button.breadcrumbForeground")); |
|
||||||
add(createSeparator()); |
|
||||||
} |
|
||||||
final BreadcrumbButton breadcrumb = createBreadcrumb(data); |
|
||||||
int currentWidth = componentWidth + breadcrumb.getPreferredSize().width; |
|
||||||
if (this.getVisibleRect().width != 0 && currentWidth > this.getVisibleRect().width) { |
|
||||||
// 大于可见宽度,隐藏前面的目录
|
|
||||||
for (int i = hidingIndex+1; i < breadcrumbs.size(); i++) { |
|
||||||
int width = breadcrumbs.get(i).getPreferredSize().width; |
|
||||||
breadcrumbs.get(i).setVisible(false); |
|
||||||
hidingIndex = i; |
|
||||||
currentWidth -= width; |
|
||||||
if (currentWidth < this.getVisibleRect().width) { |
|
||||||
if (breadcrumbs.get(i+1) instanceof UILabel) { |
|
||||||
breadcrumbs.get(i+1).setVisible(false); |
|
||||||
hidingIndex = i+1; |
|
||||||
componentWidth = currentWidth - breadcrumb.getPreferredSize().width - breadcrumbs.get(i+1).getPreferredSize().width; |
|
||||||
} else { |
|
||||||
componentWidth = currentWidth - breadcrumb.getPreferredSize().width; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
add(breadcrumb); |
|
||||||
currentCrumb = breadcrumb; |
|
||||||
final int index = getComponentCount(); |
|
||||||
addBreadcrumbListener(breadcrumb, index, backListener); |
|
||||||
} |
|
||||||
|
|
||||||
private void removeTailCrumbs(int from) { |
|
||||||
Component[] components = getComponents(); |
|
||||||
for (int i = from; i < components.length; i++) { |
|
||||||
remove(components[i]); |
|
||||||
} |
|
||||||
currentCrumb = (BreadcrumbButton) components[from-1]; |
|
||||||
revalidate(); |
|
||||||
repaint(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void remove(Component comp) { |
|
||||||
componentWidth -= comp.getPreferredSize().getWidth(); |
|
||||||
breadcrumbs.remove(comp); |
|
||||||
super.remove(comp); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Component add(Component comp) { |
|
||||||
componentWidth += comp.getPreferredSize().getWidth(); |
|
||||||
breadcrumbs.add(comp); |
|
||||||
return super.add(comp); |
|
||||||
} |
|
||||||
|
|
||||||
public void clear() { |
|
||||||
|
|
||||||
removeAll(); |
|
||||||
currentCrumb = null; |
|
||||||
componentWidth = 0; |
|
||||||
breadcrumbs.clear(); |
|
||||||
} |
|
||||||
|
|
||||||
protected Component createSeparator() { |
|
||||||
UILabel separator = new UILabel(sep); |
|
||||||
separator.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); |
|
||||||
separator.setPreferredSize(new Dimension(separator.getPreferredSize().width, FineUIScale.scale(SEP_HEIGHT))); |
|
||||||
|
|
||||||
return separator; |
|
||||||
} |
|
||||||
|
|
||||||
protected BreadcrumbButton createBreadcrumb(T content) { |
|
||||||
BreadcrumbButton button = new BreadcrumbButton(getdata(content), content); |
|
||||||
button.setPreferredSize(new Dimension(Math.min(button.getPreferredSize().width, MAX_BUTTON_WIDTH), FineUIScale.scale(BUTTON_HEIGHT))); |
|
||||||
button.setSelected(true); |
|
||||||
button.setForeground(FineUIUtils.getUIColor("Button.breadcrumbSelectedForeground", "Button.breadcrumbSelectedForeground")); |
|
||||||
return button; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 节点点击事件 |
|
||||||
* @param breadcrumb |
|
||||||
* @param index |
|
||||||
* @param backListener |
|
||||||
*/ |
|
||||||
private void addBreadcrumbListener(BreadcrumbButton breadcrumb, int index, BreadcrumbBackListener backListener) { |
|
||||||
breadcrumb.addActionListener(e -> { |
|
||||||
removeTailCrumbs(index); |
|
||||||
// 存在隐藏目录,弹出部分隐藏目录
|
|
||||||
if (hidingIndex >= 0) { |
|
||||||
int currentWidth = componentWidth; |
|
||||||
for (int i = hidingIndex; i >= 0; i--) { |
|
||||||
currentWidth += breadcrumbs.get(i).getPreferredSize().width; |
|
||||||
if (currentWidth <= this.getVisibleRect().width) { |
|
||||||
breadcrumbs.get(i).setVisible(true); |
|
||||||
} else { |
|
||||||
hidingIndex = i; |
|
||||||
if (breadcrumbs.get(i+1) instanceof UILabel) { |
|
||||||
currentWidth -= breadcrumbs.get(i+1).getPreferredSize().width; |
|
||||||
breadcrumbs.get(i+1).setVisible(false); |
|
||||||
hidingIndex = i+1; |
|
||||||
} |
|
||||||
componentWidth = currentWidth - breadcrumbs.get(i).getPreferredSize().width; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
if (currentWidth <= this.getVisibleRect().width) { |
|
||||||
hidingIndex = -1; |
|
||||||
componentWidth = currentWidth; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
breadcrumb.setSelected(true); |
|
||||||
breadcrumb.setForeground(FineUIUtils.getUIColor("Button.breadcrumbSelectedForeground", "Button.breadcrumbSelectedForeground")); |
|
||||||
if (breadcrumb != currentCrumb) { |
|
||||||
currentCrumb = breadcrumb; |
|
||||||
} |
|
||||||
if (backListener != null) { |
|
||||||
backListener.onBreadcrumbBack(breadcrumb.getContent()); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
private String getRootdata(T data) { |
|
||||||
if (data instanceof String) { |
|
||||||
return (String) data; |
|
||||||
} else if (data instanceof FILE){ |
|
||||||
FILE file = (FILE) data; |
|
||||||
if (file.getPath().endsWith("/") || file.getPath().endsWith("\\")) { |
|
||||||
return file.getPath().replaceAll("[/\\\\]+", ""); |
|
||||||
} else if (file.getPath().contains("/") || file.getPath().contains("\\")) { |
|
||||||
return file.getPath().replaceAll("[/\\\\]+", sep); |
|
||||||
} |
|
||||||
return ((FILE)data).getPath(); |
|
||||||
} |
|
||||||
return (String) data; |
|
||||||
} |
|
||||||
|
|
||||||
private String getdata(T data) { |
|
||||||
if (data instanceof String) { |
|
||||||
return (String) data; |
|
||||||
} else if (data instanceof FILE){ |
|
||||||
return ((FILE)data).getName(); |
|
||||||
} |
|
||||||
return (String) data; |
|
||||||
} |
|
||||||
|
|
||||||
public static class BreadcrumbButton <T> extends UIButton { |
|
||||||
|
|
||||||
private T content; |
|
||||||
|
|
||||||
public BreadcrumbButton(String data, T content) { |
|
||||||
super(data); |
|
||||||
BreadcrumbButton.this.content = content; |
|
||||||
setMargin(new Insets(0, 0, 0, 0)); |
|
||||||
setBorder(BorderFactory.createEmptyBorder()); |
|
||||||
FineUIStyle.setStyle(BreadcrumbButton.this, FineUIStyle.BREADCRUMB_BUTTON); |
|
||||||
setBorderPainted(false); |
|
||||||
setOpaque(false); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Insets getMargin() { |
|
||||||
Insets insets = super.getMargin(); |
|
||||||
if (insets != null) { |
|
||||||
insets.set(0, 0, 0, 0); |
|
||||||
} |
|
||||||
return insets; |
|
||||||
} |
|
||||||
|
|
||||||
protected T getContent() { |
|
||||||
return content; |
|
||||||
} |
|
||||||
|
|
||||||
protected void setContent(T content) { |
|
||||||
this.content = content; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 节点点击关联动作监听器 |
|
||||||
* @param <T> |
|
||||||
*/ |
|
||||||
public interface BreadcrumbBackListener <T> { |
|
||||||
void onBreadcrumbBack(T data); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
Loading…
Reference in new issue