插件开发工具库,推荐依赖该工具库。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

188 lines
7.0 KiB

package com.fanruan.api.design.work;
import com.fanruan.api.design.DesignKit;
import com.fanruan.api.design.ui.component.pane.UITextPane;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.util.AssistKit;
import com.fr.base.BaseFormula;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.formula.FormulaFactory;
import com.fr.design.formula.UIFormula;
import com.fr.report.cell.cellattr.core.RichText;
import com.fr.report.cell.cellattr.core.RichTextConverter;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.StyledDocument;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* @author richie
* @version 10.0
* Created by richie on 2019/10/25
* 富文本编辑器容器
*/
public class RichTextEditingPane extends UITextPane {
private static final int WRAPPER_LEN = 3;
private static final int PREFIX_LEN = 2;
private boolean updating = false;
/**
* 构造函数
*/
public RichTextEditingPane() {
//双击选取公式监听器
//往前回溯, 寻找${, 如果发现先找到了}, 说明不在公式内部, 直接return.
//有可能当前字符刚好处于{后面, 所以要-1
//发现大括号了, 再找$
//再往后找"}"
//发现左大括号了, 肯定异常
//要把后缀包进去, 所以+1
// 取得选择文本的起始位置和结束位置
//公式起点
//公式终点
//找到公式的起点与终点了, 下面就是选中, 并弹出编辑窗口
//缓存第一个字符的样式, 用于给新公式设置样式
//弹出公式编辑窗口
MouseListener doubleClickFormulaListener = new MouseAdapter() {
private int findFormulaStart(int start, StyledDocument doc) throws BadLocationException {
//往前回溯, 寻找${, 如果发现先找到了}, 说明不在公式内部, 直接return.
//有可能当前字符刚好处于{后面, 所以要-1
for (int i = start - 1; i >= 0; i--) {
String text = doc.getText(i, 1);
if (AssistKit.equals(text, RichText.SUFFIX)) {
return -1;
}
//发现大括号了, 再找$
if (AssistKit.equals(text, RichText.PREFIX)) {
if (i - 1 >= 0 && AssistKit.equals(doc.getText(i - 1, 1), RichText.FLAG)) {
return i - 1;
}
}
}
return -1;
}
private int findFormulaEnd(int start, StyledDocument doc) throws BadLocationException {
//再往后找"}"
int total = doc.getLength();
for (int j = start; j < total; j++) {
String text = doc.getText(j, 1);
//发现左大括号了, 肯定异常
if (AssistKit.equals(text, RichText.PREFIX)) {
return -1;
}
if (AssistKit.equals(text, RichText.SUFFIX)) {
//要把后缀包进去, 所以+1
return j + 1;
}
}
return -1;
}
private void popUpFormulaEditPane(final String formulaContent, final int formulaStart,
final AttributeSet attrs) {
final UIFormula formulaPane = FormulaFactory.createFormulaPane();
formulaPane.populate(BaseFormula.createFormulaBuilder().build(formulaContent));
formulaPane.showLargeWindow(DesignKit.getDesignerFrame(), new DialogActionAdapter() {
@Override
public void doOk() {
StyledDocument doc = (StyledDocument) RichTextEditingPane.this.getDocument();
BaseFormula fm = formulaPane.update();
String content = RichTextConverter.asFormula(fm.getContent());
try {
doc.remove(formulaStart, formulaContent.length() + WRAPPER_LEN);
doc.insertString(formulaStart, content, attrs);
} catch (BadLocationException e) {
LogKit.error(e.getMessage(), e);
}
}
}).setVisible(true);
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.getClickCount() == 2) {
// 取得选择文本的起始位置和结束位置
int start = RichTextEditingPane.this.getSelectionStart();
if (start <= 0) {
return;
}
StyledDocument doc = (StyledDocument) RichTextEditingPane.this.getDocument();
try {
//公式起点
final int formulaStart = findFormulaStart(start, doc);
if (formulaStart == -1) {
return;
}
//公式终点
int formulaEnd = findFormulaEnd(start, doc);
if (formulaEnd == -1) {
return;
}
//找到公式的起点与终点了, 下面就是选中, 并弹出编辑窗口
RichTextEditingPane.this.select(formulaStart, formulaEnd);
//缓存第一个字符的样式, 用于给新公式设置样式
Element ele = doc.getCharacterElement(formulaStart);
final AttributeSet attrs = ele.getAttributes();
final String formulaContent = doc.getText(formulaStart + PREFIX_LEN, formulaEnd - formulaStart - WRAPPER_LEN);
//弹出公式编辑窗口
popUpFormulaEditPane(formulaContent, formulaStart, attrs);
} catch (BadLocationException e1) {
LogKit.error(e1.getMessage());
}
}
}
};
this.addMouseListener(doubleClickFormulaListener);
}
/**
* 是否有其他进程正在更新编辑区域
*
* @return 是否有其他进程正在更新编辑区域
*/
public boolean isUpdating() {
return updating;
}
/**
* 设置更新状态
*
* @param updating 是否正在更新
*/
public void setUpdating(boolean updating) {
this.updating = updating;
}
/**
* 开始更新
*/
public void startUpdating() {
this.updating = true;
}
/**
* 结束更新
*/
public void finishUpdating() {
this.updating = false;
}
}