package com.fr.grid.selection; import com.fr.base.BaseFormula; import com.fr.base.Utils; import com.fr.base.vcs.DesignerMode; import com.fr.cache.list.IntList; import com.fr.design.actions.cell.CellAttributeAction; import com.fr.design.actions.cell.CellExpandAttrAction; import com.fr.design.actions.cell.CellStyleAttrAction; import com.fr.design.actions.cell.CellWidgetAttrAction; import com.fr.design.actions.cell.CleanAuthorityAction; import com.fr.design.actions.cell.ConditionAttributesAction; import com.fr.design.actions.cell.EditCellAction; import com.fr.design.actions.core.ActionFactory; import com.fr.design.actions.edit.CopyAction; import com.fr.design.actions.edit.CutAction; import com.fr.design.actions.edit.HyperlinkAction; import com.fr.design.actions.edit.PasteAction; import com.fr.design.actions.utils.DeprecatedActionManager; import com.fr.design.cell.clipboard.CellElementsClip; import com.fr.design.cell.clipboard.ElementsTransferable; import com.fr.design.designer.TargetComponent; import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.mainframe.CellElementPropertyPane; import com.fr.design.mainframe.CellWidgetPropertyPane; import com.fr.design.mainframe.ElementCasePane; import com.fr.design.mainframe.ElementCasePane.Clear; import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.theme.utils.DefaultThemedTemplateCellElementCase; import com.fr.design.report.RowColumnPane; import com.fr.design.selection.QuickEditor; import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils; import com.fr.grid.GridUtils; import com.fr.report.cell.CellElement; import com.fr.report.cell.DefaultTemplateCellElement; import com.fr.report.cell.TemplateCellElement; import com.fr.report.cell.cellattr.CellGUIAttr; import com.fr.report.elementcase.TemplateElementCase; import com.fr.stable.ColumnRow; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.unit.FU; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import java.awt.Rectangle; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * the cell selection (column,row)是所选单元格中左上角的位置 , 这个数据结构就是一个Rectangle * * @editor zhou 2012-3-22下午1:53:59 */ public class CellSelection extends Selection { public static final int NORMAL = 0; public static final int CHOOSE_COLUMN = 1; public static final int CHOOSE_ROW = 2; private int column; private int row; private int columnSpan; private int rowSpan; private int selectedType = NORMAL; private Rectangle editRectangle = new Rectangle(0, 0, 1, 1); private List cellRectangleList = new ArrayList(); private Set<TemplateCellElement> cellElements = new HashSet<>(); public CellSelection() { this(0, 0, 1, 1); //this.cellRectangleList.add(new Rectangle(0, 0, 1, 1)); } public CellSelection(int column, int row, int columnSpan, int rowSpan) { setBounds(column, row, columnSpan, rowSpan); this.cellRectangleList.add(new Rectangle(column, row, columnSpan, rowSpan)); } public final void setBounds(int column, int row, int columnSpan, int rowSpan) { this.column = column; this.row = row; this.columnSpan = columnSpan; this.rowSpan = rowSpan; editRectangle.setBounds(column, row, columnSpan, rowSpan); } public void setLastRectangleBounds(int column, int row, int columnSpan, int rowSpan) { this.column = column; this.row = row; this.columnSpan = columnSpan; this.rowSpan = rowSpan; if (!cellRectangleList.isEmpty()) { ((Rectangle) cellRectangleList.get(cellRectangleList.size() - 1)).setBounds(column, row, columnSpan, rowSpan); } } public void setSelectedType(int chooseType) { this.selectedType = chooseType; } public int getSelectedType() { return selectedType; } /** * 增加选中的区域 * * @param cellRectangle 区域 */ public void addCellRectangle(Rectangle cellRectangle) { int index = this.cellRectangleList.indexOf(cellRectangle); if (index != -1) { this.cellRectangleList.remove(index); } this.cellRectangleList.add(cellRectangle); } /** * Gets edit rectangle */ public Rectangle getEditRectangle() { return this.editRectangle; } /** * Gets the only cell rectangle */ public Rectangle getFirstCellRectangle() { //p:这里不判断尺寸,直接留着抛错,在type==CELL的时候,List长度一定大于0. return (Rectangle) this.cellRectangleList.get(0); } /** * Gets the last cell rectangle */ public Rectangle getLastCellRectangle() { return (Rectangle) this.cellRectangleList.get(this.cellRectangleList.size() - 1); } /** * Gets the count of cell rectangle */ public int getCellRectangleCount() { return this.cellRectangleList.size(); } /** * Gets the cell rectangle at given position */ public Rectangle getCellRectangle(int index) { return (Rectangle) this.cellRectangleList.get(index); } /** * 清除区域块 * * @param i 区域块 */ public void clearCellRectangles(int i) { this.cellRectangleList.remove(i); } /** * 包含单元格 * * @param column 列 * @param row 行 * @return 若不包含返回-1 */ public int containsCell(int column, int row) { for (int i = 0; i < this.cellRectangleList.size(); i++) { Rectangle tmpRectangle = (Rectangle) this.cellRectangleList.get(i); if (tmpRectangle.contains(column, row)) { return i; } } return -1; } public int getColumn() { return column; } public int getRow() { return row; } public int getColumnSpan() { return columnSpan; } public int getRowSpan() { return rowSpan; } /** * 转换成矩形 * * @return 矩形 */ public Rectangle toRectangle() { return new Rectangle(column, row, columnSpan, rowSpan); } /** * 是否选择一个单元格 * * @param ePane 区域 * @return 是则返回rue */ public boolean isSelectedOneCell(ElementCasePane ePane) { if (getCellRectangleCount() > 1) { return false; } if (columnSpan == 1 && rowSpan == 1) { return true; } TemplateElementCase ec = ePane.getEditingElementCase(); Iterator containedCellElementIterator = ec.intersect(column, row, columnSpan, rowSpan); while (containedCellElementIterator.hasNext()) { CellElement cellElement = (CellElement) containedCellElementIterator.next(); if (cellElement.getColumnSpan() == columnSpan && cellElement.getRowSpan() == rowSpan) { return true; } } return false; } /** * 作为可传输的 * * @param transferable 传输介质 * @param ePane 区域 */ public void asTransferable(ElementsTransferable transferable, ElementCasePane ePane) { java.util.List<TemplateCellElement> list = new java.util.ArrayList<TemplateCellElement>(); TemplateElementCase ec = ePane.getEditingElementCase(); Iterator cells = ec.intersect(column, row, columnSpan, rowSpan); while (cells.hasNext()) { TemplateCellElement cellElement = (TemplateCellElement) cells.next(); list.add((TemplateCellElement) cellElement.deriveCellElement(cellElement.getColumn() - column, cellElement.getRow() - row)); } FU[] columnWidth = new FU[columnSpan]; FU[] rowHeight = new FU[rowSpan]; for (int i = 0; i < columnSpan; i++) { columnWidth[i] = ec.getColumnWidth(this.column + i); } for (int j = 0; j < rowSpan; j++) { rowHeight[j] = ec.getRowHeight(this.row + j); } transferable.addObject(new CellElementsClip(this.columnSpan, this.rowSpan, columnWidth, rowHeight, list.toArray(new TemplateCellElement[list.size()]))); } /** * 黏贴单元格 * * @param ceClip 单元格 * @param ePane 区域 * @return 成功返回true */ @Override public boolean pasteCellElementsClip(CellElementsClip ceClip, ElementCasePane ePane) { TemplateElementCase ec = ePane.getEditingElementCase(); CellSelection cs = ceClip.pasteAt(ec, column, row); if (cs != null) { ePane.setSelection(cs); } return true; } /** * 黏贴字符串 * * @param str 字符串 * @param ePane 区域 * @return 成功返回true */ @Override public boolean pasteString(String str, ElementCasePane ePane) { // 主要需要处理Excel当中的类型. // Excel 的剪贴板格式 // Excel 的剪贴板格式非常简单。它采用制表符分隔同一行上的元素, // 并用换行符分隔行。这样,当您复制一组连续的和/或相邻的单元格时,Excel // 只将电子表格数据标记到一个长字符串中,各个单元格值由该字符串内的制表符和换行符分隔。 // 如果所选的单元格不相邻时怎么办?很简单:Excel 不会让您将所选内容复制到剪贴板。 // set value to current edit cell element. TemplateElementCase ec = ePane.getEditingElementCase(); String[] allTextArray = StableUtils.splitString(str, '\n'); for (int r = 0; r < allTextArray.length; r++) { String[] lineTextArray = StableUtils.splitString(allTextArray[r], '\t'); for (int c = 0; c < lineTextArray.length; c++) { String textValue = lineTextArray[c]; if (textValue.length() > 0 && textValue.charAt(0) == '=') { ec.setCellValue(column + c, row + r, BaseFormula.createFormulaBuilder().build(textValue)); } else { Number number = Utils.string2Number(lineTextArray[c]); if (number != null) { ec.setCellValue(column + c, row + r, number); } else { // alex:对于100,000,000这种数值,先做一个取巧的解决方法 String newStr = Utils.replaceAllString(lineTextArray[c], ",", StringUtils.EMPTY); number = Utils.string2Number(newStr); if (number != null) { ec.setCellValue(column + c, row + r, Utils.string2Number(newStr)); } else { ec.setCellValue(column + c, row + r, lineTextArray[c]); } } } } } ePane.setSelection(new CellSelection(column, row, this.columnSpan, this.rowSpan)); return true; } /** * 黏贴其他 * * @param ob 要黏贴的东西 * @param ePane 区域 * @return 成功返回true */ @Override public boolean pasteOtherType(Object ob, ElementCasePane ePane) { TemplateElementCase ec = ePane.getEditingElementCase(); TemplateCellElement cellElement = ec.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = DefaultThemedTemplateCellElementCase.createInstance(column, row, ob); ec.addCellElement(cellElement, false); } else { cellElement.setValue(ob); } ePane.setSelection(new CellSelection(column, row, 1, 1)); return true; } /** * 是否能合并单元格 * * @param ePane 区域 * @return 是则返回true */ @Override public boolean canMergeCells(ElementCasePane ePane) { return !this.isSelectedOneCell(ePane); } /** * 合并单元格 * * @param ePane 区域 * @return 成功返回true */ @Override public boolean mergeCells(ElementCasePane ePane) { TemplateElementCase ec = ePane.getEditingElementCase(); Iterator cells = ec.intersect(column, row, columnSpan, rowSpan); if (cells.hasNext()) { // alex:有两个以上的格子在这个区域内 int returnValue = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(ePane), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Des_Merger_Cell"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Utils_Merge_Cell"), JOptionPane.OK_CANCEL_OPTION); if (returnValue != JOptionPane.OK_OPTION) { return false; } } int rowStartIndex = row; int rowEndIndex = row + rowSpan - 1; int columnStartIndex = column; int columnEndIndex = column + columnSpan - 1; // 合并已有单元格,还是新建单元格 boolean hasCellElement = false; for (int ri = rowStartIndex; ri <= rowEndIndex; ri++) { for (int ci = columnStartIndex; ci <= columnEndIndex; ci++) { CellElement ce = ec.getCellElement(ci, ri); if (ce != null) { hasCellElement = true; break; } } } if (hasCellElement) { ec.merge(row, row + rowSpan - 1, column, column + columnSpan - 1); } else { ec.addCellElement(DefaultThemedTemplateCellElementCase.createInstance(column, row, columnSpan, rowSpan, null), true); } return true; } /** * 是否撤销合并单元格 * * @param ePane 区域 * @return 是则返回true */ @Override public boolean canUnMergeCells(ElementCasePane ePane) { TemplateElementCase ec = ePane.getEditingElementCase(); Iterator containedCellElementIterator = ec.intersect(column, row, columnSpan, rowSpan); while (containedCellElementIterator.hasNext()) { CellElement cellElement = (CellElement) containedCellElementIterator.next(); if (cellElement.getColumnSpan() > 1 || cellElement.getRowSpan() > 1) { return true; } } return false; } /** * 撤销合并单元格 * * @param ePane 区域 * @return 成功返回true */ @Override public boolean unMergeCells(ElementCasePane ePane) { TemplateElementCase ec = ePane.getEditingElementCase(); Iterator containedCellElementIterator = ec.intersect(column, row, columnSpan, rowSpan); while (containedCellElementIterator.hasNext()) { TemplateCellElement cellElement = (TemplateCellElement) containedCellElementIterator.next(); int columnSpan = cellElement.getColumnSpan(); int rowSpan = cellElement.getRowSpan(); ec.removeCellElement(cellElement); ec.addCellElement((TemplateCellElement) cellElement.deriveCellElement(cellElement.getColumn(), cellElement.getRow(), 1, 1)); for (int kc = cellElement.getColumn(); kc < cellElement.getColumn() + columnSpan; kc++) { for (int kr = cellElement.getRow(); kr < cellElement.getRow() + rowSpan; kr++) { if (kc == cellElement.getColumn() && kr == cellElement.getRow()) { continue; } // 不覆盖以前的元素 ec.addCellElement(DefaultThemedTemplateCellElementCase.createInstance(kc, kr), false); } } } this.setBounds(column, row, 1, 1); return true; } /** * 创建弹出菜单 * * @param ePane 区域 * @return 菜单 */ public UIPopupMenu createPopupMenu(ElementCasePane ePane) { UIPopupMenu popup = new UIPopupMenu(); if (DesignerMode.isAuthorityEditing()) { popup.add(new CleanAuthorityAction(ePane).createMenuItem()); return popup; } popup.add(new EditCellAction(ePane).createMenuItem()); popup.add(DeprecatedActionManager.getCellMenu(ePane).createJMenu()); popup.add(new CellExpandAttrAction().createMenuItem()); popup.add(new CellStyleAttrAction().createMenuItem()); popup.add(DeprecatedActionManager.getPresentMenu(ePane).createJMenu()); popup.add(new CellAttributeAction().createMenuItem()); JTemplate jTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); if (jTemplate.isJWorkBook()) { //表单中报表块编辑屏蔽掉 控件设置 popup.add(new CellWidgetAttrAction().createMenuItem()); } popup.add(new ConditionAttributesAction().createMenuItem()); popup.add(new HyperlinkAction().createMenuItem()); // cut, copy and paste popup.addSeparator(); popup.add(new CutAction(ePane).createMenuItem()); popup.add(new CopyAction(ePane).createMenuItem()); popup.add(new PasteAction(ePane).createMenuItem()); popup.addSeparator(); popup.add(DeprecatedActionManager.getInsertMenu(ePane)); popup.add(DeprecatedActionManager.getDeleteMenu(ePane)); popup.add(DeprecatedActionManager.getClearMenu(ePane)); popup.addSeparator(); addExtraMenu(ePane, popup); return popup; } /** * 清除 * * @param type 要清除的类型 * @param ePane 区域 * @return 成功返回true */ @Override public boolean clear(Clear type, ElementCasePane ePane) { TemplateElementCase ec = ePane.getEditingElementCase(); boolean isClear = true; int cellRectangleCount = getCellRectangleCount(); for (int rect = 0; rect < cellRectangleCount; rect++) { isClear = hasclearCell(type, ec, rect); } return isClear; } private boolean hasclearCell(Clear type, TemplateElementCase ec, int rect) { List<CellElement> removeElementList = new ArrayList<CellElement>(); Rectangle cellRectangle = getCellRectangle(rect); column = cellRectangle.x; row = cellRectangle.y; columnSpan = cellRectangle.width; rowSpan = cellRectangle.height; Iterator cells = ec.intersect(column, row, columnSpan, rowSpan); while (cells.hasNext()) { CellElement cellElement = (CellElement) cells.next(); CellGUIAttr cellGUIAttr = cellElement.getCellGUIAttr(); if (cellGUIAttr == null) { cellGUIAttr = CellGUIAttr.DEFAULT_CELLGUIATTR; } removeElementList.add(cellElement); } if (removeElementList.isEmpty()) { return false; } switch (type) { case ALL: for (int i = 0; i < removeElementList.size(); i++) { CellElement element = removeElementList.get(i); ec.removeCellElement((TemplateCellElement) element); } break; case FORMATS: for (int i = 0; i < removeElementList.size(); i++) { CellElement element = removeElementList.get(i); element.setStyle(null); // fvs调整单元格默认样式 AdjustWorkBookDefaultStyleUtils.adjustCellElement(element); } break; case CONTENTS: for (int i = 0; i < removeElementList.size(); i++) { CellElement element = removeElementList.get(i); element.setValue(null); setDefault(element); } break; case WIDGETS: for (int i = 0; i < removeElementList.size(); i++) { CellElement element = removeElementList.get(i); ((TemplateCellElement) element).setWidget(null); } break; default: break; } return true; } //设置显示内容为default private void setDefault(CellElement element) { CellGUIAttr cellGUIAttr = element.getCellGUIAttr(); if (cellGUIAttr != null) { cellGUIAttr.setShowAsDefault(true); cellGUIAttr.setShowAsHTML(false); cellGUIAttr.setShowAsDownload(false); cellGUIAttr.setShowAsImage(false); } } @Override public int[] getSelectedColumns() { return IntList.range(column, column + columnSpan); } @Override public int[] getSelectedRows() { return IntList.range(row, row + rowSpan); } /** * 向左移动 * * @param ePane 区域 */ public void moveLeft(ElementCasePane ePane) { if (column - 1 < 0) { return; } moveTo(ePane, column - 1, row); } /** * 向右移动 * * @param ePane 区域 */ public void moveRight(ElementCasePane ePane) { moveTo(ePane, column + columnSpan, row); } /** * 向上移动 * * @param ePane 区域 */ public void moveUp(ElementCasePane ePane) { if (row - 1 < 0) { return; } moveTo(ePane, column, row - 1); } /** * 向下移动 * * @param ePane 区域 */ public void moveDown(ElementCasePane ePane) { moveTo(ePane, column, row + rowSpan); } private static void moveTo(ElementCasePane ePane, int column, int row) { if (GridUtils.canMove(ePane, column, row)) { GridUtils.doSelectCell(ePane, column, row); ePane.ensureColumnRowVisible(column, row); } } /** * 触发删除动作 * * @param ePane 区域 * @return 成功返回true */ @Override public boolean triggerDeleteAction(ElementCasePane ePane) { final TemplateElementCase ec = ePane.getEditingElementCase(); final RowColumnPane rcPane = new RowColumnPane(); rcPane.setTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Delete")); rcPane.showWindow(SwingUtilities.getWindowAncestor(ePane), new DialogActionAdapter() { @Override public void doOk() { if (rcPane.isEntireRow()) { int[] rows = CellSelection.this.getSelectedRows(); for (int i = 0; i < rows.length; i++) { ec.removeRow(rows[i] - i); } } else { int[] columns = CellSelection.this.getSelectedColumns(); for (int i = 0; i < columns.length; i++) { ec.removeColumn(columns[i] - i); } } } }).setVisible(true); return true; } /** * 包含行列 * * @param cr 行列 * @return 包含返回true */ @Override public boolean containsColumnRow(ColumnRow cr) { return new Rectangle(column, row, columnSpan, rowSpan).contains(cr.column, cr.row); } @Override public boolean equals(Object obj) { if (!(obj instanceof CellSelection)) { return false; } CellSelection cs = (CellSelection) obj; return this.getColumn() == cs.getColumn() && this.getRow() == cs.getRow() && this.getColumnSpan() == cs.getColumnSpan() && this.getRowSpan() == cs.getRowSpan(); } @Override public CellSelection clone() { CellSelection cs = new CellSelection(column, row, columnSpan, rowSpan); if (this.editRectangle != null) { cs.editRectangle = (Rectangle) this.editRectangle.clone(); } java.util.List newCellRectList = new java.util.ArrayList(this.cellRectangleList.size()); cs.cellRectangleList = newCellRectList; for (int i = 0, len = this.cellRectangleList.size(); i < len; i++) { newCellRectList.add((Rectangle) ((Rectangle) this.cellRectangleList.get(i)).clone()); } cs.selectedType = this.selectedType; return cs; } @Override public QuickEditor getQuickEditor(TargetComponent tc) { QuickEditor editor = getQuickEditorWithoutPopulate(tc); if (editor == null) { return null; } editor.populate(tc); return editor; } @Override public QuickEditor getQuickEditorWithoutPopulate(TargetComponent tc) { ElementCasePane ePane = (ElementCasePane) tc; TemplateElementCase tplEC = ePane.getEditingElementCase(); TemplateCellElement cellElement = tplEC.getTemplateCellElement(column, row); Object value = null; if (cellElement != null) { value = cellElement.getValue(); } cellElements = getAllCellElements(tplEC); boolean sameType = checkSameType(cellElements); // 多选时,多元格元素类型 value = sameType && value != null ? value : StringUtils.EMPTY; //之前是少了个bigInteger,刚kunsnat又发现少了个bigDecimal,数字类型的都用stringEditor,没必要那个样子 QuickEditor editor = ActionFactory.getCellEditor((value instanceof Number) ? (Number.class) : (value.getClass())); return editor; } /** * 选中的单元格插入元素类型是否相同 * * @param cellElements 单元格 * @return true: 相同 */ public boolean checkSameType(Set<TemplateCellElement> cellElements) { Class lastType = null; for (TemplateCellElement cellElement : cellElements) { Object value = cellElement.getValue(); if (value == null) { value = StringUtils.EMPTY; } Class<?> type = value.getClass(); if (lastType != null && lastType != type) { return false; } lastType = type; } return true; } /** * 获取当前选中的所有单元格,若选中未编辑状态的单元格,暂时不添加为编辑状态 * * @param elementCase * @return 获取当前选中的所有单元格 */ public Set<TemplateCellElement> getAllCellElements(TemplateElementCase elementCase) { Set<TemplateCellElement> cellElements = new HashSet<>(); // 遍历选择的rect for (int rect = 0; rect < getCellRectangleCount(); rect++) { Rectangle cellRectangle = getCellRectangle(rect); // 遍历rect中每个ce for (int j = 0; j < cellRectangle.height; j++) { for (int i = 0; i < cellRectangle.width; i++) { int column = i + cellRectangle.x; int row = j + cellRectangle.y; TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); } cellElements.add(cellElement); } } } return cellElements; } @Override public void populatePropertyPane(ElementCasePane ePane) { CellElementPropertyPane.getInstance().reInit(ePane); } public void populateWidgetPropertyPane(ElementCasePane ePane) { CellWidgetPropertyPane.getInstance().reInit(ePane); } }