/*
* 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;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.TreePath;
import ro.nextreports.engine.ReportLayout;
import ro.nextreports.engine.band.Band;
import ro.nextreports.engine.band.BandElement;
import org.jdesktop.jxlayer.JXLayer;
import org.pbjar.jxlayer.demo.TransformUtils;
import org.pbjar.jxlayer.demo.QualityHints;
import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel;
import org.pbjar.jxlayer.plaf.ext.TransformUI;
import ro.nextreports.designer.grid.Cell;
import ro.nextreports.designer.grid.CellSpan;
import ro.nextreports.designer.grid.JGridHeader;
import ro.nextreports.designer.grid.ResizableGrid;
import ro.nextreports.designer.grid.SpanModel;
import ro.nextreports.designer.grid.event.SelectionModelEvent;
import ro.nextreports.designer.grid.event.SelectionModelListener;
import ro.nextreports.designer.ui.Rule;
import ro.nextreports.designer.ui.zoom.ZoomEvent;
import ro.nextreports.designer.ui.zoom.ZoomEventListener;
import ro.nextreports.designer.util.ImageUtil;
/**
* @author Decebal Suiu
*/
public class ReportGridPanel extends JPanel implements ZoomEventListener {
private JScrollPane scrollGrid;
private ReportGrid grid;
private JGridHeader columnHeader;
private JGridHeader rowHeader;
private boolean showHeader = true; // header display flag
private JXLayer rowHeaderLayer;
private JXLayer colHeaderLayer;
private JXLayer gridLayer;
private double zoom = 1.0;
public ReportGridPanel(int rows, int columns) {
super();
initComponents(new ReportGrid(new ReportGridModel(rows, columns)));
}
public ReportGrid getGrid() {
return grid;
}
public int getRowCount() {
return grid.getRowCount();
}
public int getColumnCount() {
return grid.getColumnCount();
}
public void insertRows(int row, int column, int rowCount, boolean after) {
adjustBandLocations(row, rowCount);
int insertRow = row;
if (after) {
if (Globals.getReportGrid().isCellSpan(row, column)) {
CellSpan cellSpan = Globals.getReportGrid().getSpanModel().getSpanOver(row, column);
insertRow = insertRow + cellSpan.getRowCount();
} else {
insertRow++;
}
}
((ResizableGrid) grid.getModel()).insertRows(insertRow, rowCount);
repaintHeaders();
insertBandRows(insertRow, rowCount);
}
// used by tree popup action
// special case if band has no rows
public void insertRow(Band band) {
int row = Globals.getReportGrid().getBandLocation(band.getName()).getLastGridRow();
insertRow(band, row);
}
public void insertRow(Band band, int row) {
if (band.getRowCount() == 0) {
Globals.getReportGrid().putBandLocation(band.getName(), new BandLocation(row, 1));
adjustAfterBandLocations(band.getName(), 1);
} else {
adjustBandLocations(row - 1, 1);
}
((ResizableGrid) grid.getModel()).insertRows(row, 1);
if (grid.getColumnCount() == 0) {
((ResizableGrid) grid.getModel()).insertColumns(0, 1);
}
repaintHeaders();
if (band.getRowCount() == 0) {
band.setElements(new ArrayList<List<BandElement>>());
band.insertRow(0);
band.setColumnCount(Globals.getReportGrid().getColumnCount());
} else {
insertBandRows(row, 1);
}
}
public void removeRows(int row, int rowCount) {
removeBandRows(row, rowCount);
((ResizableGrid) grid.getModel()).removeRows(row, rowCount);
adjustBandLocations(row, -rowCount);
repaintHeaders();
}
public void insertColumns(int row, int column, int columnCount, boolean after) {
int insertedColumn = column;
if (after) {
if (Globals.getReportGrid().isCellSpan(row, column)) {
CellSpan cellSpan = Globals.getReportGrid().getSpanModel().getSpanOver(row, column);
insertedColumn = insertedColumn + cellSpan.getColumnCount();
} else {
insertedColumn++;
}
}
((ResizableGrid) grid.getModel()).insertColumns(insertedColumn, columnCount);
repaintHeaders();
insertBandColumns(insertedColumn, columnCount);
// update column width array
ReportLayoutUtil.updateColumnWidth(Globals.getReportGrid());
}
public void removeColumns(int column, int columnCount) {
removeBandColumns(column, columnCount);
((ResizableGrid) grid.getModel()).removeColumns(column, columnCount);
repaintHeaders();
}
/**
* Return true if headers are enabled.
* @return true if headers are enabled
*/
public boolean getShowHeader() {
return showHeader;
}
/**
* Set whether headers should be displayed.
*
* @param showHeader true means the header is shown
*/
public void setShowHeader(boolean showHeader) {
this.showHeader = showHeader;
if (showHeader) {
// Attach column headers
columnHeader = new ReportColumnGridHeader(grid);
JPanel columnHeaderPanel = new JPanel();
boolean isMetric = Globals.UNIT_CM.equals(Globals.getRulerUnit());
Rule hRule = new Rule(Rule.HORIZONTAL, isMetric);
hRule.setPreferredHeight(Rule.SIZE + 1);
columnHeaderPanel.setLayout(new GridBagLayout());
if (LayoutHelper.getReportLayout().isUseSize() &&
Globals.isRulerVisible()) {
columnHeaderPanel.add(hRule, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
}
colHeaderLayer = TransformUtils.createTransformJXLayer(columnHeader, zoom, new QualityHints());
columnHeaderPanel.add(colHeaderLayer, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
columnHeaderPanel.add(new JLabel(), new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
scrollGrid.setColumnHeaderView(columnHeaderPanel);
// Attach row headers
rowHeader = new ReportRowGridHeader(grid);
rowHeader.setColumnWidth(0, 50);
rowHeader.setCellRenderer(Object.class, new ReportGridHeaderRowRenderer());
rowHeaderLayer = TransformUtils.createTransformJXLayer(rowHeader, zoom, new QualityHints());
JViewport viewport = new JViewport();
viewport.setView(rowHeaderLayer);
viewport.setPreferredSize(rowHeaderLayer.getPreferredSize());
scrollGrid.setRowHeaderView(viewport);
// Attach upper left corner : this corner selects the root tree (report properties)
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JLabel iconLabel = new JLabel(ImageUtil.getImageIcon("properties"));
panel.add(iconLabel, BorderLayout.CENTER);
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JTree tree = Globals.getReportDesignerPanel().getStructurePanel().getStructureTree();
tree.setSelectionPath(new TreePath(tree.getModel().getRoot()));
}
});
panel.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
scrollGrid.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, panel);
} else {
rowHeaderLayer = null;
colHeaderLayer = null;
scrollGrid.setRowHeaderView(null);
scrollGrid.setColumnHeaderView(null);
}
// scroll headers to current view position
scrollHeaders();
repaint();
}
public void repaintHeaders() {
boolean oldShowHeader = showHeader;
setShowHeader(false);
setShowHeader(oldShowHeader);
}
public void scrollHeaders() {
scrollGrid.getRowHeader().setViewPosition(scrollGrid.getViewport().getViewPosition());
scrollGrid.getColumnHeader().setViewPosition(scrollGrid.getViewport().getViewPosition());
}
public void setReportLayout(ReportLayout reportLayout) {
// clear old data
((ResizableGrid) grid.getModel()).removeRows(0, getRowCount());
((ResizableGrid) grid.getModel()).removeColumns(0, getColumnCount());
createBandLocations(reportLayout);
// insert empty rows and columns
((ResizableGrid) grid.getModel()).insertRows(0, reportLayout.getRowCount());
((ResizableGrid) grid.getModel()).insertColumns(0, reportLayout.getColumnCount());
// refresh grid's model
grid.refreshModel(reportLayout);
repaintHeaders();
}
private void createBandLocations(ReportLayout reportLayout) {
grid.clearBandLocations();
// // update header band location
// Band headerBand = reportLayout.getHeaderBand();
// int headerRows = headerBand.getRowCount();
// System.out.println("headerRows = " + headerRows);
// grid.putBandLocation(headerBand.getName(), new BandLocation(0, headerRows));
//
// // update detail band location
// Band detailBand = reportLayout.getDetailBand();
// int detailRows = detailBand.getRowCount();
// System.out.println("detailRows = " + detailRows);
// grid.putBandLocation(detailBand.getName(), new BandLocation(headerRows, detailRows));
//
// // update footer band location
// Band footerBand = reportLayout.getFooterBand();
// int footerRows = footerBand.getRowCount();
// System.out.println("footerRows = " + footerRows);
// grid.putBandLocation(footerBand.getName(), new BandLocation(headerRows + detailRows, footerRows));
int rowSum = 0;
for (Band band : reportLayout.getBands()) {
int rows = band.getRowCount();
grid.putBandLocation(band.getName(), new BandLocation(rowSum, rows));
rowSum += rows;
}
}
private void adjustBandLocations(int row, int value) {
if (value == 0) {
return;
}
String bandName = grid.getBandName(row);
BandLocation bandLocation = grid.getBandLocation(bandName);
bandLocation.adjustRowCount(value);
adjustAfterBandLocations(bandName, value);
}
private void adjustAfterBandLocations(String bandName, int value) {
ReportLayout reportLayout = LayoutHelper.getReportLayout();
List<String> bandNamesAfter = reportLayout.getBandNamesAfter(bandName);
for (String bandNameAfter : bandNamesAfter) {
BandLocation bandLocation = grid.getBandLocation(bandNameAfter);
if (bandLocation != null) {
bandLocation.adjustBorder(value);
}
}
}
protected void setGrid(ReportGrid grid) {
this.grid = grid;
gridLayer = TransformUtils.createTransformJXLayer(this.grid, zoom, new QualityHints());
scrollGrid.setViewportView(gridLayer);
// Add headers to scrollTable
setShowHeader(showHeader);
}
private void initComponents(final ReportGrid grid) {
// Add grid to panel
scrollGrid = new JScrollPane();
setLayout(new BorderLayout());
setPreferredSize(new Dimension(400, 100));
add(scrollGrid, BorderLayout.CENTER);
setGrid(grid);
grid.getSelectionModel().addSelectionModelListener(new SelectionModelListener() {
public void selectionChanged(SelectionModelEvent event) {
for (Cell cell : event.getSelectionModel().getSelectedCells()) {
rowHeader.getSelectionModel().addSelectionCell(new Cell(cell.getRow(), 0));
columnHeader.getSelectionModel().addSelectionCell(new Cell(0, cell.getColumn()));
}
}
});
}
private void insertBandRows(int row, int rowCount) {
SpanModel spanModel = Globals.getReportGrid().getSpanModel();
String bandName = grid.getBandName(row);
if (bandName != null) {
Band band = LayoutHelper.getReportLayout().getBand(bandName);
int bandRow = grid.getBandLocation(bandName).getRow(row);
if (band != null) {
for (int i = bandRow; i < bandRow + rowCount; i++) {
band.insertRow(i);
}
int columns = Globals.getReportGrid().getColumnCount();
for(int i=row; i<row+rowCount; i++) {
for (int j=0; j<columns; j++) {
if (!spanModel.isCellSpan(i, j)) {
BandUtil.insertElement(new BandElement(""), i, j);
}
}
}
}
}
}
private void insertBandColumns(int column, int columnCount) {
SpanModel spanModel = Globals.getReportGrid().getSpanModel();
List<Band> bands = LayoutHelper.getReportLayout().getBands();
for (Band band : bands) {
for (int i = column; i < column + columnCount; i++) {
band.insertColumn(i);
}
}
int rows = Globals.getReportGrid().getRowCount();
for(int i=0; i<rows; i++) {
for (int j=column; j<column+columnCount; j++) {
if (!spanModel.isCellSpan(i, j)) {
BandUtil.insertElement(new BandElement(""), i, j);
}
}
}
}
private void removeBandRows(int row, int rowCount) {
String bandName = grid.getBandName(row);
if (bandName != null) {
Band band = LayoutHelper.getReportLayout().getBand(bandName);
if (band != null) {
int bandRow = grid.getBandLocation(bandName).getRow(row);
for (int i = bandRow + rowCount - 1; i >= bandRow; i--) {
band.removeRow(i);
}
}
}
}
private void removeBandColumns(int column, int columnCount) {
List<Band> bands = LayoutHelper.getReportLayout().getNotEmptyBands();
for (Band band : bands) {
for (int i = column + columnCount - 1; i >= column; i--) {
band.removeColumn(i);
}
}
}
public void notifyZoom(ZoomEvent event) {
zoom = event.getZoom();
DefaultTransformModel model = (DefaultTransformModel) ((TransformUI) gridLayer.getUI()).getModel();
model.setScale(zoom);
gridLayer.repaint();
repaintHeaders();
}
public void addMouseWheelListener(MouseWheelListener listener) {
scrollGrid.addMouseWheelListener(listener);
}
public JGridHeader getRowHeader() {
return rowHeader;
}
public JGridHeader getColumnHeader() {
return columnHeader;
}
}