Henry.Wang
3 years ago
65 changed files with 1095 additions and 5627 deletions
@ -0,0 +1,200 @@
|
||||
package com.fr.design.gui.icombobox; |
||||
|
||||
import com.fr.data.core.DataCoreUtils; |
||||
import com.fr.data.core.db.TableProcedure; |
||||
import com.fr.data.impl.Connection; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.design.data.datapane.ChoosePane; |
||||
import com.fr.design.dialog.FineJOptionPane; |
||||
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.JOptionPane; |
||||
import javax.swing.JTree; |
||||
import javax.swing.SwingWorker; |
||||
import javax.swing.tree.DefaultMutableTreeNode; |
||||
import javax.swing.tree.DefaultTreeModel; |
||||
import javax.swing.tree.TreeCellRenderer; |
||||
import javax.swing.tree.TreeNode; |
||||
import javax.swing.tree.TreePath; |
||||
import java.awt.event.MouseEvent; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* 实现模糊搜索的FRTreeComboBox |
||||
* FRTreeComboBox:搜索后滚动到首个匹配节点 |
||||
* SearchFRTreeComboBox:显示所有匹配的节点 |
||||
* |
||||
* @author Lucian.Chen |
||||
* @version 10.0 |
||||
* Created by Lucian.Chen on 2021/4/14 |
||||
*/ |
||||
public class SearchFRTreeComboBox extends FRTreeComboBox { |
||||
|
||||
// 持有父容器,需要实时获取其他组件值
|
||||
private final ChoosePane parent; |
||||
|
||||
public SearchFRTreeComboBox(ChoosePane parent, JTree tree, TreeCellRenderer renderer) { |
||||
super(tree, renderer); |
||||
this.parent = parent; |
||||
setUI(new SearchFRTreeComboBoxUI()); |
||||
} |
||||
|
||||
protected UIComboBoxEditor createEditor() { |
||||
return new SearchFRComboBoxEditor(this); |
||||
} |
||||
|
||||
/** |
||||
* 执行模糊搜索 |
||||
*/ |
||||
private void searchExecute() { |
||||
UIComboBoxEditor searchEditor = (UIComboBoxEditor) this.getEditor(); |
||||
new SwingWorker<Void, Void>() { |
||||
@Override |
||||
protected Void doInBackground() { |
||||
processTableDataNames( |
||||
parent.getDSName(), |
||||
parent.getConnection(), |
||||
parent.getSchema(), |
||||
createFilter((String) searchEditor.getItem())); |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected void done() { |
||||
expandTree(); |
||||
// 输入框获取焦点
|
||||
searchEditor.getEditorComponent().requestFocus(); |
||||
} |
||||
}.execute(); |
||||
} |
||||
|
||||
private TableNameFilter createFilter(String text) { |
||||
return StringUtils.isEmpty(text) ? EMPTY_FILTER : new TableNameFilter(text); |
||||
} |
||||
|
||||
/** |
||||
* 查询数据库表,并构建节点目录 |
||||
* |
||||
* @param databaseName 数据库名 |
||||
* @param connection 数据连接 |
||||
* @param schema 模式 |
||||
* @param filter 模糊搜索过滤器 |
||||
*/ |
||||
private void processTableDataNames(String databaseName, Connection connection, String schema, TableNameFilter filter) { |
||||
if (tree == null) { |
||||
return; |
||||
} |
||||
DefaultMutableTreeNode rootTreeNode = (DefaultMutableTreeNode) tree.getModel().getRoot(); |
||||
rootTreeNode.removeAllChildren(); |
||||
|
||||
if (connection == null) { |
||||
return; |
||||
} |
||||
try { |
||||
schema = StringUtils.isEmpty(schema) ? null : schema; |
||||
TableProcedure[] sqlTableArray = DataCoreUtils.getTables(connection, TableProcedure.TABLE, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); |
||||
if (ArrayUtils.isNotEmpty(sqlTableArray)) { |
||||
ExpandMutableTreeNode tableTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); |
||||
rootTreeNode.add(tableTreeNode); |
||||
addArrayNode(tableTreeNode, sqlTableArray, filter); |
||||
} |
||||
TableProcedure[] sqlViewArray = DataCoreUtils.getTables(connection, TableProcedure.VIEW, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); |
||||
if (ArrayUtils.isNotEmpty(sqlViewArray)) { |
||||
ExpandMutableTreeNode viewTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); |
||||
rootTreeNode.add(viewTreeNode); |
||||
addArrayNode(viewTreeNode, sqlViewArray, filter); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"), |
||||
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Failed"), JOptionPane.ERROR_MESSAGE); |
||||
} |
||||
} |
||||
|
||||
private void addArrayNode(ExpandMutableTreeNode rootNode, TableProcedure[] sqlArray, TableNameFilter filter) { |
||||
if (sqlArray != null) { |
||||
for (TableProcedure procedure : sqlArray) { |
||||
if (filter.accept(procedure)) { |
||||
ExpandMutableTreeNode viewChildTreeNode = new ExpandMutableTreeNode(procedure); |
||||
rootNode.add(viewChildTreeNode); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 展开节点 |
||||
*/ |
||||
private void expandTree() { |
||||
((DefaultTreeModel) tree.getModel()).reload(); |
||||
// daniel 展开所有tree
|
||||
TreeNode root = (TreeNode) tree.getModel().getRoot(); |
||||
TreePath parent = new TreePath(root); |
||||
TreeNode node = (TreeNode) parent.getLastPathComponent(); |
||||
for (Enumeration e = node.children(); e.hasMoreElements(); ) { |
||||
TreeNode n = (TreeNode) e.nextElement(); |
||||
TreePath path = parent.pathByAddingChild(n); |
||||
tree.expandPath(path); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 重写输入框编辑器,实现输入框模糊搜索逻辑 |
||||
*/ |
||||
private class SearchFRComboBoxEditor extends FrTreeSearchComboBoxEditor { |
||||
|
||||
public SearchFRComboBoxEditor(FRTreeComboBox comboBox) { |
||||
super(comboBox); |
||||
} |
||||
|
||||
@Override |
||||
protected void changeHandler() { |
||||
if (isSetting()) { |
||||
return; |
||||
} |
||||
setPopupVisible(true); |
||||
this.item = textField.getText(); |
||||
searchExecute(); |
||||
} |
||||
} |
||||
|
||||
private static final TableNameFilter EMPTY_FILTER = new TableNameFilter(StringUtils.EMPTY) { |
||||
public boolean accept(TableProcedure procedure) { |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* 表名模糊搜索实现 |
||||
*/ |
||||
private static class TableNameFilter { |
||||
private final String searchFilter; |
||||
|
||||
public TableNameFilter(String searchFilter) { |
||||
if (StringUtils.isNotEmpty(searchFilter)) { |
||||
searchFilter = searchFilter.toLowerCase().trim(); |
||||
} |
||||
this.searchFilter = searchFilter; |
||||
} |
||||
|
||||
// 字符串匹配
|
||||
public boolean accept(TableProcedure procedure) { |
||||
return procedure.getName().toLowerCase().contains(searchFilter); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 重写FRTreeComboBoxUI,实现点击下拉时触发模糊搜索 |
||||
*/ |
||||
private class SearchFRTreeComboBoxUI extends FRTreeComboBoxUI { |
||||
|
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
searchExecute(); |
||||
} |
||||
} |
||||
} |
@ -1,77 +0,0 @@
|
||||
package com.fr.design.gui.icombobox; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
|
||||
import javax.swing.JTree; |
||||
import javax.swing.SwingWorker; |
||||
import javax.swing.tree.TreeCellRenderer; |
||||
import java.util.concurrent.FutureTask; |
||||
|
||||
/** |
||||
* 模糊搜索前需执行完前置任务的TreeComboBox |
||||
* @author Lucian.Chen |
||||
* @version 10.0 |
||||
* Created by Lucian.Chen on 2021/4/14 |
||||
*/ |
||||
public class SearchPreTaskTreeComboBox extends FRTreeComboBox { |
||||
|
||||
/** |
||||
* 模糊搜索前任务 |
||||
*/ |
||||
private FutureTask<Void> preSearchTask; |
||||
|
||||
public SearchPreTaskTreeComboBox(JTree tree, TreeCellRenderer renderer, boolean editable) { |
||||
super(tree, renderer, editable); |
||||
} |
||||
|
||||
public FutureTask<Void> getPreSearchTask() { |
||||
return preSearchTask; |
||||
} |
||||
|
||||
public void setPreSearchTask(FutureTask<Void> preSearchTask) { |
||||
this.preSearchTask = preSearchTask; |
||||
} |
||||
|
||||
protected UIComboBoxEditor createEditor() { |
||||
return new SearchPreTaskComboBoxEditor(this); |
||||
} |
||||
|
||||
private class SearchPreTaskComboBoxEditor extends FrTreeSearchComboBoxEditor { |
||||
|
||||
public SearchPreTaskComboBoxEditor(FRTreeComboBox comboBox) { |
||||
super(comboBox); |
||||
} |
||||
|
||||
protected void changeHandler() { |
||||
if (isSetting()) { |
||||
return; |
||||
} |
||||
setPopupVisible(true); |
||||
new SwingWorker<Void, Void>() { |
||||
@Override |
||||
protected Void doInBackground() { |
||||
FutureTask<Void> task = getPreSearchTask(); |
||||
try { |
||||
// 确保模糊搜索前任务执行完成后,再进行模糊搜索
|
||||
if (task != null) { |
||||
task.get(); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
if (task != null) { |
||||
// 任务执行后置空,否则会被别的操作重复触发
|
||||
setPreSearchTask(null); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected void done() { |
||||
// 模糊搜索
|
||||
search(); |
||||
} |
||||
}.execute(); |
||||
} |
||||
} |
||||
} |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.fit; |
||||
package com.fr.design.mainframe; |
||||
|
||||
import com.fr.stable.Constants; |
||||
import com.fr.stable.unit.LEN_UNIT; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.fit; |
||||
package com.fr.design.mainframe; |
||||
|
||||
import com.fr.design.fun.impl.AbstractReportLengthUNITProvider; |
||||
import com.fr.stable.unit.UNIT; |
@ -1,115 +0,0 @@
|
||||
package com.fr.design.actions; |
||||
|
||||
|
||||
import com.fr.base.iofile.attr.MobileOnlyTemplateAttrMark; |
||||
import com.fr.design.designer.creator.XLayoutContainer; |
||||
import com.fr.design.designer.creator.XWAbsoluteBodyLayout; |
||||
import com.fr.design.designer.creator.XWFitLayout; |
||||
import com.fr.design.dialog.BasicDialog; |
||||
import com.fr.design.dialog.DialogActionAdapter; |
||||
import com.fr.design.fit.NewJForm; |
||||
import com.fr.design.fit.common.AdaptiveSwitchUtil; |
||||
import com.fr.design.fit.common.TemplateTool; |
||||
import com.fr.design.form.mobile.FormMobileAttrPane; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.FormArea; |
||||
import com.fr.design.mainframe.FormDesigner; |
||||
import com.fr.design.mainframe.JForm; |
||||
import com.fr.design.mainframe.WidgetPropertyPane; |
||||
import com.fr.file.FILE; |
||||
import com.fr.form.main.Form; |
||||
import com.fr.form.main.mobile.FormMobileAttr; |
||||
import com.fr.record.analyzer.EnableMetrics; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import java.awt.event.ActionEvent; |
||||
|
||||
/** |
||||
* Created by fanglei on 2016/11/14. |
||||
*/ |
||||
@EnableMetrics |
||||
public class NewFormMobileAttrAction extends FormMobileAttrAction { |
||||
|
||||
public NewFormMobileAttrAction(JForm jf) { |
||||
super(jf); |
||||
} |
||||
|
||||
/** |
||||
* 执行动作 |
||||
* |
||||
* @return 是否执行成功 |
||||
*/ |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
final JForm jf = getEditingComponent(); |
||||
if (jf == null) { |
||||
return; |
||||
} |
||||
final Form formTpl = jf.getTarget(); |
||||
FormMobileAttr mobileAttr = formTpl.getFormMobileAttr(); |
||||
|
||||
final FormMobileAttrPane mobileAttrPane = new FormMobileAttrPane(); |
||||
mobileAttrPane.populateBean(mobileAttr); |
||||
|
||||
final boolean oldMobileOnly = mobileAttr.isMobileOnly(); |
||||
final boolean oldAdaptive = mobileAttr.isAdaptivePropertyAutoMatch(); |
||||
BasicDialog dialog = mobileAttrPane.showWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { |
||||
@Override |
||||
public void doOk() { |
||||
FormMobileAttr formMobileAttr = mobileAttrPane.updateBean(); |
||||
if (formMobileAttr.isMobileOnly() && jf.getTarget().getAttrMark(MobileOnlyTemplateAttrMark.XML_TAG) == null) { |
||||
// 如果是老模板,选择手机专属之后需要另存为
|
||||
FILE editingFILE = jf.getEditingFILE(); |
||||
if (editingFILE != null && editingFILE.exists()) { |
||||
String fileName = editingFILE.getName().substring(0, editingFILE.getName().length() - jf.suffix().length()) + "_mobile"; |
||||
if (!jf.saveAsTemplate(true, fileName)) { |
||||
return; |
||||
} |
||||
} |
||||
// 放到后面。如果提前 return 了,则仍然处于未设置状态,不要添加
|
||||
jf.getTarget().addAttrMark(new MobileOnlyTemplateAttrMark()); |
||||
} |
||||
// 设置移动端属性并刷新界面
|
||||
formTpl.setFormMobileAttr(formMobileAttr); // 会调整 body 的自适应布局,放到最后
|
||||
boolean changeSize = (!oldMobileOnly && formMobileAttr.isMobileOnly()) || (oldMobileOnly && !formMobileAttr.isMobileOnly()); |
||||
if (changeSize) { |
||||
((FormArea)jf.getFormDesign().getParent()).onMobileAttrModified(); |
||||
} |
||||
//改变布局为自适应布局,只在移动端属性设置保存后改变一次
|
||||
boolean changeLayout = !oldAdaptive && formMobileAttr.isAdaptivePropertyAutoMatch(); |
||||
if (changeLayout) { |
||||
jf.getFormDesign().getSelectionModel().setSelectedCreator(jf.getFormDesign().getRootComponent()); |
||||
doChangeBodyLayout(); |
||||
WidgetPropertyPane.getInstance().refreshDockingView(); |
||||
} |
||||
jf.fireTargetModified(); |
||||
FILE editingFILE = jf.getEditingFILE(); |
||||
if(editingFILE != null && editingFILE.exists()){ |
||||
JForm jForm = getEditingComponent(); |
||||
TemplateTool.saveForm(jForm); |
||||
if (jForm instanceof NewJForm) { |
||||
AdaptiveSwitchUtil.switch2OldUI(); |
||||
} |
||||
}else { |
||||
AdaptiveSwitchUtil.switch2OldUIMode(); |
||||
NewJForm mobileJForm = new NewJForm(jf.getTarget(), jf.getEditingFILE()); |
||||
//设置临时的id,和新建的模板区分
|
||||
mobileJForm.getTarget().setTemplateID(StringUtils.EMPTY); |
||||
TemplateTool.resetTabPaneEditingTemplate(mobileJForm); |
||||
TemplateTool.activeAndResizeTemplate(mobileJForm); |
||||
} |
||||
} |
||||
}); |
||||
dialog.setVisible(true); |
||||
} |
||||
|
||||
private void doChangeBodyLayout(){ |
||||
FormDesigner formDesigner = WidgetPropertyPane.getInstance().getEditingFormDesigner(); |
||||
XLayoutContainer rootLayout = formDesigner.getRootComponent(); |
||||
if (rootLayout.getComponentCount() == 1 && rootLayout.getXCreator(0).acceptType(XWAbsoluteBodyLayout.class)) { |
||||
rootLayout = (XWAbsoluteBodyLayout) rootLayout.getXCreator(0); |
||||
} |
||||
((XWFitLayout)formDesigner.getRootComponent()).switch2FitBodyLayout(rootLayout); |
||||
} |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
||||
package com.fr.design.fit.common; |
||||
|
||||
import com.fr.base.DefaultAutoChangeLine; |
||||
import com.fr.base.Style; |
||||
import com.fr.stable.unit.UNIT; |
||||
|
||||
import java.awt.Font; |
||||
import java.util.List; |
||||
|
||||
public class NewUIModeAutoChangeLine extends DefaultAutoChangeLine { |
||||
@Override |
||||
public List<String> textAutoChangeLine(String text, Font font, Style style, UNIT unitWidth, int resolution) { |
||||
return autoChangeLine(text, font, style, unitWidth, resolution); |
||||
} |
||||
|
||||
protected double calculateShowWidth(double paintWidth, Style style, int resolution) { |
||||
return paintWidth - style.getPaddingLeft() - style.getPaddingRight() - style.getBorderLeftWidth(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,69 @@
|
||||
package com.fr.design.fit.common; |
||||
|
||||
import com.fr.base.BaseUtils; |
||||
import com.fr.base.DefaultRotationTextDrawProvider; |
||||
import com.fr.base.GraphHelper; |
||||
import com.fr.base.Style; |
||||
import com.fr.design.mainframe.PX; |
||||
import com.fr.stable.Constants; |
||||
|
||||
import java.awt.Font; |
||||
import java.awt.FontMetrics; |
||||
import java.awt.Graphics2D; |
||||
import java.util.List; |
||||
|
||||
public class NewUIModeRotationDraw extends DefaultRotationTextDrawProvider { |
||||
@Override |
||||
public void drawRotationText(Graphics2D g2d, String text, Style style, Font rfont, int width, int height, int horizontalAlignment, int resolution) { |
||||
FontMetrics cellFM = GraphHelper.getFontMetrics(rfont); |
||||
List lineTextList = BaseUtils.getLineTextList(text, style, rfont, height, width, resolution, new NewUIModeAutoChangeLine()); |
||||
drawRotationText(g2d, lineTextList, style, cellFM, width, height, horizontalAlignment, resolution); |
||||
} |
||||
|
||||
|
||||
protected int calculateTextWidth(int width, Style style) { |
||||
return width - style.getPaddingRight(); |
||||
} |
||||
|
||||
protected double calculateTextX(Style style, int width, int textWidth, int horizontalAlignment, int resolution) { |
||||
double textX = padding2PixExcludeRight(style.getPaddingLeft(), resolution); |
||||
if (horizontalAlignment == Constants.CENTER) { |
||||
textX += (width - textWidth - textX) / 2f; |
||||
} else if (horizontalAlignment == Constants.RIGHT) { |
||||
textX = width - style.getPaddingRight() - textWidth; |
||||
} |
||||
return textX; |
||||
} |
||||
|
||||
protected int toPXWithResolution(double pt, int resolution) { |
||||
return (int) PX.toPixWithResolution(pt, resolution); |
||||
} |
||||
|
||||
protected double padding2PixExcludeRight(int padding, int resolution) { |
||||
return PX.toPixWithResolution(padding, resolution); |
||||
} |
||||
|
||||
protected int calculateTextY(Style style, int height, int textHeight, int textAscent, List lineTextList, int resolution) { |
||||
// 计算Y的高度.
|
||||
int textY = 0; |
||||
int textAllHeight = textHeight * lineTextList.size(); |
||||
double spacingBefore = toPXWithResolution(style.getSpacingBefore(), resolution); |
||||
double spacingAfter = toPXWithResolution(style.getSpacingAfter(), resolution); |
||||
double lineSpacing = toPXWithResolution(style.getLineSpacing(), resolution); |
||||
textAllHeight += spacingBefore + spacingAfter + lineSpacing * lineTextList.size(); |
||||
if (style.getVerticalAlignment() == Constants.TOP) { |
||||
} else if (style.getVerticalAlignment() == Constants.CENTER) { |
||||
if (height > textAllHeight) {// 如果所有文本的高度小于当前可以绘区域的高度,就从0开始画字符.
|
||||
textY = (height - textAllHeight) / 2; |
||||
} |
||||
} else if (style.getVerticalAlignment() == Constants.BOTTOM) { |
||||
if (height > textAllHeight) { |
||||
textY = height - textAllHeight; |
||||
} |
||||
} |
||||
textY += textAscent;// 在绘画的时候,必须添加Ascent的高度.
|
||||
textY += spacingBefore + lineSpacing;//james:加上"段前间距"+“行间距”
|
||||
return textY; |
||||
} |
||||
|
||||
} |
@ -1,835 +0,0 @@
|
||||
/* |
||||
* Copyright(c) 2001-2010, FineReport Inc, All Rights Reserved. |
||||
*/ |
||||
package com.fr.design.fit.common; |
||||
|
||||
import com.fr.base.AutoChangeLineAndDrawManager; |
||||
import com.fr.base.BaseFormula; |
||||
import com.fr.base.BaseUtils; |
||||
import com.fr.base.GraphHelper; |
||||
import com.fr.base.ImageProvider; |
||||
import com.fr.base.Painter; |
||||
import com.fr.base.Style; |
||||
import com.fr.base.Utils; |
||||
import com.fr.base.background.ColorBackground; |
||||
import com.fr.base.chart.BaseChartCollection; |
||||
import com.fr.base.chart.result.WebChartIDInfo; |
||||
import com.fr.code.BarcodeImpl; |
||||
import com.fr.code.bar.BarcodeException; |
||||
import com.fr.code.bar.core.BarCodeUtils; |
||||
import com.fr.code.bar.core.BarcodeAttr; |
||||
import com.fr.data.DataUtils; |
||||
import com.fr.data.PresentationType; |
||||
import com.fr.data.condition.ListCondition; |
||||
import com.fr.file.ResultChangeWhenExport; |
||||
import com.fr.form.ui.Widget; |
||||
import com.fr.general.Background; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.general.FRFont; |
||||
import com.fr.general.ImageWithSuffix; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.ExtraClassManager; |
||||
import com.fr.report.cell.CellElement; |
||||
import com.fr.report.cell.FloatElement; |
||||
import com.fr.report.cell.TemplateCellElement; |
||||
import com.fr.report.cell.cellattr.CellExpandAttr; |
||||
import com.fr.report.cell.cellattr.CellGUIAttr; |
||||
import com.fr.report.cell.cellattr.core.CellUtils; |
||||
import com.fr.report.cell.cellattr.core.ResultSubReport; |
||||
import com.fr.report.cell.cellattr.core.group.DSColumn; |
||||
import com.fr.report.core.Html2ImageUtils; |
||||
import com.fr.report.core.ReportUtils; |
||||
import com.fr.script.Calculator; |
||||
import com.fr.stable.Constants; |
||||
import com.fr.stable.CoreConstants; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.bridge.ObjectHolder; |
||||
import com.fr.stable.fun.AutoChangeLineAndDrawProcess; |
||||
import com.fr.stable.fun.FontProcessor; |
||||
import com.fr.stable.html.Tag; |
||||
import com.fr.stable.unit.FU; |
||||
import com.fr.stable.unit.PT; |
||||
import com.fr.stable.unit.UNIT; |
||||
import com.fr.stable.web.Repository; |
||||
|
||||
import javax.swing.ImageIcon; |
||||
import java.awt.AlphaComposite; |
||||
import java.awt.Color; |
||||
import java.awt.Font; |
||||
import java.awt.FontMetrics; |
||||
import java.awt.Graphics2D; |
||||
import java.awt.Image; |
||||
import java.awt.Paint; |
||||
import java.awt.Rectangle; |
||||
import java.awt.font.TextAttribute; |
||||
import java.awt.geom.GeneralPath; |
||||
import java.awt.image.BufferedImage; |
||||
import java.util.Hashtable; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* The util for paint. |
||||
*/ |
||||
public class PaintUtils { |
||||
// Add by Denny
|
||||
public static final int CELL_MARK_SIZE = 6; |
||||
public static final Color CELL_HIGHT_LIGHT_MARK_COLOR = new Color(255, 0, 55); |
||||
public static final Color CELL_PRESENT_MARK_COLOR = new Color(0, 255, 200); |
||||
public static final Color CELL_PAGINATION_MARK_COLOR = new Color(55, 255, 0); |
||||
public static final Color CELL_RESULT_MARK_COLOR = new Color(200, 0, 255); |
||||
public static final Color CELL_CONDITION_FILTER_MARK_COLOR = new Color(255, 200, 0); |
||||
public static final Color CELL_PARAMETER_FILTER_MARK_CONLR = new Color(0, 55, 255); |
||||
|
||||
public static final Color CELL_DIRECTION_MARK_COLOR = Color.gray; |
||||
private static final int UNIT_SIZE = 4; |
||||
|
||||
//原值是15,矩形线条会缺失,加1px绘制没问题。这地方有水印,但是貌似不是水印影响,未找到线条被挡住的原因
|
||||
private static final int WIDGET_WIDTH = 16; |
||||
private static final int WIDGET_HEIGHT = 16; |
||||
|
||||
// Suppresses default constructor, ensuring non-instantiability.
|
||||
private PaintUtils() { |
||||
} |
||||
|
||||
// font attributes map cache
|
||||
private static Hashtable fontAttributeMapCache = new Hashtable(); |
||||
|
||||
/* |
||||
* 用于在Grid里面画CellElement的Content + Background |
||||
* |
||||
* 不画Border,是因为在Grid里面先画所有单元格的Content + Background,再画所有单元格的Border(peter认为这可以提高速度) |
||||
*/ |
||||
public static void paintGridCellContent(Graphics2D g2d, TemplateCellElement cell, int width, int height, int resolution) { |
||||
int cell_mark_size = CELL_MARK_SIZE; |
||||
// denny_Grid
|
||||
// 左上角: 条件高亮, 形态
|
||||
int leftUpCount = 0; |
||||
int rightUpCount = 0; |
||||
int leftDownCount = 0; |
||||
GraphHelper.applyRenderingHints(g2d); |
||||
if (paintHighlightGroupMarkWhenExsit(g2d, cell, leftUpCount)) { |
||||
leftUpCount++; |
||||
} |
||||
if (paintPresentMarkWhenExsit(g2d, cell, leftUpCount)) { |
||||
leftUpCount++; |
||||
} |
||||
if (paintPaginationMarkWhenExsit(g2d, cell, width, rightUpCount)) { |
||||
rightUpCount++; |
||||
} |
||||
paintWidgetMarkWhenExsit(g2d, cell, width, height); |
||||
paintExpandMarkWhenExsit(g2d, cell); |
||||
Object value = cell.getValue(); |
||||
if (value == null) {// 先判断是否是空.
|
||||
return; |
||||
} |
||||
if (paintResultMarkWhenExsit(g2d, value, width, rightUpCount)) { |
||||
rightUpCount++; |
||||
} |
||||
|
||||
if (paintDSColumnParametermarkWhenExsit(g2d, value, height, leftDownCount)) { |
||||
leftDownCount++; |
||||
} |
||||
|
||||
if (paintDSColumnConditionmarkWhenExsit(g2d, value, height, leftDownCount)) { |
||||
leftDownCount++; |
||||
} |
||||
// 画value,但因为是在Grid里面画,所以画Formula.content
|
||||
if (value instanceof BaseFormula) { |
||||
value = ((BaseFormula) value).getContent(); |
||||
} |
||||
if (value instanceof ImageWithSuffix) { |
||||
value = ((ImageWithSuffix) value).getFineImage(); |
||||
} |
||||
if (value instanceof BaseChartCollection) { |
||||
value = ((BaseChartCollection) value).createResultChartPainterWithOutDealFormula(Calculator.createCalculator(), WebChartIDInfo.createEmptyDesignerInfo(), width, height); |
||||
} |
||||
// Carl:当是子报表时,在格子里画一个子报表的图
|
||||
/* |
||||
* alex:TODO 此处在Grid里面画ChartCollection和SubReport都只画一个图表,这种做法,很不雅 |
||||
*/ |
||||
if (value instanceof ResultSubReport) { |
||||
value = BaseUtils.readImage("/com/fr/base/images/report/painter/subReport.png"); |
||||
GraphHelper.paintImage(g2d, width, height, (Image) value, Constants.IMAGE_CENTER, |
||||
BaseUtils.getAlignment4Horizontal(cell.getStyle(), value), cell.getStyle().getVerticalAlignment(), |
||||
width > 16 ? 16 : width, height > 16 ? 16 : height); |
||||
} else { |
||||
renderContent(g2d, value, cell.getStyle(), width, height, resolution); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static void renderContent(Graphics2D g2d, Object value, Style style, int width, int height, int resolution) { |
||||
if (value != null && width != 0 && height != 0) { |
||||
if (style == null) { |
||||
style = Style.DEFAULT_STYLE.deriveImageLayout(1); |
||||
} |
||||
|
||||
if (value instanceof BaseFormula) { |
||||
value = ((BaseFormula) value).getResult(); |
||||
} |
||||
|
||||
if (value instanceof Painter) { |
||||
((Painter)value).paint(g2d, width, height, resolution, style); |
||||
} else if (value instanceof ImageProvider) { |
||||
Style.paintImageContent(g2d, ((ImageProvider) value).getImage(), style, width, height, resolution); |
||||
} else if (value instanceof Image) { |
||||
Style.paintImageContent(g2d, (Image) value, style, width, height, resolution); |
||||
} else { |
||||
String var6 = Style.valueToText(value, style.getFormat()); |
||||
NewFormStyle.paintCellStyleString2(g2d, width, height, var6, style, resolution); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
private static boolean paintHighlightGroupMarkWhenExsit(Graphics2D g2d, TemplateCellElement cell, int left_up_count) { |
||||
if (cell.getHighlightGroup() != null && cell.getHighlightGroup().size() > 0) { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
|
||||
g2d.setPaint(CELL_HIGHT_LIGHT_MARK_COLOR); |
||||
GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 3); |
||||
polyline.moveTo(0, 0); |
||||
polyline.lineTo(0, CELL_MARK_SIZE); |
||||
polyline.lineTo(CELL_MARK_SIZE, 0); |
||||
GraphHelper.fill(g2d, polyline); |
||||
|
||||
g2d.setPaint(oldPaint); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private static boolean paintPresentMarkWhenExsit(Graphics2D g2d, TemplateCellElement cell, int left_up_count) { |
||||
if (cell.getPresent() != null) { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
|
||||
g2d.setPaint(CELL_PRESENT_MARK_COLOR); |
||||
GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 3); |
||||
polyline.moveTo(0 + left_up_count * CELL_MARK_SIZE, 0); |
||||
polyline.lineTo(0 + left_up_count * CELL_MARK_SIZE, 6); |
||||
polyline.lineTo(CELL_MARK_SIZE + left_up_count * CELL_MARK_SIZE, 0); |
||||
GraphHelper.fill(g2d, polyline); |
||||
|
||||
g2d.setPaint(oldPaint); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private static boolean paintPaginationMarkWhenExsit(Graphics2D g2d, TemplateCellElement cell, int width, int ringt_up_count) { |
||||
// 右上角: 标记是否有分页
|
||||
if (isRightTopMarker(cell)) { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
|
||||
g2d.setPaint(CELL_PAGINATION_MARK_COLOR); |
||||
GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 3); |
||||
polyline.moveTo(width - 1 - ringt_up_count * CELL_MARK_SIZE, 0); |
||||
polyline.lineTo(width - 1 - ringt_up_count * CELL_MARK_SIZE, CELL_MARK_SIZE); |
||||
polyline.lineTo(width - 1 - (ringt_up_count + 1) * CELL_MARK_SIZE, 0); |
||||
GraphHelper.fill(g2d, polyline); |
||||
|
||||
g2d.setPaint(oldPaint); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private static boolean isRightTopMarker(TemplateCellElement cell) { |
||||
return cell.getCellPageAttr() != null && (cell.getCellPageAttr().isPageAfterColumn() |
||||
|| cell.getCellPageAttr().isPageBeforeColumn() |
||||
|| cell.getCellPageAttr().isPageAfterRow() |
||||
|| cell.getCellPageAttr().isPageBeforeRow()); |
||||
} |
||||
|
||||
private static boolean paintResultMarkWhenExsit(Graphics2D g2d, Object value, int width, int ringt_up_count) { |
||||
//右上角标记是否自定义显示
|
||||
if (value instanceof DSColumn && ((DSColumn) value).getResult() != null) { |
||||
if (!ComparatorUtils.equals(((DSColumn) value).getResult(), "$$$")) { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
|
||||
g2d.setPaint(CELL_RESULT_MARK_COLOR); |
||||
GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 3); |
||||
polyline.moveTo(width - ringt_up_count * CELL_MARK_SIZE - 1, 0); |
||||
polyline.lineTo(width - ringt_up_count * CELL_MARK_SIZE - 1, CELL_MARK_SIZE); |
||||
polyline.lineTo(width - (ringt_up_count + 1) * CELL_MARK_SIZE - 1, 0); |
||||
GraphHelper.fill(g2d, polyline); |
||||
|
||||
g2d.setPaint(oldPaint); |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
private static void paintWidgetMarkWhenExsit(Graphics2D g2d, TemplateCellElement cell, int width, int height) { |
||||
// 右下角:是否填报, 设置为4时,三角太小了,不知何故,设置为6
|
||||
if (cell.getWidget() != null) { |
||||
Widget widget = cell.getWidget(); |
||||
Image img = ((ImageIcon) ReportUtils.createWidgetIcon(widget.getClass())).getImage(); |
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.67f)); |
||||
g2d.drawImage(img, width - 15, height - 15, WIDGET_WIDTH, WIDGET_HEIGHT, null); |
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); |
||||
} |
||||
} |
||||
|
||||
private static void paintExpandMarkWhenExsit(Graphics2D g2d, TemplateCellElement cell) { |
||||
CellExpandAttr cellExpandAttr = cell.getCellExpandAttr(); |
||||
if (cellExpandAttr != null) { |
||||
if (cellExpandAttr.getDirection() == Constants.TOP_TO_BOTTOM) { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
g2d.setPaint(CELL_DIRECTION_MARK_COLOR); |
||||
GraphHelper.drawLine(g2d, 2, 0, 2, 5); |
||||
GraphHelper.drawLine(g2d, 2, 5, 0, 2); |
||||
GraphHelper.drawLine(g2d, 2, 5, 4, 2); |
||||
g2d.setPaint(oldPaint); |
||||
} else if (cellExpandAttr.getDirection() == Constants.LEFT_TO_RIGHT) { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
g2d.setPaint(CELL_DIRECTION_MARK_COLOR); |
||||
GraphHelper.drawLine(g2d, 0, 2, 5, 2); |
||||
GraphHelper.drawLine(g2d, 5, 2, 2, 0); |
||||
GraphHelper.drawLine(g2d, 5, 2, 2, 4); |
||||
g2d.setPaint(oldPaint); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static boolean paintDSColumnConditionmarkWhenExsit(Graphics2D g2d, Object value, int height, int left_dowm_count) { |
||||
// 左下角:数据列(DSColumn)相关:比如条件过滤
|
||||
if (value instanceof DSColumn && ((DSColumn) value).getCondition() != null) { |
||||
if (((DSColumn) value).getCondition() instanceof ListCondition && |
||||
((ListCondition) ((DSColumn) value).getCondition()).getJoinConditionCount() == 0) { |
||||
// do nothing
|
||||
} else { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
|
||||
g2d.setPaint(CELL_CONDITION_FILTER_MARK_COLOR); |
||||
GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 3); |
||||
polyline.moveTo(0 + left_dowm_count * CELL_MARK_SIZE, height - 1); |
||||
polyline.lineTo((left_dowm_count + 1) * CELL_MARK_SIZE + 1, height - 1); |
||||
polyline.lineTo(0 + left_dowm_count * CELL_MARK_SIZE, height - 2 - CELL_MARK_SIZE); |
||||
GraphHelper.fill(g2d, polyline); |
||||
|
||||
g2d.setPaint(oldPaint); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private static boolean paintDSColumnParametermarkWhenExsit(Graphics2D g2d, Object value, int height, int left_dowm_count) { |
||||
// 左下角:动态注入参数
|
||||
if (value instanceof DSColumn && ((DSColumn) value).getParameters() != null) { |
||||
if (((DSColumn) value).getParameters().length > 0) { |
||||
Paint oldPaint = g2d.getPaint(); |
||||
|
||||
g2d.setPaint(CELL_PARAMETER_FILTER_MARK_CONLR); |
||||
GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 3); |
||||
polyline.moveTo(0 + left_dowm_count * CELL_MARK_SIZE, height - 1); |
||||
polyline.lineTo((left_dowm_count + 1) * CELL_MARK_SIZE + 1, height - 1); |
||||
polyline.lineTo(0 + left_dowm_count * CELL_MARK_SIZE, height - 2 - CELL_MARK_SIZE); |
||||
GraphHelper.fill(g2d, polyline); |
||||
|
||||
g2d.setPaint(oldPaint); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/* |
||||
* 画悬浮元素 |
||||
* |
||||
* 仅根据宽度 + 高度画 |
||||
*/ |
||||
//b:此方法在grid和tohtml的时候都被调用,所以对formula会有冲突,暂时这么改,应该考虑分开的,也可以根据result来判断,但是那么写好像不妥
|
||||
public static void paintFloatElement(Graphics2D g2d, FloatElement flotEl, int width, int height, int resolution) { |
||||
Style.paintBackground(g2d, flotEl.getStyle(), width, height); |
||||
|
||||
Object value = flotEl.getValue(); |
||||
if (value instanceof BaseFormula) { |
||||
value = ((BaseFormula) value).getContent(); |
||||
} |
||||
if (value instanceof BaseChartCollection) { |
||||
value = ((BaseChartCollection) value).createResultChartPainterWithOutDealFormula(Calculator.createCalculator(), WebChartIDInfo.createEmptyDesignerInfo(), width, height); |
||||
} |
||||
//图片需要切割一下
|
||||
if (value instanceof Image) { |
||||
value = CellUtils.value2ImageWithBackground(value, resolution, flotEl.getStyle(), width, height); |
||||
} |
||||
Style.paintContent(g2d, value, flotEl.getStyle(), width, height, resolution); |
||||
|
||||
Style.paintBorder(g2d, flotEl.getStyle(), width, height); |
||||
} |
||||
|
||||
/* |
||||
* 画悬浮元素flotEl |
||||
* |
||||
* 也就是画三个东西:背景 + 内容 + 边框 |
||||
*/ |
||||
public static void paintFloatElement(Graphics2D g2d, FloatElement flotEl, Rectangle paintRectangle, Rectangle clipRectangle, int resolution) { |
||||
// 画悬浮元素的背景
|
||||
Style.paintBackground(g2d, flotEl.getStyle(), paintRectangle, clipRectangle); |
||||
|
||||
Object value = flotEl.getValue(); |
||||
if (value instanceof ResultChangeWhenExport) { |
||||
value = ((ResultChangeWhenExport) value).changeThis(); |
||||
} |
||||
// 画悬浮元素的内容
|
||||
Style.paintContent(g2d, value, resolution, flotEl.getStyle(), paintRectangle, clipRectangle); |
||||
// 画悬浮元素的边框
|
||||
Style.paintBorder(g2d, flotEl.getStyle(), paintRectangle, clipRectangle); |
||||
} |
||||
|
||||
public static void paintHTMLContent(Graphics2D g2d, String value, int resolution, Style style, Rectangle paintRectangle, Rectangle clipRectangle) { |
||||
Style.paintContent(g2d, createHTMLContentBufferedImage(value, paintRectangle, 0, 0, style), resolution, style, paintRectangle, clipRectangle); |
||||
} |
||||
|
||||
public static void paintTag(Painter painter, Repository repo, int width, int height, Style style, Tag tag) { |
||||
painter.paintTag(repo, width, height, style, tag); |
||||
} |
||||
|
||||
/** |
||||
* 如果用户希望以HTML方式展示String,这个时候先value变成图片 |
||||
* |
||||
* @param value 值 |
||||
* @param paintRectangle 绘制范围 |
||||
* @param x x坐标 |
||||
* @param y y坐标 |
||||
* @param style 当前格子样式 |
||||
* @return BufferedImage 返回图片. |
||||
*/ |
||||
public static BufferedImage createHTMLContentBufferedImage(String value, Rectangle paintRectangle, int x, int y, Style style) { |
||||
return Html2ImageUtils.createHTMLContentBufferedImage(value, paintRectangle, x, y, style); |
||||
} |
||||
|
||||
/** |
||||
* see <code>BaseUtils.getLineTextList</code>, 等于BaseUtils.getLineTextList().size() |
||||
* Denny: 为了提高速度和性能,才单独拿出来的 |
||||
* TODO: 重构 |
||||
* |
||||
* @param text 文本 |
||||
* @param style 样式 |
||||
* @param paintWidth 单元格宽度 |
||||
* @return paintWidth 单位为PT |
||||
*/ |
||||
public static int getLineTextCount(String text, Style style, UNIT paintWidth) { |
||||
if (style.getRotation() != 0) { |
||||
return 1; |
||||
} |
||||
|
||||
|
||||
if (style.getTextStyle() != Style.TEXTSTYLE_WRAPTEXT) { |
||||
return dealNotWrapTextCount(text.toCharArray()); |
||||
} else {// 自动换行
|
||||
return dealWrapTextCount(text, style, paintWidth); |
||||
} |
||||
} |
||||
|
||||
private static int dealNotWrapTextCount(char[] text_chars) { |
||||
boolean remain_chars = false; |
||||
int count = 0; |
||||
for (int t = 0; t < text_chars.length; t++) { |
||||
if (text_chars[t] == '\\') {// 判断是否是 "\n"
|
||||
if (t + 1 < text_chars.length && text_chars[t + 1] == 'n') { |
||||
// 是"\n"字符串,但不是换行符.
|
||||
t++; |
||||
count++; |
||||
if (remain_chars) { |
||||
remain_chars = false; |
||||
} |
||||
} else { |
||||
if (!remain_chars) { |
||||
remain_chars = true; |
||||
} |
||||
} |
||||
} else if (text_chars[t] == '\n' || (text_chars[t] == '\r' && t + 1 < text_chars.length - 1 && text_chars[t + 1] != '\n')) { |
||||
count++; |
||||
if (remain_chars) { |
||||
remain_chars = false; |
||||
} |
||||
} else { |
||||
if (!remain_chars) { |
||||
remain_chars = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 最后一个
|
||||
if (remain_chars) { |
||||
count++; |
||||
} |
||||
|
||||
return count; |
||||
} |
||||
|
||||
// 自动换行
|
||||
//neil:style里面, 默认值padding right = 2时, 默认不生效, 这边算行高时也不要计算入内
|
||||
//临时处理, 去掉左边框线, 因为浏览器计算时需要考虑左边框线宽度, 但这边还是存在问题的
|
||||
//同样需要考虑的是导出和web端展示, padding计算方式也不一致.
|
||||
private static int dealWrapTextCount(String text, Style style, UNIT unitWidth) { |
||||
AutoChangeLineAndDrawProcess process = AutoChangeLineAndDrawManager.getProcess(); |
||||
if (process != null) { |
||||
return process.getAutoChangeLineCount(text, new ObjectHolder(style), unitWidth); |
||||
} |
||||
int count = 0; |
||||
char[] text_chars = text.toCharArray(); |
||||
FontMetrics fontMetrics = getFontMetrics(style); |
||||
double paintWidth = unitWidth.toPixD(Constants.FR_PAINT_RESOLUTION); |
||||
double width = paintWidth - style.getPaddingLeft() - (style.getPaddingRight() == Style.DEFAULT_PADDING ? 0 : style.getPaddingRight()) - style.getBorderLeftWidth(); |
||||
boolean remain_lineText = false; |
||||
int lineTextWidth = 0; |
||||
int wordWidth = 0; |
||||
for (int t = 0, len = text_chars.length; t < len; t++) { |
||||
if (t != 0 && BaseUtils.isNumOrLetter(text_chars[t]) && BaseUtils.isNumOrLetter(text_chars[t - 1])) { |
||||
if (wordWidth + fontMetrics.charWidth(text_chars[t]) > width) { |
||||
if (lineTextWidth > 0) { |
||||
count++; |
||||
remain_lineText = false; |
||||
lineTextWidth = 0; |
||||
} |
||||
count++; |
||||
wordWidth = 0; |
||||
} |
||||
wordWidth += fontMetrics.charWidth(text_chars[t]); |
||||
} else if (isSwitchLine(text_chars, t) || isLN(text_chars, t)) {// 判断是否是 "\n"
|
||||
if (isLN(text_chars, t)) { |
||||
t++;// 忽略'n'字符.// 是"\n"字符串,但不是换行符,依然需要换行.
|
||||
} |
||||
if (lineTextWidth + wordWidth > width && remain_lineText) { |
||||
count += 2; |
||||
} else { |
||||
count++; |
||||
} |
||||
remain_lineText = false; |
||||
lineTextWidth = 0; |
||||
wordWidth = 0; |
||||
} else { |
||||
if (text_chars[t] == '\\' && t + 1 < text_chars.length && text_chars[t + 1] == '\\') {// 判断是否是转义字符'\'
|
||||
t++;// _denny: 增加了转义字符'\\'用来表示\,使"\n"可以输入
|
||||
} |
||||
if (lineTextWidth + wordWidth > width && remain_lineText) { |
||||
count++; |
||||
lineTextWidth = isPunctuationAtLineHead(t, text_chars) ? dealLineWidthWithPunctuation(t, text_chars, fontMetrics) : 0; |
||||
} |
||||
remain_lineText = true; |
||||
lineTextWidth += wordWidth; |
||||
wordWidth = fontMetrics.charWidth(text_chars[t]); |
||||
} |
||||
} |
||||
if (lineTextWidth + wordWidth > width && remain_lineText) { |
||||
count += 2; |
||||
} else { |
||||
count++; |
||||
} |
||||
return count; |
||||
} |
||||
|
||||
/** |
||||
* 标点符号是否在换行后的行首 |
||||
*/ |
||||
private static boolean isPunctuationAtLineHead(int t, char[] text_chars) { |
||||
if (t > 1 && BaseUtils.isPunctuation(text_chars[t - 1])) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 防止有连续多个标点符号,要找一个非标点符号字符 |
||||
* |
||||
* @date 2014-4-17 |
||||
*/ |
||||
private static int dealLineWidthWithPunctuation(int t, char[] text_chars, FontMetrics fontMetrics) { |
||||
if (t < 2) { |
||||
return 0; |
||||
} |
||||
int lineWidth = 0; |
||||
for (int index = t - 2; index >= 0; index--) { |
||||
lineWidth += fontMetrics.charWidth(text_chars[index]); |
||||
if (!BaseUtils.isPunctuation(text_chars[index])) { |
||||
break; |
||||
} |
||||
} |
||||
return lineWidth; |
||||
} |
||||
|
||||
private static boolean isSwitchLine(char[] text_chars, int t) { |
||||
return text_chars[t] == '\n' || (text_chars[t] == '\r' && t + 1 < text_chars.length - 1 && text_chars[t + 1] != '\n'); |
||||
} |
||||
|
||||
private static boolean isLN(char[] text_chars, int t) { |
||||
return text_chars[t] == '\\' && t + 1 < text_chars.length && text_chars[t + 1] == 'n'; |
||||
} |
||||
|
||||
/** |
||||
* Gets the preferred width. |
||||
*/ |
||||
public static UNIT getPreferredWidth(CellElement cell, UNIT height) { |
||||
if (cell == null) { |
||||
return UNIT.ZERO; |
||||
} |
||||
|
||||
Object value = cell.getShowValue(); |
||||
// 只接受Text,Number,和SeparatorPainter
|
||||
// got the text
|
||||
if (value instanceof BaseFormula) { |
||||
if (((BaseFormula) value).getResult() != null) { |
||||
value = ((BaseFormula) value).getResult(); |
||||
} else { |
||||
value = StringUtils.EMPTY; |
||||
} |
||||
} |
||||
Style style = cell.getStyle(); |
||||
if (style == null) { |
||||
style = Style.DEFAULT_STYLE; |
||||
} |
||||
CellGUIAttr cg = cell.getCellGUIAttr() == null ? new CellGUIAttr() : cell.getCellGUIAttr(); |
||||
value = Utils.resolveOtherValue(value, cg.isShowAsImage(), PresentationType.EXPORT); |
||||
String text = Style.valueToText(value, style.getFormat()); |
||||
|
||||
FontMetrics cellFM = getFontMetrics(style); |
||||
//bug 12151 有边框线的单元格 自动调整列宽 会多一行
|
||||
UNIT padding = new PT(style.getPaddingLeft() + style.getPaddingRight()); |
||||
|
||||
if (cg.isShowAsHTML()) { |
||||
return Html2ImageUtils.getHtmlWidth(text, height, style); |
||||
} |
||||
|
||||
return FU.valueOfPix(cellFM.stringWidth(text) + UNIT_SIZE, Constants.FR_PAINT_RESOLUTION).add(padding); |
||||
} |
||||
|
||||
private static FontMetrics getFontMetrics(Style style) { |
||||
Font font = style.getFRFont().applyResolutionNP(Constants.FR_PAINT_RESOLUTION); |
||||
FontProcessor processor = ExtraClassManager.getInstance().getSingle(FontProcessor.MARK_STRING); |
||||
if (processor != null) { |
||||
font = processor.readExtraFont(font); |
||||
} |
||||
return GraphHelper.getFontMetrics(font); |
||||
} |
||||
|
||||
/** |
||||
* Preferred height. (Got the shrink preferred height of CellElement). |
||||
* 单位格的预计算高度 |
||||
* |
||||
* @param cellElement 单元格内容 |
||||
* @param paintWidth 画的宽度 |
||||
* @return UNIT 单位 |
||||
*/ |
||||
public static UNIT analyzeCellElementPreferredHeight(CellElement cellElement, UNIT paintWidth) { |
||||
// 计算高度用显示值
|
||||
Object value = cellElement.getShowValue(); |
||||
// 只接受Text,Number,和SeparatorPainter
|
||||
Style style = cellElement.getStyle(); |
||||
// got the text
|
||||
if (value instanceof BaseFormula) { |
||||
if (((BaseFormula) value).getResult() != null) { |
||||
value = ((BaseFormula) value).getResult(); |
||||
} else { |
||||
value = StringUtils.EMPTY; |
||||
} |
||||
} |
||||
CellGUIAttr cg = cellElement.getCellGUIAttr() == null ? new CellGUIAttr() : cellElement.getCellGUIAttr(); |
||||
if (!(value instanceof String) && !(value instanceof Integer)) { |
||||
value = DataUtils.resolveOtherValue(value, cg.isShowAsImage(), cg.isShowAsDownload(), null, true); |
||||
} |
||||
String text = Style.valueToText(value, style.getFormat()); |
||||
|
||||
if (cg.isShowAsHTML()) { |
||||
return Html2ImageUtils.getHtmlHeight(text, paintWidth, style); |
||||
} |
||||
|
||||
return PaintUtils.analyzeCellElementPreferredHeight(text, style, paintWidth, cg.isShowAsHTML()); |
||||
} |
||||
|
||||
/** |
||||
* 单位格的预计算高度 |
||||
* 单位PT |
||||
* |
||||
* @param text 文本 |
||||
* @param style 格式 |
||||
* @param paintWidth 画的宽度 |
||||
* @param isShowAsHtml 是否以html展示 |
||||
* @return 返回 单位 |
||||
*/ |
||||
private static UNIT analyzeCellElementPreferredHeight(String text, Style style, UNIT paintWidth, boolean isShowAsHtml) { |
||||
if (style == null) { |
||||
//peter:获取默认的Style.
|
||||
style = Style.DEFAULT_STYLE; |
||||
} |
||||
|
||||
// got the text
|
||||
if (text == null || text.length() <= 0) { |
||||
return PT.valueOf(0); |
||||
} |
||||
|
||||
// 变成Line Text List.
|
||||
if (style.getRotation() != 0) { // more easy to paint.
|
||||
// attribute map.
|
||||
return PT.valueOf((float) GraphHelper.stringDimensionWithRotation(text, style.getFRFont(), -style.getRotation(), |
||||
CoreConstants.DEFAULT_FRC).getHeight()); |
||||
} |
||||
// 先获得FontMetics.
|
||||
int lineCount = getLineTextCount(text, style, paintWidth); |
||||
AutoChangeLineAndDrawProcess process = AutoChangeLineAndDrawManager.getProcess(); |
||||
if (process != null) { |
||||
//算了这两个接口分开做
|
||||
return process.getLinedTextHeight(lineCount, new ObjectHolder(style)); |
||||
} |
||||
|
||||
// carl:和paint那边一致,添上段前段后和行间距
|
||||
PT lineSpacing = PT.valueOf(style.getSpacingAfter() + style.getSpacingBefore() + style.getLineSpacing() * lineCount); |
||||
FontMetrics fontMetrics = getFontMetrics(style); |
||||
int textHeight = fontMetrics.getHeight(); |
||||
FU allTextHeight = FU.valueOfPix(textHeight * lineCount, Constants.FR_PAINT_RESOLUTION); |
||||
return lineSpacing.add(allTextHeight);// 需要给底部添加Leading.
|
||||
} |
||||
|
||||
/** |
||||
* 截取文字,只考虑了垂直方向,水平方向没意义且难度大. |
||||
* |
||||
* @param value 画的值 |
||||
* @param style 字体样式格式. |
||||
* @param blockArea 冻结的范围 |
||||
* @param resolution 分辨率 |
||||
* @return 返回的字符串 |
||||
*/ |
||||
public static String clipBlockValue(Object value, Style style, Rectangle primitiveArea, Rectangle blockArea, int resolution, boolean isShowAsHTML) { |
||||
if (value == null) { |
||||
return null; |
||||
} |
||||
if (value instanceof BaseFormula) { |
||||
value = ((BaseFormula) value).getResult(); |
||||
} |
||||
if (blockArea.y >= primitiveArea.height || blockArea.y + blockArea.height <= 0) { |
||||
return null; |
||||
} |
||||
//截取位置,相对于clipArea
|
||||
int startY = blockArea.y > 0 ? blockArea.y : 0; |
||||
int endY = blockArea.y + blockArea.height < primitiveArea.height ? blockArea.y + blockArea.height : primitiveArea.height; |
||||
if (blockArea.x >= primitiveArea.width || blockArea.x + blockArea.width <= 0) { |
||||
return null; |
||||
} |
||||
if (isShowAsHTML) { |
||||
return Html2ImageUtils.clipHtmlContent(value, style, primitiveArea, resolution, startY, endY); |
||||
} |
||||
List lineList = BaseUtils.getLineTextList((String) value, style, style.getFRFont().applyResolutionNP(resolution), primitiveArea.width, resolution); |
||||
if (lineList.isEmpty()) { |
||||
return null; |
||||
} |
||||
double spacingBefore = PT.pt2pix(style.getSpacingBefore(), resolution); |
||||
double spacingAfter = PT.pt2pix(style.getSpacingAfter(), resolution); |
||||
double lineSpacing = PT.pt2pix(style.getLineSpacing(), resolution); |
||||
double lineHeight = lineSpacing + GraphHelper.getFontMetrics(style.getFRFont().applyResolutionNP(resolution)).getHeight(); |
||||
int textAllHeight = (int) (lineHeight * lineList.size() + spacingBefore + spacingAfter); |
||||
//第一行文字距区域高度
|
||||
int textStartY = (int) spacingBefore; |
||||
|
||||
if (style.getVerticalAlignment() == Constants.BOTTOM) { |
||||
textStartY += (primitiveArea.height - textAllHeight); |
||||
} |
||||
if (endY <= textStartY || startY >= textStartY + lineHeight * lineList.size()) { |
||||
return null; |
||||
} |
||||
int lineStart = getLineStart(lineList, lineHeight, textStartY, startY);//截取区域起始行
|
||||
int lineEnd = getLineEnd(lineList, lineHeight, endY, textStartY);//截取区域结束行
|
||||
String text = ""; |
||||
for (; lineStart <= lineEnd; lineStart++) { |
||||
text += lineList.get(lineStart); |
||||
} |
||||
return text; |
||||
} |
||||
|
||||
private static int getLineStart(List lineList, double lineHeight, int textStartY, int startY) { |
||||
int lineStart = 0; |
||||
for (int i = 0; i < lineList.size(); i++) { |
||||
if (textStartY + lineHeight * (i) <= startY && textStartY + lineHeight * (i + 1) > startY) {//压线
|
||||
if (startY - textStartY - lineHeight * (i) > lineHeight / 2) { |
||||
lineStart = i + 1; |
||||
} else { |
||||
lineStart = i; |
||||
} |
||||
} |
||||
} |
||||
return lineStart; |
||||
} |
||||
|
||||
private static int getLineEnd(List lineList, double lineHeight, int endY, int textStartY) { |
||||
int lineEnd = lineList.size() - 1; |
||||
for (int i = 0; i < lineList.size(); i++) { |
||||
if (textStartY + lineHeight * (i) < endY && textStartY + lineHeight * (i + 1) >= endY) {//压线
|
||||
//neil:仿宋,12号字, 行间距8为例, 转为px的行间距大小为10.666, 这边算出的应该有31.98行, 因此要进位
|
||||
if (endY - textStartY - lineHeight * (i) >= lineHeight / 2) { |
||||
lineEnd = i; |
||||
} else { |
||||
lineEnd = i - 1; |
||||
} |
||||
} |
||||
} |
||||
return lineEnd; |
||||
} |
||||
|
||||
/** |
||||
* paintBarcode |
||||
*/ |
||||
public static void paintBarcode(Graphics2D g2d, int width, int height, String text, Style style, BarcodeAttr barcodeAttr) { |
||||
BarcodeImpl barcodeImpl; |
||||
try { |
||||
barcodeImpl = BarCodeUtils.getBarcodeImpl(barcodeAttr, text); |
||||
} catch (BarcodeException exp) { |
||||
try { |
||||
//设置默认值.
|
||||
barcodeImpl = BarCodeUtils.getBarcodeImpl(new BarcodeAttr(), null); |
||||
} catch (BarcodeException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
//字体
|
||||
if (style.getFRFont() != null) { |
||||
barcodeImpl.setFont(style.getFRFont()); |
||||
barcodeImpl.setForeground(style.getFRFont().getForeground()); |
||||
} |
||||
//背景
|
||||
Background background = style.getBackground(); |
||||
if (background != null && background instanceof ColorBackground) { |
||||
barcodeImpl.setBackground(((ColorBackground) background).getColor()); |
||||
} |
||||
|
||||
//根据宽度和高度来确定起始点
|
||||
int pointX = (width - barcodeImpl.getWidth()) / 2; |
||||
int pointY = (height - barcodeImpl.getHeight()) / 2; |
||||
|
||||
barcodeImpl.draw(g2d, pointX, pointY); |
||||
} |
||||
|
||||
/** |
||||
* create font attribute map, 创建属性map |
||||
* |
||||
* @param font 字体 |
||||
* @return map 返回字体创建的Map |
||||
*/ |
||||
public static Map createFontAttributeMap(Font font) { |
||||
Map returnFontAttributeMap = (Map) fontAttributeMapCache.get(font); |
||||
if (returnFontAttributeMap == null) {// create
|
||||
// returnFontAttributeMap.
|
||||
returnFontAttributeMap = font.getAttributes(); |
||||
fontAttributeMapCache.put(font, returnFontAttributeMap); |
||||
} |
||||
|
||||
if (font instanceof FRFont) { |
||||
FRFont frFont = (FRFont) font; |
||||
|
||||
// Strikethrough
|
||||
if (frFont.isStrikethrough()) { |
||||
returnFontAttributeMap.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON); |
||||
} |
||||
} |
||||
|
||||
return returnFontAttributeMap; |
||||
} |
||||
|
||||
} |
@ -1,27 +0,0 @@
|
||||
package com.fr.design.fit; |
||||
|
||||
|
||||
import com.fr.design.file.HistoryTemplateListCache; |
||||
import com.fr.design.fit.common.PaintUtils; |
||||
import com.fr.design.mainframe.JForm; |
||||
import com.fr.grid.CellElementPainter; |
||||
import com.fr.report.cell.TemplateCellElement; |
||||
import com.fr.report.elementcase.ElementCase; |
||||
|
||||
import java.awt.Graphics2D; |
||||
|
||||
/** |
||||
* Created by kerry on 2020-04-21 |
||||
*/ |
||||
public class AdaptiveCellElementPainter extends CellElementPainter { |
||||
|
||||
public void paintContent(Graphics2D g2d, ElementCase report, TemplateCellElement ce, int width, int height, int resolution) { |
||||
if (HistoryTemplateListCache.getInstance().getCurrentEditingTemplate() instanceof JForm) { |
||||
PaintUtils.paintGridCellContent(g2d, ce, width, height, resolution); |
||||
}else { |
||||
super.paintContent(g2d, report, ce, width, height, resolution); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,21 @@
|
||||
package com.fr.design.fit; |
||||
|
||||
import com.fr.design.fit.common.NewUIModeRotationDraw; |
||||
import com.fr.grid.CellElementPainter; |
||||
import com.fr.report.cell.TemplateCellElement; |
||||
import com.fr.report.core.PaintUtils; |
||||
import com.fr.report.elementcase.ElementCase; |
||||
|
||||
import java.awt.Graphics2D; |
||||
|
||||
/** |
||||
* Created by kerry on 2020-04-21 |
||||
*/ |
||||
public class NewUIModeCellElementPainter extends CellElementPainter { |
||||
|
||||
public void paintContent(Graphics2D g2d, ElementCase report, TemplateCellElement ce, int width, int height, int resolution) { |
||||
PaintUtils.paintGridCellContent(g2d, ce, width, height, resolution, new NewUIModeRotationDraw()); |
||||
} |
||||
|
||||
|
||||
} |
@ -1,70 +0,0 @@
|
||||
package com.fr.design.fit.grid; |
||||
|
||||
import com.fr.base.DynamicUnitList; |
||||
import com.fr.design.fit.DesignerUIModeConfig; |
||||
import com.fr.design.mainframe.ElementCasePane; |
||||
import com.fr.grid.GridHeader; |
||||
import com.fr.grid.AbstractGridHeaderMouseHandler; |
||||
import com.fr.report.elementcase.ElementCase; |
||||
import com.fr.report.elementcase.TemplateElementCase; |
||||
|
||||
import java.awt.event.MouseEvent; |
||||
|
||||
public abstract class GridHeaderWithBoundMouseHandler extends AbstractGridHeaderMouseHandler{ |
||||
protected static final int FUZZY_EDGE = 10; |
||||
private int limit; |
||||
|
||||
public GridHeaderWithBoundMouseHandler(GridHeader gHeader, int limit) { |
||||
super(gHeader); |
||||
this.limit = limit; |
||||
} |
||||
|
||||
public void setLimit(int limit) { |
||||
this.limit = limit; |
||||
} |
||||
|
||||
public int getLimit() { |
||||
return limit; |
||||
} |
||||
|
||||
public int getDragIndex(MouseEvent evt) { |
||||
ElementCase report = this.getEditingElementCase(); |
||||
DynamicUnitList sizeList = getSizeList(report); |
||||
|
||||
int scrollValue = getScrollValue(this.getElementCasePane()); |
||||
int scrollExtent = getScrollExtent(this.getElementCasePane()); |
||||
int endValue = scrollValue + scrollExtent + 1; |
||||
|
||||
int beginValue = getBeginValue(this.getElementCasePane()); |
||||
|
||||
double tmpSize1 = 0; |
||||
double tmpSize2; |
||||
double tmpIncreaseSize = 0; |
||||
|
||||
int resolution = DesignerUIModeConfig.getInstance().getScreenResolution(); |
||||
|
||||
for (int index = beginValue; index < endValue; index++) { |
||||
if (index == 0) { |
||||
index = scrollValue; |
||||
} |
||||
|
||||
tmpSize1 += tmpIncreaseSize; |
||||
tmpIncreaseSize = sizeList.get(index).toPixD(resolution); |
||||
tmpSize2 = tmpSize1 + Math.max(1, tmpIncreaseSize); |
||||
if (isOnSeparatorLineIncludeZero(evt, tmpSize2, tmpIncreaseSize) || isOnNormalSeparatorLine(evt, tmpSize2)) { |
||||
return index; |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
public ElementCasePane getElementCasePane() { |
||||
return this.gHeader.getElementCasePane(); |
||||
} |
||||
|
||||
public TemplateElementCase getEditingElementCase() { |
||||
return this.getElementCasePane().getEditingElementCase(); |
||||
} |
||||
|
||||
} |
@ -1,194 +0,0 @@
|
||||
package com.fr.design.fit.grid; |
||||
|
||||
import com.fr.base.DynamicUnitList; |
||||
import com.fr.design.fit.DesignerUIModeConfig; |
||||
import com.fr.design.gui.imenu.UIPopupMenu; |
||||
import com.fr.design.mainframe.ElementCasePane; |
||||
import com.fr.grid.GridColumn; |
||||
import com.fr.grid.GridHeader; |
||||
import com.fr.grid.GridUtils; |
||||
import com.fr.grid.selection.CellSelection; |
||||
import com.fr.grid.selection.Selection; |
||||
import com.fr.report.ReportHelper; |
||||
import com.fr.report.elementcase.ElementCase; |
||||
import com.fr.stable.ColumnRow; |
||||
import com.fr.stable.unit.FU; |
||||
import com.fr.stable.unit.UNIT; |
||||
|
||||
import javax.swing.SwingUtilities; |
||||
import java.awt.Dimension; |
||||
import java.awt.Point; |
||||
import java.awt.Rectangle; |
||||
import java.awt.Toolkit; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* peter:处理对GridColumn的Mouse事件. |
||||
*/ |
||||
public class GridLimitColumnMouseHandler extends GridHeaderWithBoundMouseHandler { |
||||
|
||||
|
||||
public GridLimitColumnMouseHandler(GridColumn gridColumn, int limit) { |
||||
super(gridColumn, limit); |
||||
this.resolution = gridColumn.getResolution(); |
||||
} |
||||
|
||||
@Override |
||||
protected void resetSelectionByRightButton(ColumnRow selectedCellPoint, Selection cs, ElementCasePane ePane) { |
||||
int[] selectedColumns = cs.getSelectedColumns(); |
||||
if (selectedColumns.length == 0 |
||||
|| selectedCellPoint.getColumn() < selectedColumns[0] |
||||
|| selectedCellPoint.getColumn() > selectedColumns[selectedColumns.length - 1]) { |
||||
resetGridSelectionBySelect(selectedCellPoint.getColumn(), ePane); |
||||
} |
||||
} |
||||
|
||||
|
||||
protected int doChooseFrom() { |
||||
return CellSelection.CHOOSE_COLUMN; |
||||
} |
||||
|
||||
@Override |
||||
protected Rectangle resetSelectedBoundsByShift(Rectangle editRectangle, ColumnRow selectedCellPoint, ElementCasePane reportPane) { |
||||
int tempOldSelectedCellX = editRectangle.x;// editRectangle.x;
|
||||
|
||||
// adjust them to got the correct selected bounds.
|
||||
if (selectedCellPoint.getColumn() >= editRectangle.x) { |
||||
selectedCellPoint = ColumnRow.valueOf(selectedCellPoint.getColumn() + 1, selectedCellPoint.getRow()); |
||||
} else { |
||||
tempOldSelectedCellX++; |
||||
} |
||||
|
||||
int lastRow = GridUtils.getAdjustLastColumnRowOfReportPane(reportPane).getRow(); |
||||
return new Rectangle(Math.min(tempOldSelectedCellX, selectedCellPoint.getColumn()), 0, Math.max(editRectangle.width, Math.abs(tempOldSelectedCellX |
||||
- selectedCellPoint.getColumn())), lastRow); |
||||
} |
||||
|
||||
@Override |
||||
protected int[] getGridSelectionIndices(CellSelection cs) { |
||||
return cs.getSelectedColumns(); |
||||
} |
||||
|
||||
@Override |
||||
protected int getScrollValue(ElementCasePane casePane) { |
||||
return casePane.getGrid().getHorizontalValue(); |
||||
} |
||||
|
||||
@Override |
||||
protected int getScrollExtent(ElementCasePane casePane) { |
||||
return casePane.getGrid().getHorizontalExtent(); |
||||
} |
||||
|
||||
@Override |
||||
protected int getBeginValue(ElementCasePane casePane) { |
||||
return casePane.getGrid().getHorizontalBeginValue(); |
||||
} |
||||
|
||||
@Override |
||||
protected int getColumnOrRowByGridHeader(ColumnRow selectedCellPoint) { |
||||
return selectedCellPoint.getColumn(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Checks whether is on zero separator line. |
||||
*/ |
||||
@Override |
||||
protected boolean isOnSeparatorLineIncludeZero(MouseEvent evt, double tmpWidth2, double tmpIncreaseWidth) { |
||||
return tmpIncreaseWidth <= 1 && (evt.getX() >= tmpWidth2 + 2 && (evt.getX() <= tmpWidth2 + SEPARATOR_GAP)); |
||||
} |
||||
|
||||
@Override |
||||
protected boolean between(MouseEvent evt, double from, double to) { |
||||
return evt.getX() > from && evt.getX() <= to; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether is on normal separator line. |
||||
*/ |
||||
@Override |
||||
protected boolean isOnNormalSeparatorLine(MouseEvent evt, double tmpWidth2) { |
||||
return (evt.getX() >= tmpWidth2 - 2) && (evt.getX() <= tmpWidth2 + 2); |
||||
} |
||||
|
||||
@Override |
||||
protected int evtOffset(MouseEvent evt, int offset) { |
||||
return evt.getX() - offset; |
||||
} |
||||
|
||||
@Override |
||||
protected DynamicUnitList getSizeList(ElementCase elementCase) { |
||||
return ReportHelper.getColumnWidthList(elementCase); |
||||
} |
||||
|
||||
@Override |
||||
protected String methodName() { |
||||
return "setColumnWidth"; |
||||
} |
||||
|
||||
@Override |
||||
protected String getSelectedHeaderTooltip(int selectedColumnCount) { |
||||
return selectedColumnCount + "C"; |
||||
} |
||||
|
||||
@Override |
||||
protected Point getTipLocationByMouseEvent(MouseEvent evt, GridHeader gHeader, Dimension tipPreferredSize) { |
||||
Point convertPoint = new Point(evt.getX(), 0); |
||||
SwingUtilities.convertPointToScreen(convertPoint, gHeader); |
||||
|
||||
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); |
||||
convertPoint.x = Math.max(0, Math.min(convertPoint.x - tipPreferredSize.width / 2, screenSize.width - tipPreferredSize.width)); |
||||
convertPoint.y = convertPoint.y - tipPreferredSize.height - 2; |
||||
|
||||
return convertPoint; |
||||
} |
||||
|
||||
@Override |
||||
protected void resetGridSelectionBySelect(int column, ElementCasePane ePane) { |
||||
int lastRow = GridUtils.getAdjustLastColumnRowOfReportPane(ePane).getRow(); |
||||
CellSelection cellSelection = new CellSelection(column, 0, 1, lastRow); |
||||
cellSelection.setSelectedType(CellSelection.CHOOSE_COLUMN); |
||||
ePane.setSelection(cellSelection); |
||||
} |
||||
|
||||
@Override |
||||
protected String nameOfMoveCursorGIF() { |
||||
return "cursor_hmove"; |
||||
} |
||||
|
||||
@Override |
||||
protected String nameOfSelectCursorGIF() { |
||||
return "cursor_hselect"; |
||||
} |
||||
|
||||
@Override |
||||
protected String nameOfSplitCursorGIF() { |
||||
return "cursor_hsplit"; |
||||
} |
||||
|
||||
@Override |
||||
protected UIPopupMenu createPopupMenu(ElementCasePane reportPane, |
||||
MouseEvent evt, int columnIndex) { |
||||
return ElementCasePaneUtil.createColumnPopupMenu(reportPane, evt, columnIndex); |
||||
} |
||||
|
||||
@Override |
||||
protected void resetGridSelectionByDrag(CellSelection gridSelection, ElementCasePane reportPane, |
||||
int startMultiSelectIndex, int endMultiSelectIndex) { |
||||
int lastRow = GridUtils.getAdjustLastColumnRowOfReportPane(reportPane).getRow(); |
||||
gridSelection.setLastRectangleBounds(Math.min(endMultiSelectIndex, startMultiSelectIndex), 0, Math.abs(startMultiSelectIndex - endMultiSelectIndex) + 1, lastRow); |
||||
} |
||||
|
||||
@Override |
||||
public void mouseReleased(MouseEvent e) { |
||||
super.mouseReleased(e); |
||||
int resolution = DesignerUIModeConfig.getInstance().getScreenResolution(); |
||||
int dragIndex = getDragIndex(e); |
||||
if (Math.abs(e.getX() - getLimit()) < FUZZY_EDGE && dragIndex >= 0) { |
||||
UNIT oldValue = this.getEditingElementCase().getColumnWidth(dragIndex); |
||||
this.getEditingElementCase().setColumnWidth(dragIndex, FU.valueOfPix(oldValue.toPixI(resolution) + getLimit() - e.getX(), resolution)); |
||||
} |
||||
this.getElementCasePane().repaint(); |
||||
} |
||||
|
||||
} |
@ -1,190 +0,0 @@
|
||||
package com.fr.design.fit.grid; |
||||
|
||||
import com.fr.base.DynamicUnitList; |
||||
import com.fr.design.fit.DesignerUIModeConfig; |
||||
import com.fr.design.gui.imenu.UIPopupMenu; |
||||
import com.fr.design.mainframe.ElementCasePane; |
||||
import com.fr.grid.GridHeader; |
||||
import com.fr.grid.GridRow; |
||||
import com.fr.grid.GridUtils; |
||||
import com.fr.grid.selection.CellSelection; |
||||
import com.fr.grid.selection.Selection; |
||||
import com.fr.report.ReportHelper; |
||||
import com.fr.report.elementcase.ElementCase; |
||||
import com.fr.stable.ColumnRow; |
||||
import com.fr.stable.unit.FU; |
||||
import com.fr.stable.unit.UNIT; |
||||
|
||||
import javax.swing.SwingUtilities; |
||||
import java.awt.Dimension; |
||||
import java.awt.Point; |
||||
import java.awt.Rectangle; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* peter:处理对GridRow的Mouse事件. |
||||
*/ |
||||
public class GridLimitRowMouseHandler extends GridHeaderWithBoundMouseHandler { |
||||
|
||||
public GridLimitRowMouseHandler(GridRow gridRow, int limit) { |
||||
super(gridRow, limit); |
||||
} |
||||
|
||||
@Override |
||||
protected void resetSelectionByRightButton(ColumnRow selectedCellPoint, Selection cs, ElementCasePane ePane) { |
||||
int[] selectedRows = cs.getSelectedRows(); |
||||
if (selectedRows.length == 0 |
||||
|| selectedCellPoint.getRow() < selectedRows[0] |
||||
|| selectedCellPoint.getRow() > selectedRows[selectedRows.length - 1]) { |
||||
resetGridSelectionBySelect(selectedCellPoint.getRow(), ePane); |
||||
} |
||||
} |
||||
|
||||
|
||||
protected int doChooseFrom() { |
||||
return CellSelection.CHOOSE_ROW; |
||||
} |
||||
|
||||
@Override |
||||
protected int getScrollValue(ElementCasePane casePane) { |
||||
return casePane.getGrid().getVerticalValue(); |
||||
} |
||||
|
||||
@Override |
||||
protected int getScrollExtent(ElementCasePane casePane) { |
||||
return casePane.getGrid().getVerticalExtent(); |
||||
} |
||||
|
||||
@Override |
||||
protected int getBeginValue(ElementCasePane casePane) { |
||||
return casePane.getGrid().getVerticalBeginValue(); |
||||
} |
||||
|
||||
@Override |
||||
protected Rectangle resetSelectedBoundsByShift(Rectangle editRectangle, ColumnRow selectedCellPoint, ElementCasePane reportPane) { |
||||
int tempOldSelectedCellY = editRectangle.y;// editRectangle.x;
|
||||
|
||||
// ajust them to got the correct selected bounds.
|
||||
if (selectedCellPoint.getRow() >= editRectangle.y) { |
||||
selectedCellPoint = ColumnRow.valueOf(selectedCellPoint.getColumn(), selectedCellPoint.getRow() + 1); |
||||
} else { |
||||
tempOldSelectedCellY++; |
||||
} |
||||
|
||||
int lastColumn = GridUtils.getAdjustLastColumnRowOfReportPane(reportPane).getColumn(); |
||||
return new Rectangle(0, Math.min(tempOldSelectedCellY, selectedCellPoint.getRow()), |
||||
lastColumn, Math.max(editRectangle.height, Math.abs(tempOldSelectedCellY - selectedCellPoint.getRow()))); |
||||
} |
||||
|
||||
@Override |
||||
protected int[] getGridSelectionIndices(CellSelection cs) { |
||||
return cs.getSelectedRows(); |
||||
} |
||||
|
||||
@Override |
||||
protected int getColumnOrRowByGridHeader(ColumnRow selectedCellPoint) { |
||||
return selectedCellPoint.getRow(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected void resetGridSelectionBySelect(int row, ElementCasePane ePane) { |
||||
int lastColumn = GridUtils.getAdjustLastColumnRowOfReportPane(ePane).getColumn(); |
||||
CellSelection cellSelection = new CellSelection(0, row, lastColumn, 1); |
||||
cellSelection.setSelectedType(CellSelection.CHOOSE_ROW); |
||||
ePane.setSelection(cellSelection); |
||||
} |
||||
|
||||
/** |
||||
* Checks whether is on zero separator line. |
||||
*/ |
||||
@Override |
||||
protected boolean isOnSeparatorLineIncludeZero(MouseEvent evt, double tmpHeight2, double tmpIncreaseHeight) { |
||||
return tmpIncreaseHeight <= 1 && (evt.getY() >= tmpHeight2 + 2 && evt.getY() <= tmpHeight2 + SEPARATOR_GAP); |
||||
} |
||||
|
||||
@Override |
||||
protected boolean between(MouseEvent evt, double from, double to) { |
||||
return evt.getY() > from && evt.getY() <= to; |
||||
} |
||||
|
||||
@Override |
||||
protected DynamicUnitList getSizeList(ElementCase elementCase) { |
||||
return ReportHelper.getRowHeightList(elementCase); |
||||
} |
||||
|
||||
@Override |
||||
protected String methodName() { |
||||
return "setRowHeight"; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether is on normal separator line. |
||||
*/ |
||||
@Override |
||||
protected boolean isOnNormalSeparatorLine(MouseEvent evt, double tmpHeight2) { |
||||
return (evt.getY() >= tmpHeight2 - 2) && (evt.getY() <= tmpHeight2 + 2); |
||||
} |
||||
|
||||
@Override |
||||
protected int evtOffset(MouseEvent evt, int offset) { |
||||
return evt.getY() - offset; |
||||
} |
||||
|
||||
@Override |
||||
protected String getSelectedHeaderTooltip(int rowSelectedCount) { |
||||
return rowSelectedCount + "R"; |
||||
} |
||||
|
||||
@Override |
||||
protected Point getTipLocationByMouseEvent(MouseEvent evt, GridHeader gHeader, Dimension tipPreferredSize) { |
||||
Point convertPoint = new Point(0, evt.getY()); |
||||
SwingUtilities.convertPointToScreen(convertPoint, gHeader); |
||||
|
||||
convertPoint.x = convertPoint.x + gHeader.getSize().width + 2; |
||||
convertPoint.y = convertPoint.y - tipPreferredSize.height / 2; |
||||
|
||||
return convertPoint; |
||||
} |
||||
|
||||
@Override |
||||
protected String nameOfMoveCursorGIF() { |
||||
return "cursor_vmove"; |
||||
} |
||||
|
||||
@Override |
||||
protected String nameOfSelectCursorGIF() { |
||||
return "cursor_vselect"; |
||||
} |
||||
|
||||
@Override |
||||
protected String nameOfSplitCursorGIF() { |
||||
return "cursor_vsplit"; |
||||
} |
||||
|
||||
@Override |
||||
protected UIPopupMenu createPopupMenu(ElementCasePane reportPane, |
||||
MouseEvent evt, int rowIndex) { |
||||
return ElementCasePaneUtil.createRowPopupMenu(reportPane, evt, rowIndex); |
||||
} |
||||
|
||||
@Override |
||||
protected void resetGridSelectionByDrag(CellSelection gridSelection, ElementCasePane reportPane, |
||||
int startMultiSelectIndex, int endMultiSelectIndex) { |
||||
int lastColumn = GridUtils.getAdjustLastColumnRowOfReportPane(reportPane).getColumn(); |
||||
gridSelection.setLastRectangleBounds(0, Math.min(endMultiSelectIndex, startMultiSelectIndex), lastColumn, Math.abs(startMultiSelectIndex - endMultiSelectIndex) + 1); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void mouseReleased(MouseEvent e) { |
||||
super.mouseReleased(e); |
||||
int resolution = DesignerUIModeConfig.getInstance().getScreenResolution(); |
||||
int dragIndex = getDragIndex(e); |
||||
if (Math.abs(e.getY() - getLimit()) < FUZZY_EDGE && dragIndex >= 0) { |
||||
UNIT oldValue = this.getEditingElementCase().getRowHeight(dragIndex); |
||||
this.getEditingElementCase().setRowHeight(dragIndex, FU.valueOfPix(oldValue.toPixI(resolution) + getLimit() - e.getY(), resolution)); |
||||
} |
||||
this.getElementCasePane().repaint(); |
||||
} |
||||
} |
@ -1,201 +0,0 @@
|
||||
package com.fr.design.fit.grid; |
||||
|
||||
import com.fr.design.designer.creator.XElementCase; |
||||
import com.fr.design.fit.AdaptiveCellElementPainter; |
||||
import com.fr.design.fit.DesignerUIModeConfig; |
||||
import com.fr.design.fit.common.FormDesignerUtil; |
||||
import com.fr.design.mainframe.ElementCasePane; |
||||
import com.fr.design.mainframe.FormDesigner; |
||||
import com.fr.grid.CellElementPainter; |
||||
import com.fr.grid.Grid; |
||||
import com.fr.grid.GridColumn; |
||||
import com.fr.grid.GridRow; |
||||
import com.fr.grid.GridUI; |
||||
import com.fr.report.elementcase.TemplateElementCase; |
||||
import com.fr.report.worksheet.FormElementCase; |
||||
import com.fr.stable.Constants; |
||||
import com.fr.stable.GraphDrawHelper; |
||||
|
||||
import javax.swing.JComponent; |
||||
import java.awt.Color; |
||||
import java.awt.Graphics; |
||||
import java.awt.Graphics2D; |
||||
import java.awt.Insets; |
||||
import java.awt.Rectangle; |
||||
import java.awt.event.MouseListener; |
||||
import java.awt.event.MouseMotionListener; |
||||
import java.awt.event.MouseWheelListener; |
||||
|
||||
|
||||
/** |
||||
* Created by kerry on 2020-04-14 |
||||
*/ |
||||
public class NewFormDesignerGridUI extends GridUI { |
||||
private GridLimitColumnMouseHandler gridColumnMouseHandler; |
||||
private GridLimitRowMouseHandler gridRowMouseHandler; |
||||
private AdaptiveGridListener adaptiveGridListener; |
||||
private FormDesigner designer; |
||||
|
||||
public NewFormDesignerGridUI(FormDesigner designer, int resolution) { |
||||
super(resolution); |
||||
this.designer = designer; |
||||
this.setCellElementPainter(new AdaptiveCellElementPainter()); |
||||
} |
||||
|
||||
public void setCellElementPainter(CellElementPainter elementPainter) { |
||||
this.painter = elementPainter; |
||||
} |
||||
|
||||
public void paint(Graphics g, JComponent c) { |
||||
Graphics2D g2d = (Graphics2D) g; |
||||
Grid grid = (Grid) c; |
||||
// 取得ElementCasePane.ElementCase
|
||||
ElementCasePane elementCasePane = grid.getElementCasePane(); |
||||
final TemplateElementCase elementCase = elementCasePane.getEditingElementCase(); |
||||
|
||||
super.paint(g, c); |
||||
|
||||
if (!(elementCase instanceof FormElementCase)) { |
||||
return; |
||||
} |
||||
final Rectangle rectangle = getBoundsLineRect(elementCase, grid); |
||||
int width = getScaleWidth(rectangle.width) - columnWidthList.getRangeValue(0, horizontalValue).toPixI(resolution); |
||||
int height = getScaleHeight(rectangle.height) - rowHeightList.getRangeValue(0, verticalValue).toPixI(resolution); |
||||
drawBoundsLine(g2d, width, height); |
||||
addListener(grid, elementCasePane, width, height, rectangle.width, rectangle.height); |
||||
} |
||||
|
||||
private int getScaleWidth(int width) { |
||||
return width * resolution / DesignerUIModeConfig.getInstance().getScreenResolution(); |
||||
|
||||
} |
||||
|
||||
private int getScaleHeight(int height) { |
||||
return height * resolution / DesignerUIModeConfig.getInstance().getScreenResolution(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取需要画线的矩形大小 |
||||
*/ |
||||
private Rectangle getBoundsLineRect(TemplateElementCase elementCase, Grid grid) { |
||||
final Rectangle rectangle = new Rectangle(); |
||||
XElementCase xElementCase = FormDesignerUtil.getXelementCase(designer.getRootComponent(), (FormElementCase) elementCase); |
||||
if (xElementCase != null) { |
||||
rectangle.setBounds(xElementCase.getBounds()); |
||||
|
||||
//减去内边距的宽和高
|
||||
Insets insets = xElementCase.getInsets(); |
||||
rectangle.width -= insets.left + insets.right; |
||||
rectangle.height -= insets.top + insets.bottom; |
||||
|
||||
} |
||||
return rectangle; |
||||
} |
||||
|
||||
|
||||
private void addListener(Grid grid, ElementCasePane elementCasePane, int width, int height, int actualWidth, int actualHeight) { |
||||
addGridColumnListener(elementCasePane.getGridColumn(), width); |
||||
addGridRowListener(elementCasePane.getGridRow(), height); |
||||
addMouseListener(grid, width, height, actualWidth, actualHeight); |
||||
} |
||||
|
||||
|
||||
private void drawBoundsLine(Graphics2D g2d, int width, int height) { |
||||
g2d.setPaint(Color.black); |
||||
g2d.setStroke(GraphDrawHelper.getStroke(Constants.LINE_DASH_DOT)); |
||||
g2d.drawLine(0, height, width, height); |
||||
g2d.drawLine(width, 0, width, height); |
||||
} |
||||
|
||||
private void removeGridColumnListener(GridColumn column) { |
||||
MouseMotionListener[] mouseMotionListeners = column.getMouseMotionListeners(); |
||||
for (MouseMotionListener mouseMotionListener : mouseMotionListeners) { |
||||
if (mouseMotionListener instanceof com.fr.grid.GridColumnMouseHandler || mouseMotionListener instanceof GridLimitColumnMouseHandler) { |
||||
column.removeMouseMotionListener(mouseMotionListener); |
||||
} |
||||
} |
||||
MouseListener[] mouseListeners = column.getMouseListeners(); |
||||
for (MouseListener motionListener : mouseListeners) { |
||||
if (motionListener instanceof com.fr.grid.GridColumnMouseHandler || motionListener instanceof GridLimitColumnMouseHandler) { |
||||
column.removeMouseListener(motionListener); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void removeGridRowListener(GridRow row) { |
||||
MouseMotionListener[] mouseMotionListeners = row.getMouseMotionListeners(); |
||||
for (MouseMotionListener mouseMotionListener : mouseMotionListeners) { |
||||
if (mouseMotionListener instanceof com.fr.grid.GridRowMouseHandler || mouseMotionListener instanceof GridLimitRowMouseHandler) { |
||||
row.removeMouseMotionListener(mouseMotionListener); |
||||
} |
||||
} |
||||
MouseListener[] mouseListeners = row.getMouseListeners(); |
||||
for (MouseListener motionListener : mouseListeners) { |
||||
if (motionListener instanceof com.fr.grid.GridRowMouseHandler || motionListener instanceof GridLimitRowMouseHandler) { |
||||
row.removeMouseListener(motionListener); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void removeGridListener(Grid grid) { |
||||
MouseMotionListener[] mouseMotionListeners = grid.getMouseMotionListeners(); |
||||
for (MouseMotionListener mouseMotionListener : mouseMotionListeners) { |
||||
if (mouseMotionListener instanceof AdaptiveGridListener) { |
||||
grid.removeMouseMotionListener(mouseMotionListener); |
||||
break; |
||||
} |
||||
} |
||||
MouseListener[] mouseListeners = grid.getMouseListeners(); |
||||
for (MouseListener motionListener : mouseListeners) { |
||||
if (motionListener instanceof AdaptiveGridListener) { |
||||
grid.removeMouseListener(motionListener); |
||||
break; |
||||
} |
||||
} |
||||
MouseWheelListener[] mouseWheelListeners = grid.getMouseWheelListeners(); |
||||
for (MouseWheelListener mouseWheelListener : mouseWheelListeners) { |
||||
if (mouseWheelListener instanceof AdaptiveGridListener) { |
||||
grid.removeMouseWheelListener(mouseWheelListener); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void addGridColumnListener(GridColumn column, int width) { |
||||
if (gridColumnMouseHandler != null) { |
||||
gridColumnMouseHandler.setLimit(width); |
||||
return; |
||||
} |
||||
removeGridColumnListener(column); |
||||
gridColumnMouseHandler = new GridLimitColumnMouseHandler(column, width); |
||||
column.addMouseListener(gridColumnMouseHandler); |
||||
column.addMouseMotionListener(gridColumnMouseHandler); |
||||
} |
||||
|
||||
|
||||
private void addGridRowListener(GridRow row, int height) { |
||||
if (gridRowMouseHandler != null) { |
||||
gridRowMouseHandler.setLimit(height); |
||||
return; |
||||
} |
||||
removeGridRowListener(row); |
||||
gridRowMouseHandler = new GridLimitRowMouseHandler(row, height); |
||||
row.addMouseMotionListener(gridRowMouseHandler); |
||||
row.addMouseListener(gridRowMouseHandler); |
||||
} |
||||
|
||||
|
||||
private void addMouseListener(Grid grid, int width, int height, int actualWidth, int actualHeight) { |
||||
if (adaptiveGridListener != null) { |
||||
adaptiveGridListener.resetBoundInfo(width, height, actualWidth, actualHeight); |
||||
return; |
||||
} |
||||
removeGridListener(grid); |
||||
adaptiveGridListener = new AdaptiveGridListener(grid, width, height, actualWidth, actualHeight); |
||||
grid.addMouseMotionListener(adaptiveGridListener); |
||||
grid.addMouseListener(adaptiveGridListener); |
||||
grid.addMouseWheelListener(adaptiveGridListener); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue