/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.designer.core.model;
import org.pentaho.reporting.designer.core.Messages;
import org.pentaho.reporting.designer.core.editor.ReportDocumentContext;
import org.pentaho.reporting.designer.core.editor.report.drag.MoveDragOperation;
import org.pentaho.reporting.designer.core.editor.report.snapping.EmptySnapModel;
import org.pentaho.reporting.designer.core.util.undo.MassElementStyleUndoEntry;
import org.pentaho.reporting.designer.core.util.undo.MassElementStyleUndoEntryBuilder;
import org.pentaho.reporting.designer.core.util.undo.UndoManager;
import org.pentaho.reporting.engine.classic.core.Band;
import org.pentaho.reporting.engine.classic.core.CrosstabGroup;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.PageDefinition;
import org.pentaho.reporting.engine.classic.core.ReportElement;
import org.pentaho.reporting.engine.classic.core.RootLevelBand;
import org.pentaho.reporting.engine.classic.core.Section;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleSheet;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AlignmentUtilities {
private final UndoManager undo;
private PageDefinition originalPageDefinition;
private PageDefinition currentPageDefinition;
private List<Element> visualElements;
private MassElementStyleUndoEntryBuilder builder;
public AlignmentUtilities( final ReportDocumentContext reportRenderContext, final PageDefinition pageDefinition ) {
undo = reportRenderContext.getUndo();
final MasterReport masterReport = reportRenderContext.getContextRoot();
currentPageDefinition = masterReport.getPageDefinition();
originalPageDefinition = pageDefinition;
final ArrayList<Element> elementArrayList = new ArrayList<Element>();
collectAlignableElements( masterReport, elementArrayList );
visualElements = Collections.unmodifiableList( elementArrayList );
builder = new MassElementStyleUndoEntryBuilder( visualElements );
}
public void alignRight() {
final double theCurrentPageWidth = currentPageDefinition.getWidth();
final int theShiftRight =
(int) ( theCurrentPageWidth - StrictGeomUtility.toExternalValue( computeFarRightPostion() ) );
align( theShiftRight, visualElements );
registerChanges();
}
public void alignLeft() {
final int theShiftLeft = (int) ( 0 - StrictGeomUtility.toExternalValue( computeFarLeftPosition() ) );
align( theShiftLeft, visualElements );
registerChanges();
}
public void resizeProportional() {
final float originalPageWidth = originalPageDefinition.getWidth();
final float currentPageWidth = currentPageDefinition.getWidth();
final float scaleFactor = currentPageWidth / originalPageWidth;
for ( Element element : visualElements ) {
// Resize the element.
final CachedLayoutData cachedLayoutData = ModelUtility.getCachedLayoutData( element );
final double elementWidth = StrictGeomUtility.toExternalValue( cachedLayoutData.getWidth() );
final ElementStyleSheet styleSheet = element.getStyle();
styleSheet.setStyleProperty( ElementStyleKeys.MIN_WIDTH, new Float( elementWidth * scaleFactor ) );
// Reposition the element.
final double origin = StrictGeomUtility.toExternalValue( cachedLayoutData.getX() );
final double destination = scaleFactor * origin;
final int theShift = (int) ( destination - origin );
final List<Element> elementsCarrier = new ArrayList<Element>( 1 );
elementsCarrier.add( element );
align( theShift, elementsCarrier );
}
registerChanges();
}
public void alignCenter() {
final long farLeftPostion = computeFarLeftPosition();
final long farRightPostion = computeFarRightPostion();
final long currentPageWidth = StrictGeomUtility.toInternalValue( currentPageDefinition.getWidth() );
final long remainingRightSpace = currentPageWidth - farRightPostion;
final long normalizedSpace = ( farLeftPostion + remainingRightSpace ) / 2;
long requiredShift = normalizedSpace - farLeftPostion;
if ( remainingRightSpace > farLeftPostion ) {
// move to the Right
requiredShift = Math.abs( requiredShift );
} else {
// move to the Left
requiredShift = 0 - Math.abs( requiredShift );
}
final int shiftInPoints = (int) StrictGeomUtility.toExternalValue( requiredShift );
align( shiftInPoints, visualElements );
registerChanges();
}
private void align( final int theShiftValue, final List<Element> elements ) {
final MoveDragOperation mop =
new MoveDragOperation( elements, new Point(), EmptySnapModel.INSTANCE, EmptySnapModel.INSTANCE );
mop.update( new Point( theShiftValue, 0 ), 1 );
mop.finish();
}
private void registerChanges() {
final MassElementStyleUndoEntry massElementStyleUndoEntry = builder.finish();
undo.addChange( Messages.getString( "AlignmentUtilities.Undo" ), massElementStyleUndoEntry );
}
private long computeFarRightPostion() {
boolean first = true;
long theFarRightPostion = 0;
for ( Element visualElement : visualElements ) {
final CachedLayoutData theElementData = ModelUtility.getCachedLayoutData( visualElement );
final long theCurrentPosition = theElementData.getX() + theElementData.getWidth();
if ( first ) {
theFarRightPostion = theCurrentPosition;
} else if ( theCurrentPosition > theFarRightPostion ) {
theFarRightPostion = theCurrentPosition;
}
first = false;
}
return theFarRightPostion;
}
private long computeFarLeftPosition() {
boolean first = true;
long theFarLeftPostion = 0;
for ( Element visualElement : visualElements ) {
final CachedLayoutData theElementData = ModelUtility.getCachedLayoutData( visualElement );
final long theCurrentPosition = theElementData.getX();
if ( first ) {
theFarLeftPostion = theCurrentPosition;
} else {
theFarLeftPostion = theCurrentPosition < theFarLeftPostion ? theCurrentPosition : theFarLeftPostion;
}
first = false;
}
return theFarLeftPostion;
}
private void collectAlignableElements( final Section section, final List<Element> collectedElements ) {
if ( section instanceof CrosstabGroup ) {
return;
}
final int theElementCount = section.getElementCount();
for ( int i = 0; i < theElementCount; i++ ) {
final ReportElement reportElement = section.getElement( i );
if ( reportElement instanceof Section ) {
collectAlignableElements( (Section) reportElement, collectedElements );
}
final CachedLayoutData cachedLayoutData = ModelUtility.getCachedLayoutData( (Element) reportElement );
final long layoutAge = cachedLayoutData.getLayoutAge();
if ( layoutAge != -1 ) {
if ( reportElement instanceof RootLevelBand ) {
continue;
}
if ( reportElement instanceof Band ||
reportElement instanceof Section == false ) {
collectedElements.add( (Element) reportElement );
}
}
}
}
}