/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ro.nextreports.designer.action.report.layout.cell;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import ro.nextreports.designer.BandUtil;
import ro.nextreports.designer.Globals;
import ro.nextreports.designer.LayoutHelper;
import ro.nextreports.designer.MergeAlgorithm;
import ro.nextreports.designer.PasteContext;
import ro.nextreports.designer.ReportGrid;
import ro.nextreports.designer.action.undo.LayoutEdit;
import ro.nextreports.designer.grid.Cell;
import ro.nextreports.designer.grid.CellSpan;
import ro.nextreports.designer.grid.DefaultSpanModel;
import ro.nextreports.designer.grid.SelectionModel;
import ro.nextreports.designer.util.I18NSupport;
import ro.nextreports.designer.util.ShortcutsUtil;
import ro.nextreports.designer.util.Show;
import ro.nextreports.engine.util.ObjectCloner;
import ro.nextreports.engine.XStreamFactory;
import ro.nextreports.engine.ReportLayout;
import ro.nextreports.engine.band.BandElement;
import ro.nextreports.engine.band.Band;
/**
* @author Decebal Suiu
*/
public class PasteAction extends AbstractAction {
public PasteAction() {
super();
putValue(Action.NAME, I18NSupport.getString("paste.cell.action.name"));
putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(ShortcutsUtil.getShortcut("layout.paste.accelerator", "control V")));
}
public void actionPerformed(ActionEvent event) {
ReportGrid grid = Globals.getReportGrid();
SelectionModel selectionModel = grid.getSelectionModel();
List<Cell> cells = selectionModel.getSelectedCells();
if ((cells == null) || (cells.size() == 0)) {
return;
}
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
String data = null;
try {
data = (String) (clipboard.getContents(this).getTransferData(DataFlavor.stringFlavor));
} catch (Exception e) {
e.printStackTrace();
return;
}
// Clipboard data is a PasteContext object with one BandElement in list for single cell copy/paste
// and more band elements in list for multiple copy/paste cells
PasteContext obj = (PasteContext)XStreamFactory.createXStream().fromXML(data);
boolean multipleCopy = obj.getElements().size() > 1;
if (multipleCopy && (cells.size() > 1)) {
Show.info(I18NSupport.getString("paste.cell.action.invalid"));
return;
}
ReportLayout oldLayout = ObjectCloner.silenceDeepCopy(LayoutHelper.getReportLayout());
// paste a cell in one or more cells
if (!multipleCopy) {
for (Cell cell : cells) {
PasteContext pasteContext = (PasteContext) XStreamFactory.createXStream().fromXML(data);
pasteElement(grid, pasteContext.getElements().get(0), cell, pasteContext.getColumnSizes().get(0));
}
// paste more cells starting from the selected cell
} else {
PasteContext pasteContext = (PasteContext) XStreamFactory.createXStream().fromXML(data);
List<Cell> copyCells =pasteContext.getCells();
Cell topLeft = copyCells.get(0);
Cell bottomRight = MergeAlgorithm.getLastCell(copyCells);
Cell selected = cells.get(0);
int rows = bottomRight.getRow() - topLeft.getRow() + 1;
int columns = bottomRight.getColumn() - topLeft.getColumn() + 1;
String bandName = grid.getBandName(selected);
Band band = LayoutHelper.getReportLayout().getBand(bandName);
int bandRows = band.getRowCount();
int bandColumns = band.getColumnCount();
int insertRows = grid.getBandLocation(bandName).getRow(selected.getRow()) + rows - bandRows;
int insertColumns = selected.getColumn() + columns - bandColumns;
//System.out.println("bandName=" + bandName);
//System.out.println("insertRows=" + insertRows);
//System.out.println("insertColumns=" + insertColumns);
// insert eventual rows and columns (at the end of the band)
if (insertRows > 0) {
for (int i = 0; i < insertRows; i++) {
Globals.getReportLayoutPanel().getReportGridPanel().insertRows(
LayoutHelper.getReportLayout().getGridRow(bandName, bandRows - 1 + i),
selected.getColumn(), 1, true);
}
}
if (insertColumns > 0) {
for (int i = 0; i < insertColumns; i++) {
Globals.getReportLayoutPanel().getReportGridPanel().insertColumns(
selected.getRow(), bandColumns - 1 + i, 1, true);
}
}
selectionModel.clearSelection();
// paste all elements
List<BandElement> elements = pasteContext.getElements();
List<Integer> columnSizes = pasteContext.getColumnSizes();
int dR = selected.getRow() - topLeft.getRow();
int dC = selected.getColumn() - topLeft.getColumn();
for (int i=0, size=copyCells.size(); i<size; i++) {
Cell copyCell = copyCells.get(i);
BandElement element = elements.get(i);
int whereX = selected.getRow()+dR-(selected.getRow()-copyCell.getRow());
int whereY = selected.getColumn()+dC-(selected.getColumn()-copyCell.getColumn());
//System.out.println("copyCell="+copyCell + " elem="+element);
//System.out.println("dR=" +dR + " dC="+dC);
//System.out.println("whereX="+whereX + " whereY="+whereY);
pasteElement(grid, element, new Cell(whereX,whereY), columnSizes.get(i));
}
// create the span for pasted elements
DefaultSpanModel spanModel = (DefaultSpanModel) grid.getSpanModel();
List<CellSpan> visitedSpans = new ArrayList<CellSpan>();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if (spanModel.isCellSpan(topLeft.getRow() + i, topLeft.getColumn() + j)) {
CellSpan span = spanModel.getSpanOver(topLeft.getRow() + i, topLeft.getColumn() + j);
if (!visitedSpans.contains(span)) {
visitedSpans.add(span);
CellSpan newSpan = new CellSpan(selected.getRow() + i, selected.getColumn() + j, span.getRowCount(), span.getColumnCount());
spanModel.addSpan(newSpan);
BandUtil.updateBandElement(newSpan);
}
}
}
}
}
ReportLayout newLayout = ObjectCloner.silenceDeepCopy(LayoutHelper.getReportLayout());
Globals.getReportUndoManager().addEdit(new LayoutEdit(oldLayout, newLayout, I18NSupport.getString("edit.insert.element")));
}
private void pasteElement(ReportGrid grid, BandElement element, Cell cell, int columnSize) {
int row = cell.getRow();
int column = cell.getColumn();
if (element == null) {
BandUtil.insertElement(null, row, column);
return;
}
BandElement target = grid.getBandElement(cell);
// if cell is not empty, clear it first
if (target != null) {
BandUtil.deleteElement(row, column);
}
CellSpan cellSpan = grid.getSpanModel().getSpanOver(row, column);
// for merge cells insert only in the first cell of the merge
if ((cellSpan != null) && (((cellSpan.getColumnCount() > 1) && (column > cellSpan.getFirstColumn())) ||
((cellSpan.getRowCount() > 1) && (row > cellSpan.getFirstRow())))) {
return;
}
BandElement newElement = BandUtil.copyBandElement(element);
//System.out.println("cellSpan=" + cellSpan + " row="+row + " col="+column);
BandElement oldElement = BandUtil.insertElement(newElement, row, column); // it's null
// resize column -- do we wish ??? (comment for now)
// if (LayoutHelper.getReportLayout().isUseSize()) {
// ReportLayoutUtil.resizeColumn(grid, column, columnSize);
// }
// repaint headers
Globals.getReportLayoutPanel().getReportGridPanel().repaintHeaders();
}
}