/* * 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.Color; import java.awt.FontMetrics; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.swing.UIManager; import ro.nextreports.designer.grid.CellSpan; import ro.nextreports.designer.grid.JGrid; import ro.nextreports.designer.grid.event.GridModelEvent; import ro.nextreports.designer.grid.event.GridModelListener; import ro.nextreports.designer.grid.event.SelectionModelEvent; import ro.nextreports.engine.band.BandElement; import ro.nextreports.engine.band.Border; import ro.nextreports.engine.band.Padding; /** * @author Decebal Suiu */ class AutoFitGridHandler implements GridModelListener { private ReportGrid grid; private Map<Integer, Map<Integer, Integer>> columnSizeCache; private Map<Integer, Map<Integer, Integer>> rowSizeCache; public AutoFitGridHandler(ReportGrid grid) { this.grid = grid; columnSizeCache = new HashMap<Integer, Map<Integer, Integer>>(); rowSizeCache = new HashMap<Integer, Map<Integer, Integer>>(); } public void clearCache() { columnSizeCache.clear(); rowSizeCache.clear(); } public void gridChanged(GridModelEvent event) { int eventType = event.getType(); if (eventType == GridModelEvent.CELLS_UPDATED) { onCellsUpdated(event); } else if (eventType == GridModelEvent.COLUMNS_DELETED) { onColumnsDeleted(event); } else if (eventType == GridModelEvent.ROWS_DELETED) { onRowsDeleted(event); } else if (eventType == GridModelEvent.ROWS_INSERTED) { onRowsInserted(event); } } private void onCellsUpdated(GridModelEvent event) { int column = event.getFirstColumn(); int row = event.getFirstRow(); BandElement element = grid.getBandElement(row, column); //System.out.println("row="+row + " column="+column + " element="+element); // handle column size if (LayoutHelper.getReportLayout().isUseSize()) { grid.getColumnHeaderModel().setSize(column, LayoutHelper.getReportLayout().getColumnsWidth().get(column)); } if (element == null) { // possible a clear cell !? // handle column size if (!LayoutHelper.getReportLayout().isUseSize()) { Map<Integer, Integer> rowsMap = getRowsMap(column); rowsMap.put(row, JGrid.DEFAULT_COLUMN_WIDTH); grid.getColumnHeaderModel().setSize(column, Collections.max(rowsMap.values())); } // handle row size Map<Integer, Integer> columnsMap = getColumnsMap(row); columnsMap.put(column, JGrid.DEFAULT_ROW_HEIGHT); grid.getRowHeaderModel().setSize(row, Collections.max(columnsMap.values())); return; } // in case that property value is deleted from PropertyPanel (close button) // set a default value setDefaultProperties(element); // retrieves a font metrics from the element font FontMetrics fontMetrics = grid.getFontMetrics(element.getFont()); // if the cell is inside a span , divide the width to the number of cells in the span // and update all columns / rows // todo on start span model is not initialized!!! CellSpan span = grid.getSpanModel().getSpanOver(row, column); //System.out.println("span="+span); // handle column size // TODO calculate insets (now it's 8) if (!LayoutHelper.getReportLayout().isUseSize()) { for (int i = column; i < span.getColumnCount() + column; i++) { int columnSize = fontMetrics.stringWidth(element.getText()) / span.getColumnCount() + 8; BandElement elementC = grid.getBandElement(row, i); if (elementC != null) { Padding padding = elementC.getPadding(); if (padding != null) { columnSize += padding.getLeft() + padding.getRight(); } } if (columnSize < JGrid.DEFAULT_COLUMN_WIDTH) { columnSize = JGrid.DEFAULT_COLUMN_WIDTH; } Map<Integer, Integer> rowsMap = getRowsMap(i); rowsMap.put(row, columnSize); //System.out.println("i="+i + " textSize=" + fontMetrics.stringWidth(element.getText()) + " colSize="+columnSize); grid.getColumnHeaderModel().setSize(i, Collections.max(rowsMap.values())); } } // TODO calculate insets (now it's 4) // handle row size for (int i = row; i < span.getRowCount() + row; i++) { int rowSize = fontMetrics.getHeight() / span.getRowCount() + 4; BandElement elementC = grid.getBandElement(i, column); if (elementC != null) { Padding padding = elementC.getPadding(); if (padding != null) { rowSize += padding.getTop() + padding.getBottom(); } } if (rowSize < JGrid.DEFAULT_ROW_HEIGHT) { rowSize = JGrid.DEFAULT_ROW_HEIGHT; } Map<Integer, Integer> columnsMap = getColumnsMap(i); columnsMap.put(column, rowSize); grid.getRowHeaderModel().setSize(i, Collections.max(columnsMap.values())); } notifyPropertyPanel(); } private void onRowsInserted(GridModelEvent event) { int firstRow = event.getFirstRow(); int lastRow = event.getLastRow(); for (int i = firstRow; i < grid.getRowCount(); i++) { Map<Integer, Integer> columnsMap = rowSizeCache.remove(i); rowSizeCache.put(i + lastRow - firstRow + 1, columnsMap); } } private void onRowsDeleted(GridModelEvent event) { int firstRow = event.getFirstRow(); int lastRow = event.getLastRow(); for (int i = firstRow; i <= lastRow; i++) { rowSizeCache.remove(i); } for (int i = lastRow + 1; i < grid.getRowCount(); i++) { Map<Integer, Integer> columnsMap = rowSizeCache.remove(i); rowSizeCache.put(i - lastRow + firstRow - 1, columnsMap); } } private void onColumnsDeleted(GridModelEvent event) { int firstColumn = event.getFirstColumn(); int lastColumn = event.getLastColumn(); for (int i = lastColumn; i >= firstColumn; i--) { columnSizeCache.remove(i); } } private void setDefaultProperties(BandElement element) { if (element.getFont() == null) { element.setFont(UIManager.getDefaults().getFont("Label.font")); } if (element.getBackground() == null) { element.setBackground(Color.WHITE); } if (element.getForeground() == null) { element.setForeground(Color.BLACK); } if (element.getPadding() == null) { element.setPadding(new Padding(0, 0, 0, 0)); } if (element.getBorder() == null) { element.setBorder(new Border(0, 0, 0, 0)); } } private void notifyPropertyPanel() { SelectionModelEvent selectionEvent = new SelectionModelEvent(Globals.getReportGrid().getSelectionModel(), false); Globals.getReportDesignerPanel().getPropertiesPanel().selectionChanged(selectionEvent); } private Map<Integer, Integer> getRowsMap(int column) { Map<Integer, Integer> rowsMap = columnSizeCache.get(column); if (rowsMap == null) { rowsMap = new HashMap<Integer, Integer>(); columnSizeCache.put(column, rowsMap); } return rowsMap; } private Map<Integer, Integer> getColumnsMap(int row) { Map<Integer, Integer> columnsMap = rowSizeCache.get(row); if (columnsMap == null) { columnsMap = new HashMap<Integer, Integer>(); rowSizeCache.put(row, columnsMap); } return columnsMap; } }