forked from fanruan/finekit
richie
5 years ago
12 changed files with 1642 additions and 0 deletions
@ -0,0 +1,231 @@
|
||||
package com.fanruan.api.design.ui.component; |
||||
|
||||
import com.fanruan.api.design.macro.UIConstants; |
||||
import com.fanruan.api.design.util.GUICoreKit; |
||||
import com.fanruan.api.util.AssistKit; |
||||
import com.fanruan.api.util.GeneralKit; |
||||
import com.fr.design.event.GlobalNameListener; |
||||
import com.fr.design.event.GlobalNameObserver; |
||||
import com.fr.design.event.UIObserver; |
||||
import com.fr.design.event.UIObserverListener; |
||||
import com.fr.design.gui.ibutton.UIButtonUI; |
||||
import com.fr.design.gui.ipoppane.PopupHider; |
||||
import com.fr.design.style.color.ColorControlWindow; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.event.ChangeEvent; |
||||
import javax.swing.event.ChangeListener; |
||||
import javax.swing.event.EventListenerList; |
||||
import java.awt.*; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
*/ |
||||
public class UIColorButton extends UIButton implements PopupHider, UIObserver, GlobalNameObserver { |
||||
|
||||
private static final int SIZE = 16; |
||||
private static final int SIZE_2 = 2; |
||||
private static final int SIZE_4 = 4; |
||||
private static final int SIZE_6 = 6; |
||||
private static final int POPUP_MENU_SHIFT = -70; |
||||
private Color color = Color.BLACK; |
||||
private ColorControlWindow popupWin; |
||||
private EventListenerList colorChangeListenerList = new EventListenerList(); |
||||
private boolean isEventBanned = false; |
||||
private String colorButtonName = ""; |
||||
private UIObserverListener uiObserverListener; |
||||
private GlobalNameListener globalNameListener = null; |
||||
|
||||
public UIColorButton() { |
||||
this(UIConstants.FONT_ICON); |
||||
} |
||||
|
||||
public UIColorButton(Icon icon) { |
||||
super(icon); |
||||
setUI(getButtonUI()); |
||||
addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
showPopupMenu(); |
||||
} |
||||
}); |
||||
iniListener(); |
||||
} |
||||
|
||||
private void iniListener() { |
||||
if (shouldResponseChangeListener()) { |
||||
this.addColorChangeListener(new ChangeListener() { |
||||
@Override |
||||
public void stateChanged(ChangeEvent e) { |
||||
if (uiObserverListener == null) { |
||||
return; |
||||
} |
||||
if (globalNameListener != null && shouldResponseNameListener()) { |
||||
globalNameListener.setGlobalName(colorButtonName); |
||||
} |
||||
uiObserverListener.doChange(); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
private UIButtonUI getButtonUI() { |
||||
return new UIButtonUI() { |
||||
@Override |
||||
protected void paintIcon(Graphics g, JComponent c) { |
||||
super.paintIcon(g, c); |
||||
AbstractButton b = (AbstractButton) c; |
||||
ButtonModel model = b.getModel(); |
||||
if (model.isEnabled()) { |
||||
g.setColor(UIColorButton.this.getColor()); |
||||
} else { |
||||
g.setColor(new Color(GeneralKit.filterRGB(UIColorButton.this.getColor().getRGB(), 50))); |
||||
} |
||||
g.fillRect((b.getWidth() - SIZE) / SIZE_2, b.getHeight() - SIZE_6, SIZE, SIZE_4); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public void setEventBanned(boolean isEventBanned) { |
||||
this.isEventBanned = isEventBanned; |
||||
} |
||||
|
||||
public void setGlobalName(String name) { |
||||
colorButtonName = name; |
||||
} |
||||
|
||||
public Color getColor() { |
||||
return color; |
||||
} |
||||
|
||||
public void setColor(Color color) { |
||||
if (AssistKit.equals(this.color, color)) { |
||||
return; |
||||
} |
||||
|
||||
this.color = color; |
||||
hidePopupMenu(); |
||||
fireColorStateChanged(); |
||||
} |
||||
|
||||
private void showPopupMenu() { |
||||
if (isEventBanned) { |
||||
return; |
||||
} |
||||
|
||||
if (popupWin != null && popupWin.isVisible()) { |
||||
hidePopupMenu(); |
||||
return; |
||||
} |
||||
|
||||
if (!this.isEnabled()) { |
||||
return; |
||||
} |
||||
|
||||
popupWin = this.getColorControlWindow(); |
||||
|
||||
GUICoreKit.showPopupMenu(popupWin, this, POPUP_MENU_SHIFT, this.getSize().height); |
||||
} |
||||
|
||||
/** |
||||
* 隐藏popupmenu |
||||
*/ |
||||
public void hidePopupMenu() { |
||||
if (popupWin != null) { |
||||
popupWin.setVisible(false); |
||||
repaint(); |
||||
} |
||||
|
||||
popupWin = null; |
||||
} |
||||
|
||||
private ColorControlWindow getColorControlWindow() { |
||||
if (this.popupWin == null) { |
||||
this.popupWin = new ColorControlWindow(UIColorButton.this) { |
||||
@Override |
||||
protected void colorChanged() { |
||||
UIColorButton.this.setColor(this.getColor()); |
||||
} |
||||
|
||||
}; |
||||
} |
||||
return popupWin; |
||||
} |
||||
|
||||
/** |
||||
* 添加监听 |
||||
* |
||||
* @param changeListener 监听列表 |
||||
*/ |
||||
public void addColorChangeListener(ChangeListener changeListener) { |
||||
colorChangeListenerList.add(ChangeListener.class, changeListener); |
||||
} |
||||
|
||||
/** |
||||
* 移除监听 |
||||
* Removes an old ColorChangeListener. |
||||
* |
||||
* @param changeListener 监听列表 |
||||
*/ |
||||
public void removeColorChangeListener(ChangeListener changeListener) { |
||||
colorChangeListenerList.remove(ChangeListener.class, changeListener); |
||||
} |
||||
|
||||
/** |
||||
* 颜色状态改变 |
||||
*/ |
||||
public void fireColorStateChanged() { |
||||
Object[] listeners = colorChangeListenerList.getListenerList(); |
||||
ChangeEvent e = null; |
||||
|
||||
for (int i = listeners.length - 2; i >= 0; i -= 2) { |
||||
if (listeners[i] == ChangeListener.class) { |
||||
if (e == null) { |
||||
e = new ChangeEvent(this); |
||||
} |
||||
((ChangeListener) listeners[i + 1]).stateChanged(e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 注册状态改变监听 |
||||
* |
||||
* @param listener 观察者监听事件 |
||||
*/ |
||||
public void registerChangeListener(UIObserverListener listener) { |
||||
uiObserverListener = listener; |
||||
} |
||||
|
||||
/** |
||||
* 是否需要响应监听 |
||||
* |
||||
* @return 是否响应 |
||||
*/ |
||||
public boolean shouldResponseChangeListener() { |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 注册监听 |
||||
* |
||||
* @param listener 观察者监听事件 |
||||
*/ |
||||
public void registerNameListener(GlobalNameListener listener) { |
||||
globalNameListener = listener; |
||||
} |
||||
|
||||
/** |
||||
* 是否需要相应 |
||||
* |
||||
* @return 是否响应 |
||||
*/ |
||||
public boolean shouldResponseNameListener() { |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,245 @@
|
||||
package com.fanruan.api.design.ui.component; |
||||
|
||||
import com.fanruan.api.design.macro.UIConstants; |
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.design.event.GlobalNameListener; |
||||
import com.fr.design.event.GlobalNameObserver; |
||||
import com.fr.design.gui.ibutton.UIButtonUI; |
||||
import com.fr.design.roleAuthority.ReportAndFSManagePane; |
||||
import com.fr.design.utils.gui.GUIPaintUtils; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.event.ChangeEvent; |
||||
import javax.swing.event.ChangeListener; |
||||
import java.awt.*; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
import java.awt.event.MouseListener; |
||||
import java.awt.geom.RoundRectangle2D; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
* 可切换状态的按钮 |
||||
*/ |
||||
public class UIToggleButton extends UIButton implements GlobalNameObserver { |
||||
|
||||
private static final int ICON_COUNT = 2; |
||||
private boolean selected; |
||||
private boolean eventBanned = false; |
||||
private String toggleButtonName = StringKit.EMPTY; |
||||
private GlobalNameListener globalNameListener = null; |
||||
private Icon[] icons; |
||||
|
||||
public UIToggleButton() { |
||||
this(StringKit.EMPTY); |
||||
} |
||||
|
||||
public UIToggleButton(Icon image) { |
||||
this(StringKit.EMPTY, image); |
||||
} |
||||
|
||||
public UIToggleButton(String text) { |
||||
this(text, null); |
||||
} |
||||
|
||||
public UIToggleButton(String text, Icon image) { |
||||
super(text, image); |
||||
addMouseListener(getMouseListener()); |
||||
} |
||||
|
||||
/** |
||||
* 需要反白的按钮接口(组合按钮情况-UIButtonGroup) |
||||
* support icons[normalIcon, selectedIcon] |
||||
* |
||||
* @param icons 图标 |
||||
*/ |
||||
public UIToggleButton(Icon[] icons) { |
||||
super(icons[0], null, null); |
||||
setExtraPainted(true); |
||||
this.icons = icons; |
||||
addActionListener(new AbstractAction() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
if (!UIToggleButton.super.isSelected()) { |
||||
UIToggleButton.super.setSelected(!UIToggleButton.super.isSelected()); |
||||
} |
||||
} |
||||
}); |
||||
addMouseListener(getMouseListener()); |
||||
} |
||||
|
||||
/** |
||||
* 需要反白的按钮接口(单个按钮情况)-再次点击取消选中状态 |
||||
* |
||||
* @param icons 图标 |
||||
* @param needRelease 是否能够点击之后释放 |
||||
*/ |
||||
public UIToggleButton(Icon[] icons, boolean needRelease) { |
||||
super(icons[0], null, null); |
||||
setBorderPainted(true); |
||||
setExtraPainted(true); |
||||
this.icons = icons; |
||||
if (!needRelease) { |
||||
addActionListener(new AbstractAction() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
if (UIToggleButton.super.isSelected()) { |
||||
UIToggleButton.super.setSelected(false); |
||||
} else { |
||||
UIToggleButton.super.setSelected(true); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
addMouseListener(getMouseListener()); |
||||
} |
||||
|
||||
@Override |
||||
public final void setGlobalName(String name) { |
||||
toggleButtonName = name; |
||||
} |
||||
|
||||
@Override |
||||
public final boolean isSelected() { |
||||
return selected; |
||||
} |
||||
|
||||
@Override |
||||
public final void setSelected(boolean isSelected) { |
||||
super.setSelected(isSelected); |
||||
if (this.selected != isSelected) { |
||||
this.selected = isSelected; |
||||
refresh(isSelected); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected void initListener() { |
||||
if (shouldResponseChangeListener()) { |
||||
this.addChangeListener(new ChangeListener() { |
||||
@Override |
||||
public void stateChanged(ChangeEvent e) { |
||||
if (uiObserverListener == null) { |
||||
return; |
||||
} |
||||
if (globalNameListener != null && shouldResponseNameListener()) { |
||||
globalNameListener.setGlobalName(toggleButtonName); |
||||
} |
||||
uiObserverListener.doChange(); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
public final void setSelectedWithFireListener(boolean isSelected) { |
||||
if (this.selected != isSelected) { |
||||
this.selected = isSelected; |
||||
fireSelectedChanged(); |
||||
refresh(isSelected); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void refresh(final boolean isSelected) { |
||||
SwingUtilities.invokeLater(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
Icon[] icons = UIToggleButton.this.icons; |
||||
if (icons != null && icons.length == ICON_COUNT) { |
||||
if (isSelected) { |
||||
UIToggleButton.this.setIcon(icons[1]); |
||||
} else { |
||||
UIToggleButton.this.setIcon(icons[0]); |
||||
} |
||||
} |
||||
UIToggleButton.this.repaint(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
protected MouseListener getMouseListener() { |
||||
return new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
if (isEnabled() && !eventBanned) { |
||||
setSelectedWithFireListener(!isSelected()); |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public void setEventBanned(boolean ban) { |
||||
this.eventBanned = ban; |
||||
} |
||||
|
||||
@Override |
||||
protected void fireStateChanged() { |
||||
|
||||
} |
||||
|
||||
|
||||
protected final void fireSelectedChanged() { |
||||
Object[] listeners = listenerList.getListenerList(); |
||||
|
||||
for (int i = listeners.length - 2; i >= 0; i -= 2) { |
||||
if (listeners[i] == ChangeListener.class) { |
||||
((ChangeListener) listeners[i + 1]).stateChanged(new ChangeEvent(this)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected final void paintBorder(Graphics g) { |
||||
if (!isBorderPainted()) { |
||||
return; |
||||
} |
||||
boolean isBorderPainted = isBorderPaintedOnlyWhenPressed && (getModel().isPressed() || selected); |
||||
if (isBorderPainted || !isBorderPaintedOnlyWhenPressed) { |
||||
if (ui instanceof UIButtonUI) { |
||||
drawRoleName((Graphics2D) g); |
||||
} else { |
||||
super.paintBorder(g); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void drawRoleName(Graphics2D g) { |
||||
String roleName = ReportAndFSManagePane.getInstance().getRoleTree().getSelectedRoleName(); |
||||
GUIPaintUtils.drawBorder(g, 0, 0, getWidth(), getHeight(), isRoundBorder(), getRectDirection(), isDoneAuthorityEdited(roleName)); |
||||
} |
||||
|
||||
@Override |
||||
protected final void paintOtherBorder(Graphics g) { |
||||
Graphics2D g2d = (Graphics2D) g; |
||||
g2d.setStroke(UIConstants.BS); |
||||
Shape shape = new RoundRectangle2D.Float(0.5f, 0.5f, getWidth() - 1F, getHeight() - 1F, UIConstants.ARC, UIConstants.ARC); |
||||
g2d.setColor(UIConstants.LINE_COLOR); |
||||
g2d.draw(shape); |
||||
} |
||||
|
||||
/** |
||||
* 组件是否需要响应添加的观察者事件 |
||||
* |
||||
* @return 如果需要响应观察者事件则返回true,否则返回false |
||||
*/ |
||||
@Override |
||||
public final boolean shouldResponseChangeListener() { |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @param listener 观察者监听事件 |
||||
*/ |
||||
@Override |
||||
public final void registerNameListener(GlobalNameListener listener) { |
||||
globalNameListener = listener; |
||||
} |
||||
|
||||
public final boolean shouldResponseNameListener() { |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,29 @@
|
||||
package com.fanruan.api.design.ui.component.pane; |
||||
|
||||
import javax.swing.text.StyledDocument; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
* 用于显示文本的容器(可显示富文本) |
||||
* @see javax.swing.JTextPane |
||||
*/ |
||||
public class UITextPane extends com.fr.design.gui.frpane.UITextPane { |
||||
|
||||
/** |
||||
* 构造容器 |
||||
*/ |
||||
public UITextPane() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* 根据特定的样式构造容器 |
||||
* |
||||
* @param document 样式 |
||||
*/ |
||||
public UITextPane(StyledDocument document) { |
||||
super(document); |
||||
} |
||||
} |
@ -0,0 +1,188 @@
|
||||
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; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,612 @@
|
||||
package com.fanruan.api.design.work; |
||||
|
||||
import com.fanruan.api.design.DesignKit; |
||||
import com.fanruan.api.design.ui.component.UIButton; |
||||
import com.fanruan.api.design.ui.component.UIComboBox; |
||||
import com.fanruan.api.design.ui.component.UIToggleButton; |
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fanruan.api.util.GeneralKit; |
||||
import com.fanruan.api.util.IOKit; |
||||
import com.fr.base.BaseFormula; |
||||
import com.fr.design.dialog.BasicPane; |
||||
import com.fr.design.dialog.DialogActionAdapter; |
||||
import com.fr.design.formula.FormulaFactory; |
||||
import com.fr.design.formula.UIFormula; |
||||
import com.fr.design.gui.style.FRFontPane; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.report.RichTextEditingPane; |
||||
import com.fr.design.report.RichTextPane; |
||||
import com.fr.design.style.color.UIToolbarColorButton; |
||||
import com.fr.general.FRFont; |
||||
import com.fr.report.cell.cellattr.core.RichTextConverter; |
||||
import com.fr.stable.Constants; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.event.CaretEvent; |
||||
import javax.swing.event.CaretListener; |
||||
import javax.swing.event.ChangeEvent; |
||||
import javax.swing.event.ChangeListener; |
||||
import javax.swing.event.DocumentEvent; |
||||
import javax.swing.event.DocumentListener; |
||||
import javax.swing.text.AttributeSet; |
||||
import javax.swing.text.BadLocationException; |
||||
import javax.swing.text.Element; |
||||
import javax.swing.text.MutableAttributeSet; |
||||
import javax.swing.text.SimpleAttributeSet; |
||||
import javax.swing.text.StyleConstants; |
||||
import javax.swing.text.StyledDocument; |
||||
import java.awt.*; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
import java.awt.event.ItemEvent; |
||||
import java.awt.event.ItemListener; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
import java.awt.event.MouseListener; |
||||
import java.math.BigDecimal; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
* 富文本编辑器工具栏 |
||||
*/ |
||||
public class RichTextToolBar extends BasicPane { |
||||
|
||||
private static final Dimension BUTTON_SIZE = new Dimension(24, 20); |
||||
|
||||
private static final int NOT_INITIALIZED = -1; |
||||
private static final int UPDATING = -2; |
||||
|
||||
private int inputStart = NOT_INITIALIZED; |
||||
|
||||
private UIComboBox<String> fontNameComboBox; |
||||
private UIComboBox<Integer> fontSizeComboBox; |
||||
private UIToggleButton bold; |
||||
private UIToggleButton italic; |
||||
private UIToggleButton underline; |
||||
|
||||
private UIToolbarColorButton colorSelectPane; |
||||
private UIToggleButton superPane; |
||||
private UIToggleButton subPane; |
||||
private UIToggleButton formulaPane; |
||||
|
||||
//外部传进来的
|
||||
private RichTextEditingPane textPane; |
||||
|
||||
public RichTextToolBar() { |
||||
this.initComponents(); |
||||
} |
||||
|
||||
public RichTextToolBar(RichTextEditingPane textPane) { |
||||
this.textPane = textPane; |
||||
|
||||
this.initComponents(); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return DesignKit.i18nText("Fine-Design_Form_Font"); |
||||
} |
||||
|
||||
protected void initComponents() { |
||||
//初始化并设置所有按钮样式
|
||||
initAllButton(); |
||||
//添加到工具栏
|
||||
addToToolBar(); |
||||
} |
||||
|
||||
private void initAllButton() { |
||||
fontNameComboBox = new UIComboBox<>(GeneralKit.getAvailableFontFamilyNames()); |
||||
fontNameComboBox.setPreferredSize(new Dimension(144, 20)); |
||||
fontSizeComboBox = new UIComboBox<>(FRFontPane.getFontSizes()); |
||||
colorSelectPane = new UIToolbarColorButton(IOKit.readIcon("/com/fr/design/images/gui/color/foreground.png")); |
||||
colorSelectPane.set4Toolbar(); |
||||
|
||||
bold = new UIToggleButton(IOKit.readIcon("/com/fr/design/images/m_format/cellstyle/bold.png")); |
||||
italic = new UIToggleButton(IOKit.readIcon("/com/fr/design/images/m_format/cellstyle/italic.png")); |
||||
underline = new UIToggleButton(IOKit.readIcon("/com/fr/design/images/m_format/cellstyle/underline.png")); |
||||
superPane = new UIToggleButton(IOKit.readIcon("/com/fr/design/images/m_format/cellstyle/sup.png")); |
||||
subPane = new UIToggleButton(IOKit.readIcon("/com/fr/design/images/m_format/cellstyle/sub.png")); |
||||
formulaPane = new UIToggleButton(IOKit.readIcon("/com/fr/design/images/m_insert/formula.png")); |
||||
|
||||
//名字
|
||||
initAllNames(); |
||||
//悬浮提示
|
||||
setToolTips(); |
||||
//样式
|
||||
setAllButtonStyle(); |
||||
//绑定监听器
|
||||
bindListener(); |
||||
} |
||||
|
||||
private void setAllButtonStyle() { |
||||
setButtonStyle(bold); |
||||
setButtonStyle(italic); |
||||
setButtonStyle(underline); |
||||
setButtonStyle(subPane); |
||||
setButtonStyle(superPane); |
||||
setButtonStyle(formulaPane); |
||||
} |
||||
|
||||
private void setButtonStyle(UIButton button) { |
||||
button.setNormalPainted(false); |
||||
button.setBackground(null); |
||||
button.setOpaque(false); |
||||
button.setPreferredSize(BUTTON_SIZE); |
||||
button.setBorderPaintedOnlyWhenPressed(true); |
||||
} |
||||
|
||||
private void addToToolBar() { |
||||
this.setLayout(new FlowLayout(FlowLayout.LEFT)); |
||||
|
||||
this.add(fontNameComboBox); |
||||
this.add(fontSizeComboBox); |
||||
this.add(bold); |
||||
this.add(italic); |
||||
this.add(underline); |
||||
this.add(colorSelectPane); |
||||
this.add(superPane); |
||||
this.add(subPane); |
||||
this.add(formulaPane); |
||||
} |
||||
|
||||
private void bindListener() { |
||||
FRFont defaultFont = (this.textPane != null) ? FRFont.getInstance(this.textPane.getFont()) : RichTextPane.DEFAUL_FONT; |
||||
fontNameComboBox.addItemListener(fontNameItemListener); |
||||
fontNameComboBox.setSelectedItem(defaultFont.getFontName()); |
||||
fontSizeComboBox.addItemListener(fontSizeItemListener); |
||||
fontSizeComboBox.setSelectedItem(scaleDown(defaultFont.getSize())); |
||||
|
||||
bold.addActionListener(blodChangeAction); |
||||
italic.addActionListener(itaChangeAction); |
||||
underline.addActionListener(underlineChangeAction); |
||||
subPane.addActionListener(subChangeAction); |
||||
superPane.addActionListener(superChangeAction); |
||||
colorSelectPane.addColorChangeListener(colorChangeAction); |
||||
formulaPane.addActionListener(formulaActionListener); |
||||
|
||||
//选中文字的监听器
|
||||
textPane.addCaretListener(textCareListener); |
||||
textPane.addMouseListener(setMouseCurrentStyle); |
||||
textPane.getDocument().addDocumentListener(inputListener); |
||||
} |
||||
|
||||
private void initAllNames() { |
||||
fontNameComboBox.setGlobalName(DesignKit.i18nText("Fine-Design_Report_Font_Family")); |
||||
fontSizeComboBox.setGlobalName(DesignKit.i18nText("Fine-Design_Form_Font_Size")); |
||||
italic.setGlobalName(DesignKit.i18nText("Fine-Design_Report_Italic")); |
||||
bold.setGlobalName(DesignKit.i18nText("Fine-Design_Report_Bold")); |
||||
underline.setGlobalName(DesignKit.i18nText("Fine-Design_Report_Underline")); |
||||
superPane.setGlobalName(DesignKit.i18nText("Fine-Design_Report_Super_Script")); |
||||
subPane.setGlobalName(DesignKit.i18nText("Fine-Design_Report_Sub_Script")); |
||||
} |
||||
|
||||
private void setToolTips() { |
||||
colorSelectPane.setToolTipText(DesignKit.i18nText("Fine-Design_Report_Foreground")); |
||||
italic.setToolTipText(DesignKit.i18nText("Fine-Design_Report_Italic")); |
||||
bold.setToolTipText(DesignKit.i18nText("Fine-Design_Report_Bold")); |
||||
underline.setToolTipText(DesignKit.i18nText("Fine-Design_Report_Underline")); |
||||
superPane.setToolTipText(DesignKit.i18nText("Fine-Design_Report_Super_Script")); |
||||
subPane.setToolTipText(DesignKit.i18nText("Fine-Design_Report_Sub_Script")); |
||||
formulaPane.setToolTipText(DesignKit.i18nText("Fine-Design_Basic_Formula")); |
||||
} |
||||
|
||||
/** |
||||
* 移除输入监听 |
||||
* 用于populate时, 插入字符串, 那时不需要插入监听 |
||||
*/ |
||||
public void removeInputListener() { |
||||
this.textPane.getDocument().removeDocumentListener(inputListener); |
||||
} |
||||
|
||||
/** |
||||
* 增加输入监听事件 |
||||
*/ |
||||
public void addInputListener() { |
||||
this.textPane.getDocument().addDocumentListener(inputListener); |
||||
} |
||||
|
||||
private ActionListener blodChangeAction = new ActionListener() { |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
boolean isBold = RichTextToolBar.this.bold.isSelected(); |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setBold(attr, !isBold); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
|
||||
private ActionListener itaChangeAction = new ActionListener() { |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
boolean isIta = RichTextToolBar.this.italic.isSelected(); |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setItalic(attr, !isIta); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
|
||||
private ActionListener underlineChangeAction = new ActionListener() { |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
boolean isUnder = RichTextToolBar.this.underline.isSelected(); |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setUnderline(attr, !isUnder); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
private ActionListener subChangeAction = new ActionListener() { |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
boolean isSub = RichTextToolBar.this.subPane.isSelected(); |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setSubscript(attr, !isSub); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
private ActionListener superChangeAction = new ActionListener() { |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
boolean isSuper = RichTextToolBar.this.superPane.isSelected(); |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setSuperscript(attr, !isSuper); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
|
||||
private ChangeListener colorChangeAction = new ChangeListener() { |
||||
@Override |
||||
public void stateChanged(ChangeEvent e) { |
||||
Color color = RichTextToolBar.this.colorSelectPane.getColor(); |
||||
color = color == null ? Color.BLACK : color; |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setForeground(attr, color); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
|
||||
// 设置文本区选择文本的样式
|
||||
private void setCharacterAttributes(JEditorPane editor, AttributeSet attr, |
||||
boolean replace) { |
||||
//注意不要失焦
|
||||
textPane.requestFocus(); |
||||
|
||||
// 取得选择文本的起始位置和结束位置
|
||||
int start = editor.getSelectionStart(); |
||||
int end = editor.getSelectionEnd(); |
||||
|
||||
// 如果选中文本,设置选中文本的样式
|
||||
if (start != end) { |
||||
StyledDocument doc = (StyledDocument) textPane.getDocument(); |
||||
// 将所选文本设置为新的样式,replace为false表示不覆盖原有的样式
|
||||
doc.setCharacterAttributes(start, end - start, attr, replace); |
||||
} |
||||
} |
||||
|
||||
private ItemListener fontSizeItemListener = new ItemListener() { |
||||
@Override |
||||
public void itemStateChanged(ItemEvent e) { |
||||
int fontSize = (Integer) RichTextToolBar.this.fontSizeComboBox.getSelectedItem(); |
||||
fontSize = scaleUp(fontSize); |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setFontSize(attr, fontSize); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
|
||||
private ItemListener fontNameItemListener = new ItemListener() { |
||||
@Override |
||||
public void itemStateChanged(ItemEvent e) { |
||||
String fontName = (String) RichTextToolBar.this.fontNameComboBox.getSelectedItem(); |
||||
// 调用setCharacterAttributes函数设置文本区选择文本的字体
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setFontFamily(attr, fontName); |
||||
setCharacterAttributes(RichTextToolBar.this.textPane, attr, false); |
||||
} |
||||
}; |
||||
|
||||
private ActionListener formulaActionListener = new ActionListener() { |
||||
public void actionPerformed(ActionEvent evt) { |
||||
final UIFormula formulaPane = FormulaFactory.createFormulaPane(); |
||||
formulaPane.populate(BaseFormula.createFormulaBuilder().build()); |
||||
formulaPane.showLargeWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { |
||||
@Override |
||||
public void doOk() { |
||||
StyledDocument doc = (StyledDocument) textPane.getDocument(); |
||||
BaseFormula fm = formulaPane.update(); |
||||
String content = RichTextConverter.asFormula(fm.getContent()); |
||||
int start = textPane.getSelectionStart(); |
||||
AttributeSet attrs = start > 0 ? doc.getCharacterElement(start - 1).getAttributes() : new SimpleAttributeSet(); |
||||
try { |
||||
doc.insertString(start, content, attrs); |
||||
} catch (BadLocationException e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
}).setVisible(true); |
||||
} |
||||
}; |
||||
|
||||
private int roundUp(double num) { |
||||
String numStr = Double.toString(num); |
||||
numStr = new BigDecimal(numStr).setScale(0, BigDecimal.ROUND_HALF_UP).toString(); |
||||
return Integer.parseInt(numStr); |
||||
} |
||||
|
||||
private CaretListener textCareListener = new CaretListener() { |
||||
|
||||
//根据选中部分的文字样式, 来动态显示工具栏上按钮的状态
|
||||
private void setSelectedCharStyle(int start, int end, StyledDocument doc) { |
||||
boolean isBold = true; |
||||
boolean isItalic = true; |
||||
boolean isUnderline = true; |
||||
boolean isSubscript = true; |
||||
boolean isSuperscript = true; |
||||
String fontName_1st = null; |
||||
int fontSize_1st = 0; |
||||
Color fontColor_1st = null; |
||||
|
||||
for (int i = start; i < end; i++) { |
||||
Element ele = doc.getCharacterElement(i); |
||||
AttributeSet attrs = ele.getAttributes(); |
||||
|
||||
//粗体
|
||||
isBold = isBold && StyleConstants.isBold(attrs); |
||||
//斜体
|
||||
isItalic = isItalic && StyleConstants.isItalic(attrs); |
||||
//下划线
|
||||
isUnderline = isUnderline && StyleConstants.isUnderline(attrs); |
||||
//下标
|
||||
isSubscript = isSubscript && StyleConstants.isSubscript(attrs); |
||||
//上标
|
||||
isSuperscript = isSuperscript && StyleConstants.isSuperscript(attrs); |
||||
|
||||
if (i == start) { |
||||
fontName_1st = (String) attrs.getAttribute(StyleConstants.FontFamily); |
||||
fontSize_1st = (Integer) attrs.getAttribute(StyleConstants.FontSize); |
||||
fontColor_1st = (Color) attrs.getAttribute(StyleConstants.Foreground); |
||||
fontColor_1st = fontColor_1st == null ? Color.BLACK : fontColor_1st; |
||||
} |
||||
} |
||||
|
||||
setButtonSelected(isBold, isItalic, isUnderline, isSubscript, isSuperscript, |
||||
fontName_1st, fontSize_1st, fontColor_1st); |
||||
} |
||||
|
||||
//动态显示工具栏上按钮的状态
|
||||
private void setButtonSelected(boolean isBold, boolean isItalic, boolean isUnderline, |
||||
boolean isSubscript, boolean isSuperscript, String fontName_1st, |
||||
int fontSize_1st, Color fontColor_1st) { |
||||
bold.setSelected(isBold); |
||||
italic.setSelected(isItalic); |
||||
underline.setSelected(isUnderline); |
||||
subPane.setSelected(isSubscript); |
||||
superPane.setSelected(isSuperscript); |
||||
//为什么字体名称, 大小, 颜色, 不需要去判断是否全相同呢
|
||||
//因为如果全相同, 则设置为第一个字符的样式, 如果不全相同, 那么默认也设置成第一个字符的样式.
|
||||
fontNameComboBox.setSelectedItem(fontName_1st); |
||||
fontSizeComboBox.removeItemListener(fontSizeItemListener); |
||||
fontSizeComboBox.setSelectedItem(scaleDown(fontSize_1st)); |
||||
fontSizeComboBox.addItemListener(fontSizeItemListener); |
||||
selectColorPane(fontColor_1st); |
||||
} |
||||
|
||||
private void selectColorPane(Color color) { |
||||
colorSelectPane.removeColorChangeListener(colorChangeAction); |
||||
colorSelectPane.setColor(color); |
||||
colorSelectPane.addColorChangeListener(colorChangeAction); |
||||
} |
||||
|
||||
@Override |
||||
public void caretUpdate(CaretEvent e) { |
||||
StyledDocument doc = (StyledDocument) textPane.getDocument(); |
||||
|
||||
// 取得选择文本的起始位置和结束位置
|
||||
int start = textPane.getSelectionStart(); |
||||
int end = textPane.getSelectionEnd(); |
||||
|
||||
//如果没有选定字符
|
||||
if (end == start) { |
||||
return; |
||||
} |
||||
|
||||
setSelectedCharStyle(start, end, doc); |
||||
} |
||||
}; |
||||
|
||||
//设置当前光标位样式
|
||||
private MouseListener setMouseCurrentStyle = new MouseAdapter() { |
||||
|
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
StyledDocument doc = (StyledDocument) textPane.getDocument(); |
||||
|
||||
// 取得选择文本的起始位置和结束位置
|
||||
int start = textPane.getSelectionStart(); |
||||
int end = textPane.getSelectionEnd(); |
||||
|
||||
if (start != end) { |
||||
return; |
||||
} |
||||
|
||||
setToLastCharStyle(end, doc); |
||||
} |
||||
|
||||
//如果默认不选字符, 那么设置为最后一个字符的样式
|
||||
private void setToLastCharStyle(int end, StyledDocument doc) { |
||||
if (textPane.isUpdating()) { |
||||
return; |
||||
} |
||||
|
||||
//取前一个字符的样式
|
||||
Element ele = doc.getCharacterElement(end - 1); |
||||
AttributeSet attrs = ele.getAttributes(); |
||||
populateToolBar(attrs); |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* 从样式中更新工具栏上的按钮状态 |
||||
* |
||||
* @param attrs 样式 |
||||
* @date 2015-1-5-下午5:12:33 |
||||
*/ |
||||
public void populateToolBar(AttributeSet attrs) { |
||||
int size = scaleDown(StyleConstants.getFontSize(attrs)); |
||||
fontNameComboBox.setSelectedItem(StyleConstants.getFontFamily(attrs)); |
||||
fontSizeComboBox.setSelectedItem(size); |
||||
|
||||
bold.setSelected(StyleConstants.isBold(attrs)); |
||||
italic.setSelected(StyleConstants.isItalic(attrs)); |
||||
underline.setSelected(StyleConstants.isUnderline(attrs)); |
||||
subPane.setSelected(StyleConstants.isSubscript(attrs)); |
||||
superPane.setSelected(StyleConstants.isSuperscript(attrs)); |
||||
Color foreGround = StyleConstants.getForeground(attrs); |
||||
foreGround = foreGround == null ? Color.BLACK : foreGround; |
||||
colorSelectPane.setColor(foreGround); |
||||
colorSelectPane.repaint(); |
||||
} |
||||
|
||||
//pt转为px =*4/3
|
||||
private int scaleUp(int fontSize) { |
||||
return scale(fontSize, true); |
||||
} |
||||
|
||||
//px转pt = *3/4
|
||||
private int scaleDown(int fontSize) { |
||||
return scale(fontSize, false); |
||||
} |
||||
|
||||
private int scale(int fontSize, boolean isUp) { |
||||
double dpi96 = Constants.FR_PAINT_RESOLUTION; |
||||
double dpi72 = Constants.DEFAULT_FONT_PAINT_RESOLUTION; |
||||
double scale = isUp ? (dpi96 / dpi72) : (dpi72 / dpi96); |
||||
|
||||
return roundUp(fontSize * scale); |
||||
} |
||||
|
||||
private DocumentListener inputListener = new DocumentListener() { |
||||
|
||||
@Override |
||||
public void removeUpdate(DocumentEvent e) { |
||||
} |
||||
|
||||
@Override |
||||
public void insertUpdate(DocumentEvent e) { |
||||
//标志正在更新内容
|
||||
textPane.startUpdating(); |
||||
final MutableAttributeSet attr = updateStyleFromToolBar(); |
||||
final int start = textPane.getSelectionStart(); |
||||
int end = textPane.getSelectionEnd(); |
||||
|
||||
if (start != end) { |
||||
textPane.finishUpdating(); |
||||
return; |
||||
} |
||||
|
||||
//放到SwingWorker里, 是因为在documentListener里不能动态改变doc内容
|
||||
SwingUtilities.invokeLater(new Runnable() { |
||||
|
||||
@Override |
||||
public void run() { |
||||
changeContentStyle(start, attr); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
//根据Style来显示populate按钮
|
||||
private void changeContentStyle(int start, MutableAttributeSet attr) { |
||||
changeContentStyle(start, attr, 1); |
||||
} |
||||
|
||||
private void changeContentStyle(int start, MutableAttributeSet attr, int contentLength) { |
||||
// 将所选文本设置为新的样式,replace为false表示不覆盖原有的样式
|
||||
StyledDocument doc = (StyledDocument) textPane.getDocument(); |
||||
doc.setCharacterAttributes(start, contentLength, attr, false); |
||||
textPane.finishUpdating(); |
||||
} |
||||
|
||||
//将界面上的设置赋值给输入的字符
|
||||
private MutableAttributeSet updateStyleFromToolBar() { |
||||
final boolean isBold = bold.isSelected(); |
||||
final boolean isItalic = italic.isSelected(); |
||||
final boolean isSub = subPane.isSelected(); |
||||
final boolean isSuper = superPane.isSelected(); |
||||
final boolean isUnderLine = underline.isSelected(); |
||||
final String fontName = (String) fontNameComboBox.getSelectedItem(); |
||||
final int fontSize = scaleUp((Integer) fontSizeComboBox.getSelectedItem()); |
||||
final Color foreGround = colorSelectPane.getColor() == null ? Color.BLACK : colorSelectPane.getColor(); |
||||
|
||||
MutableAttributeSet attr = new SimpleAttributeSet(); |
||||
StyleConstants.setBold(attr, isBold); |
||||
StyleConstants.setItalic(attr, isItalic); |
||||
StyleConstants.setSubscript(attr, isSub); |
||||
StyleConstants.setSuperscript(attr, isSuper); |
||||
StyleConstants.setUnderline(attr, isUnderLine); |
||||
StyleConstants.setForeground(attr, foreGround); |
||||
StyleConstants.setFontFamily(attr, fontName); |
||||
StyleConstants.setFontSize(attr, fontSize); |
||||
|
||||
return attr; |
||||
} |
||||
|
||||
@Override |
||||
public void changedUpdate(DocumentEvent e) { |
||||
|
||||
} |
||||
|
||||
private void setContentStyle(final int inputLen) { |
||||
//缓存下Start, 下面要用来设置样式
|
||||
final int _start = inputStart; |
||||
final MutableAttributeSet attr = updateStyleFromToolBar(); |
||||
|
||||
//放到SwingWorker里, 是因为在documentListener里不能动态改变doc内容
|
||||
SwingUtilities.invokeLater(new Runnable() { |
||||
|
||||
@Override |
||||
public void run() { |
||||
//防止触发死循环change事件
|
||||
startUpdating(); |
||||
//Start-1 是因为中文输入法会用空格占1位
|
||||
changeContentStyle(_start, attr, inputLen); |
||||
resetFlag(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private boolean isUpdating() { |
||||
return inputStart == UPDATING; |
||||
} |
||||
|
||||
private void startUpdating() { |
||||
inputStart = UPDATING; |
||||
} |
||||
|
||||
//初始标记状态, 用于记录中文输入法多个字符同时输入的问题
|
||||
private void initFlag(StyledDocument doc) { |
||||
if (inputStart != NOT_INITIALIZED) { |
||||
return; |
||||
} |
||||
inputStart = textPane.getSelectionStart() - 1; |
||||
} |
||||
|
||||
//重置标记状态
|
||||
private void resetFlag() { |
||||
inputStart = NOT_INITIALIZED; |
||||
} |
||||
}; |
||||
|
||||
} |
@ -0,0 +1,133 @@
|
||||
package com.fanruan.api.design.work.component; |
||||
|
||||
import com.fanruan.api.design.DesignKit; |
||||
import com.fanruan.api.design.ui.component.UIComboBox; |
||||
import com.fanruan.api.macro.LineConstants; |
||||
import com.fanruan.api.util.GraphKit; |
||||
import com.fr.base.FRContext; |
||||
import com.fr.base.ScreenResolution; |
||||
import com.fr.design.gui.icombobox.UIComboBoxRenderer; |
||||
import com.fr.general.FRFont; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.awt.geom.GeneralPath; |
||||
import java.awt.geom.Point2D; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
* 用于选择线条类型的下拉框 |
||||
*/ |
||||
public class LineComboBox extends UIComboBox<Integer> { |
||||
|
||||
public LineComboBox(int[] lineStyleArray) { |
||||
Integer[] lineStyleIntegerArray = new Integer[lineStyleArray.length]; |
||||
|
||||
for (int i = 0; i < lineStyleArray.length; i++) { |
||||
lineStyleIntegerArray[i] = lineStyleArray[i]; |
||||
} |
||||
|
||||
this.setModel(new DefaultComboBoxModel(lineStyleIntegerArray)); |
||||
|
||||
this.setRenderer(new LineComboBox.LineCellRenderer()); |
||||
} |
||||
|
||||
/** |
||||
* 获取选择的线条类型 |
||||
* |
||||
* @return 用于表示线条类型的整数 |
||||
*/ |
||||
public int getSelectedLineStyle() { |
||||
int style = (Integer) getSelectedItem(); |
||||
return (style < 0) ? LineConstants.LINE_NONE : style; |
||||
} |
||||
|
||||
/** |
||||
* 设置选中的线条类型 |
||||
* |
||||
* @param style 用于表示线条类型的整数 |
||||
*/ |
||||
public void setSelectedLineStyle(int style) { |
||||
this.setSelectedItem(style); |
||||
} |
||||
|
||||
private static class LineCellRenderer extends UIComboBoxRenderer { |
||||
|
||||
private int style = LineConstants.LINE_NONE; |
||||
|
||||
public Component getListCellRendererComponent( |
||||
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { |
||||
JLabel comp = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); |
||||
this.style = (Integer) value; |
||||
comp.setText(null); |
||||
return comp; |
||||
} |
||||
|
||||
public void paint(Graphics g) { |
||||
super.paint(g); |
||||
Graphics2D g2d = (Graphics2D) g; |
||||
|
||||
Dimension d = getSize(); |
||||
g2d.setColor(getForeground()); |
||||
|
||||
FRFont font = FRContext.getDefaultValues().getFRFont(); |
||||
int resolution = ScreenResolution.getScreenResolution(); |
||||
Font rfont = font.applyResolutionNP(resolution); |
||||
g2d.setFont(rfont); |
||||
FontMetrics fm = GraphKit.getFontMetrics(rfont); |
||||
if (style == LineConstants.LINE_NONE) { |
||||
GraphKit.drawString(g2d, DesignKit.i18nText("Fine-Design_Report_None"), 4, (d.height - fm.getHeight()) / 2D + fm.getAscent()); |
||||
} else { |
||||
GraphKit.drawLine(g2d, 4, d.height / 2D, d.width - 8D, d.height / 2D, style); |
||||
} |
||||
|
||||
if (isShowAxisWithLineStyle()) { // 带有坐标轴箭头的样式.
|
||||
drawArrow(g2d, new Point2D.Double(4, d.height / 2D), new Point2D.Double(d.width - 8D, d.height / 2D)); |
||||
} |
||||
} |
||||
|
||||
private void drawArrow(Graphics2D g2d, Point2D p0, Point2D p1) { |
||||
Point2D s = new Point2D.Double(p1.getX() - p0.getX(), p1.getY() - p0.getY()); |
||||
Point2D t = new Point2D.Double(); |
||||
double d1 = p0.distance(p1); |
||||
//d2-d5设定箭头的大小,p1-p2为坐标轴的延长线,p2-p5-p3-p6为箭头4个点的具体位置
|
||||
double d2 = 9; |
||||
double d3 = 15; |
||||
double d4 = 7; |
||||
double d5 = 3; |
||||
t.setLocation(d2 * s.getX() / d1, d2 * s.getY() / d1); |
||||
Point2D p2 = new Point2D.Double(p1.getX() + t.getX(), p1.getY() + t.getY()); |
||||
t.setLocation(d3 * s.getX() / d1, d3 * s.getY() / d1); |
||||
Point2D p3 = new Point2D.Double(p1.getX() + t.getX(), p1.getY() + t.getY()); |
||||
t.setLocation(d4 * s.getX() / d1, d4 * s.getY() / d1); |
||||
Point2D p4 = new Point2D.Double(p1.getX() + t.getX(), p1.getY() + t.getY()); |
||||
Point2D p5 = new Point2D.Double(p4.getX() + s.getY() / d1 * d5, p4.getY() - s.getX() / d1 * d5); |
||||
Point2D p6 = new Point2D.Double(p4.getX() - s.getY() / d1 * d5, p4.getY() + s.getX() / d1 * d5); |
||||
|
||||
GeneralPath arrow = new GeneralPath(); |
||||
arrow.moveTo((float) p2.getX() - 10, (float) p2.getY()); |
||||
arrow.lineTo((float) p5.getX() - 10, (float) p5.getY()); |
||||
arrow.lineTo((float) p3.getX() - 10, (float) p3.getY()); |
||||
arrow.lineTo((float) p6.getX() - 10, (float) p6.getY()); |
||||
arrow.closePath(); |
||||
|
||||
g2d.draw(arrow); |
||||
g2d.fill(arrow); |
||||
} |
||||
|
||||
private boolean isShowAxisWithLineStyle() { |
||||
return style == LineConstants.LINE_CHART_MED_ARROW |
||||
|| style == LineConstants.LINE_CHART_THICK_ARROW || style == LineConstants.LINE_CHART_THIN_ARROW; |
||||
} |
||||
|
||||
public Dimension getPreferredSize() { |
||||
return new Dimension(60, 16); |
||||
} |
||||
|
||||
public Dimension getMinimumSize() { |
||||
return getPreferredSize(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,32 @@
|
||||
package com.fanruan.api.macro; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
* 用于表示线条样式 |
||||
*/ |
||||
public class LineConstants { |
||||
|
||||
public static final int LINE_NONE = 0; |
||||
public static final int LINE_THIN = 1; |
||||
public static final int LINE_MEDIUM = 2; |
||||
public static final int LINE_DASH = 3; |
||||
public static final int LINE_HAIR = 4; |
||||
public static final int LINE_THICK = 5; |
||||
public static final int LINE_DOUBLE = 6; |
||||
public static final int LINE_DOT = 7; |
||||
public static final int LINE_MEDIUM_DASH = 8; |
||||
public static final int LINE_DASH_DOT = 9; |
||||
public static final int LINE_MEDIUM_DASH_DOT = 10; |
||||
public static final int LINE_DASH_DOT_DOT = 11; |
||||
public static final int LINE_MEDIUM_DASH_DOT_DOT = 12; |
||||
public static final int LINE_SLANTED_DASH_DOT = 13; |
||||
public static final int LINE_HAIR2 = 14; |
||||
public static final int LINE_DOUBLE_DOT = 15; |
||||
public static final int LINE_LARGE = 16; |
||||
public static final int LINE_SLIM = 17; |
||||
public static final int LINE_CHART_THIN_ARROW = 21; |
||||
public static final int LINE_CHART_MED_ARROW = 22; |
||||
public static final int LINE_CHART_THICK_ARROW = 23; |
||||
} |
@ -0,0 +1,21 @@
|
||||
package com.fanruan.api.report.form.category; |
||||
|
||||
import com.fanruan.api.report.form.BaseWidget; |
||||
import com.fr.form.ui.LayoutBorderStyle; |
||||
import com.fr.form.ui.PaddingMargin; |
||||
import com.fr.form.ui.RichStyleWidgetProvider; |
||||
import com.fr.general.Background; |
||||
import com.fr.general.act.BorderPacker; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
* 带边框和样式设置的控件基类 |
||||
*/ |
||||
public abstract class BaseBorderStyleWidget extends BaseWidget implements RichStyleWidgetProvider { |
||||
|
||||
private BorderPacker borderStyle = new LayoutBorderStyle(); |
||||
private Background background; |
||||
private PaddingMargin margin = new PaddingMargin(); |
||||
} |
@ -0,0 +1,104 @@
|
||||
package com.fanruan.api.util; |
||||
|
||||
import com.fr.stable.GraphDrawHelper; |
||||
|
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019/10/25 |
||||
* 图形绘制相关的工具类 |
||||
*/ |
||||
public class GraphKit { |
||||
|
||||
/** |
||||
* 获取字体规格属性 |
||||
* |
||||
* @param font 字体 |
||||
* @return 字体的规格属性 |
||||
*/ |
||||
public static FontMetrics getFontMetrics(Font font) { |
||||
return GraphDrawHelper.getFontMetrics(font); |
||||
} |
||||
|
||||
/** |
||||
* 获取字体规格属性 |
||||
* |
||||
* @param font 字体 |
||||
* @param g2d 图形绘制上下文 |
||||
* @return 字体的规格属性 |
||||
*/ |
||||
public static FontMetrics getFontMetrics(Font font, Graphics2D g2d) { |
||||
return GraphDrawHelper.getFontMetrics(font, g2d); |
||||
} |
||||
|
||||
/** |
||||
* 绘制文本 |
||||
* |
||||
* @param g 图形绘制上下文 |
||||
* @param str 待绘制的文本 |
||||
* @param x 横坐标 |
||||
* @param y 纵坐标 |
||||
*/ |
||||
public static void drawString(Graphics g, String str, double x, double y) { |
||||
GraphDrawHelper.drawString(g, str, x, y); |
||||
} |
||||
|
||||
/** |
||||
* 绘制线段 |
||||
* |
||||
* @param g 图形绘制上下文 |
||||
* @param x1 起点横坐标 |
||||
* @param y1 起点纵坐标 |
||||
* @param x2 终点横坐标 |
||||
* @param y2 终点纵坐标 |
||||
*/ |
||||
public static void drawLine(Graphics g, double x1, double y1, double x2, double y2) { |
||||
GraphDrawHelper.drawLine(g, x1, y1, x2, y2); |
||||
} |
||||
|
||||
/** |
||||
* 绘制线段 |
||||
* |
||||
* @param g 图形绘制上下文 |
||||
* @param x1 起点横坐标 |
||||
* @param y1 起点纵坐标 |
||||
* @param x2 终点横坐标 |
||||
* @param y2 终点纵坐标 |
||||
* @param lineStyle 线条样式 |
||||
* @see com.fanruan.api.macro.LineConstants |
||||
*/ |
||||
public static void drawLine(Graphics g, |
||||
double x1, double y1, double x2, double y2, int lineStyle) { |
||||
GraphDrawHelper.drawLine(g, x1, y1, x2, y2, lineStyle); |
||||
} |
||||
|
||||
/** |
||||
* 绘制矩形 |
||||
* |
||||
* @param g 图形绘制上下文 |
||||
* @param x 起点横坐标 |
||||
* @param y 起点纵坐标 |
||||
* @param width 矩形宽度 |
||||
* @param height 矩形高度 |
||||
*/ |
||||
public static void drawRect(Graphics g, double x, double y, double width, double height) { |
||||
GraphDrawHelper.drawRect(g, x, y, width, height); |
||||
} |
||||
|
||||
/** |
||||
* 绘制矩形 |
||||
* |
||||
* @param g 图形绘制上下文 |
||||
* @param x 起点横坐标 |
||||
* @param y 起点纵坐标 |
||||
* @param width 矩形宽度 |
||||
* @param height 矩形高度 |
||||
* @param lineStyle 线条样式 |
||||
* @see com.fanruan.api.macro.LineConstants |
||||
*/ |
||||
public static void drawRect(Graphics g, double x, double y, double width, double height, int lineStyle) { |
||||
GraphDrawHelper.drawRect(g, x, y, width, height, lineStyle); |
||||
} |
||||
} |
Loading…
Reference in new issue