renekton
3 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