diff options
Diffstat (limited to '')
-rw-r--r-- | wizards/com/sun/star/wizards/reportbuilder/layout/ReportBuilderLayouter.java | 1582 |
1 files changed, 1582 insertions, 0 deletions
diff --git a/wizards/com/sun/star/wizards/reportbuilder/layout/ReportBuilderLayouter.java b/wizards/com/sun/star/wizards/reportbuilder/layout/ReportBuilderLayouter.java new file mode 100644 index 000000000..cfa2071a3 --- /dev/null +++ b/wizards/com/sun/star/wizards/reportbuilder/layout/ReportBuilderLayouter.java @@ -0,0 +1,1582 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package com.sun.star.wizards.reportbuilder.layout; + +import com.sun.star.awt.FontDescriptor; +import com.sun.star.awt.Rectangle; +import com.sun.star.awt.Size; +import com.sun.star.awt.XControl; +import com.sun.star.awt.XControlModel; +import com.sun.star.awt.XLayoutConstrains; +import com.sun.star.awt.XUnitConversion; +import com.sun.star.awt.XWindow; +import com.sun.star.awt.XWindowPeer; +import com.sun.star.beans.Property; +import com.sun.star.beans.PropertyAttribute; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.container.XEnumeration; +import com.sun.star.container.XNameAccess; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.report.XFixedLine; +import com.sun.star.report.XFixedText; +import com.sun.star.report.XFormattedField; +import com.sun.star.report.XGroup; +import com.sun.star.report.XGroups; +import com.sun.star.report.XImageControl; +import com.sun.star.report.XReportComponent; +import com.sun.star.report.XReportControlModel; +import com.sun.star.report.XReportDefinition; +import com.sun.star.report.XSection; +import com.sun.star.drawing.XShape; +import com.sun.star.sdbc.DataType; +import com.sun.star.style.XStyle; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.XNumberFormatTypes; +import com.sun.star.util.XNumberFormats; +import com.sun.star.util.XNumberFormatsSupplier; +import com.sun.star.wizards.common.Configuration; +import com.sun.star.wizards.common.FileAccess; +import com.sun.star.wizards.common.Helper; +import com.sun.star.wizards.common.PropertyNames; +import com.sun.star.wizards.common.PropertySetHelper; +import com.sun.star.wizards.common.Resource; +import com.sun.star.wizards.report.IReportBuilderLayouter; +import com.sun.star.wizards.report.IReportDefinitionReadAccess; +import com.sun.star.wizards.ui.UIConsts; + +import java.util.HashMap; +import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class is abstract and more like a helper for create different layouts for Report Builder Wizard. + */// TODO: let a little bit place between 2 formatted fields +// TODO: move all sectionobjects which have a connect to the right max page width to left if there is a orientation change. +abstract public class ReportBuilderLayouter implements IReportBuilderLayouter +{ + + private IReportDefinitionReadAccess m_xReportDefinitionReadAccess; + private final Resource m_aResource; + private String[][] m_aSortNames; + + /** + * dispose the ReportBuilderLayouter + */ + public void dispose() + { + closeDesignTemplate(); + m_xReportDefinitionReadAccess = null; + } + + /** + * The Constructor is protected, this is an abstract class, use Tabular or other to create an instance. + * @param _xDefinitionAccess + * @param _aResource + */ + protected ReportBuilderLayouter(IReportDefinitionReadAccess _xDefinitionAccess, Resource _aResource) + { + m_xReportDefinitionReadAccess = _xDefinitionAccess; + m_aResource = _aResource; + } + + /** + * Access to the current ReportDefinition + * @return the ReportDefinition + */ + public XReportDefinition getReportDefinition() + { + // we have to ask our parent for this value + return m_xReportDefinitionReadAccess.getReportDefinition(); + } + + /** + * Access to the global MultiServiceFactory + * @return the global Service Factory + */ + private XMultiServiceFactory getGlobalMSF() + { + return m_xReportDefinitionReadAccess.getGlobalMSF(); + } + + /** + * Layout the complete report new, by all information we know until this time. + * + * If there are some information less, it is no problem for this function, they will be leaved out. + * It is possible to call this function after every change, but be careful, could take a little bit longer. + */ + public synchronized void layout() + { + try + { + // we bring the clear and insert methods together, this should be a little bit smoother + clearReportHeader(); + insertReportHeader(); + + clearReportFooter(); + insertReportFooter(); + + clearPageHeader(); + insertPageHeader(); + + clearPageFooter(); + insertPageFooter(); + + clearGroups(); + int lastGroupPosition = insertGroups(); + + clearDetails(); + insertDetailFieldTitles(lastGroupPosition); + insertDetailFields(); + } + catch (java.lang.ArrayIndexOutOfBoundsException e) + { + // could happen, if you change the count of values + } + catch (java.lang.RuntimeException e) + { + throw e; + } + catch (Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + + + /** + * Remove all Groups + */ + private void clearGroups() + { + final XGroups xGroups = getReportDefinition().getGroups(); + while (xGroups.hasElements()) + { + try + { + xGroups.removeByIndex(0); + } + catch (com.sun.star.uno.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + + /** + * Remove all fields + * @param _xSectionToClear + */ + private void emptySection(XSection _xSectionToClear) + { + if (_xSectionToClear == null) + { + return; + } + while (_xSectionToClear.hasElements()) + { + try + { + final Object aObj = _xSectionToClear.getByIndex(0); + final XShape aShape = UnoRuntime.queryInterface(XShape.class, aObj); + _xSectionToClear.remove(aShape); + } + catch (com.sun.star.uno.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + + } + } + + private void clearDetails() + { + final XSection xSection = getReportDefinition().getDetail(); + emptySection(xSection); + } + + /** + * @param _nGroupCount + * @return the left indent in 1/100mm + */ + protected int getLeftGroupIndent(int _nGroupCount) + { +// TODO: Fix values for group indent (1/2cm) only the first 2 groups + int nIndent = 0; + final int MAX_INDENT = 2; + if (_nGroupCount <= MAX_INDENT) + { + nIndent = _nGroupCount * LayoutConstants.IndentFactorWidth; + } + else + { + nIndent = MAX_INDENT * LayoutConstants.IndentFactorWidth; + } + return nIndent; + } + + private int m_nLeftIndent = -1; + + /** + * Get left page indent. + * The left indent is the area on the left side which will no be printed. + * The default is 2000 1/100mm what is 2cm of DIN A4. + * @return the left indent in 1/100mm + */ + protected int getLeftPageIndent() + { + if (m_nLeftIndent < 0) + { + m_nLeftIndent = getFromPageStyles("LeftMargin", 2000); + } + return m_nLeftIndent; + } + + private int m_nRightIndent = -1; + + /** + * Get right page indent. + * The right indent is the area on the right side which will no be printed. + * The default is 2000 1/100mm what is 2cm of DIN A4. + * @return the right indent in 1/100mm + */ + protected int getRightPageIndent() + { + if (m_nRightIndent < 0) + { + m_nRightIndent = getFromPageStyles("RightMargin", 2000); + } + return m_nRightIndent; + } + + private XStyle getUsedStyle(String _sStyleName) + { + XStyle aUsedStyle = null; + final XNameAccess xNameAccess = getReportDefinition().getStyleFamilies(); + try + { + // get all Page Styles + final Object aPageStylesObj = xNameAccess.getByName(_sStyleName); + final XNameAccess xContainer = UnoRuntime.queryInterface(XNameAccess.class, aPageStylesObj); + + // step over all Page Styles, search the one which is in use + final String[] aElementNames = xContainer.getElementNames(); + for (int i = 0; i < aElementNames.length; i++) + { + final String sName = aElementNames[i]; + final Object aObj = xContainer.getByName(sName); + final XStyle xStyle = UnoRuntime.queryInterface(XStyle.class, aObj); + if (xStyle.isInUse()) + { + aUsedStyle = xStyle; + break; + } + } + } + catch (com.sun.star.uno.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + return aUsedStyle; + } + + private int getFromPageStyles(String _sStyleName, int _nDefault) + { + int nValue = _nDefault; + final XStyle xStyle = getUsedStyle("PageStyles"); + if (xStyle != null) + { + // we found the page style which is in use + final PropertySetHelper aHelper = new PropertySetHelper(xStyle); + nValue = aHelper.getPropertyValueAsInteger(_sStyleName, nValue); + } + return nValue; + } + + private void setToPageStyles(String _sStyleName, Object _aObj) + { + final XStyle xStyle = getUsedStyle("PageStyles"); + if (xStyle != null) + { + final PropertySetHelper aHelper = new PropertySetHelper(xStyle); + aHelper.setPropertyValueDontThrow(_sStyleName, _aObj); + } + } + + private int m_nPageWidth = -1; + + /** + * Get page width. The default is 21000 1/100mm what is 21cm of DIN A4. + * @return the Width of the page in 1/100mm + */ + protected int getPageWidth() + { + if (m_nPageWidth < 0) + { + m_nPageWidth = getFromPageStyles(PropertyNames.PROPERTY_WIDTH, 21000); + } + return m_nPageWidth; + } + + + /** + * Stores the Group names. To insert/create a report with such group names, call layout() + */ + public void insertGroupNames(String[] _aGroupNames) + { + m_aGroupNames = _aGroupNames; + } + + public void insertSortingNames(String[][] _aSortFieldNames) + { + m_aSortNames = _aSortFieldNames; + } + + protected void copyGroupProperties(int _nGroup) + { + if (getDesignTemplate() != null) + { + try + { + final XGroups xForeignGroups = getDesignTemplate().getGroups(); + if (_nGroup < xForeignGroups.getCount()) + { + XGroup xForeignGroup = UnoRuntime.queryInterface(XGroup.class, xForeignGroups.getByIndex(_nGroup)); + XSection xForeignGroupSection = xForeignGroup.getHeader(); + + if (xForeignGroupSection != null) + { + final XGroups xGroups = getReportDefinition().getGroups(); + Object aGroup = xGroups.getByIndex(_nGroup); + XGroup xGroup = UnoRuntime.queryInterface(XGroup.class, aGroup); + XSection xGroupSection = xGroup.getHeader(); + + // copy Properties + copyProperties(xForeignGroupSection, xGroupSection); + } + } + } + catch (Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + + private int insertGroups() + { + final XGroups xGroups = getReportDefinition().getGroups(); + int lastGroupPosition = -1; + + if (m_aGroupNames != null) + { + final int nLeftPageIndent = getLeftPageIndent(); + final int nLabelWidth = getMaxLabelWidth(); // 3000; + final int nUsablePageWidth = getPageWidth() - getLeftPageIndent() - getRightPageIndent() - getLeftGroupIndent(getCountOfGroups()); + final int nFieldWidth = nUsablePageWidth - nLabelWidth; + + XGroup aLastGroup = null; + // after done with all groups, we need access to the last group, for set property 'KeepTogether' so we remember it. + + for (int i = 0; i < m_aGroupNames.length; i++) + { + lastGroupPosition = i; + final XGroup xGroup = xGroups.createGroup(); + aLastGroup = xGroup; + + xGroup.setExpression(m_aGroupNames[i]); + xGroup.setHeaderOn(true); + + try + { + int nCount = xGroups.getCount(); + xGroups.insertByIndex(nCount, xGroup); + final XSection xGroupSection = xGroup.getHeader(); + copyGroupProperties(nCount); + + Rectangle aRect = new Rectangle(); + aRect.X = nLeftPageIndent + getLeftGroupIndent(i); + SectionObject aSO = getDesignTemplate().getGroupLabel(i); + aRect = insertLabel(xGroupSection, getTitleFromFieldName(m_aGroupNames[i]), aRect, nLabelWidth, aSO); + final String sGroupName = convertToFieldName(m_aGroupNames[i]); + aSO = getDesignTemplate().getGroupTextField(i); + aRect = insertFormattedField(xGroupSection, sGroupName, aRect, nFieldWidth, aSO); + int height = aRect.Height; + + // draw a line under the label/formattedfield + aRect.X = nLeftPageIndent + getLeftGroupIndent(i); + aRect.Y = aRect.Height; + final int nLineWidth = getPageWidth() - getRightPageIndent() - aRect.X; + final int nLineHeight = LayoutConstants.LineHeight; + insertHorizontalLine(xGroupSection, aRect, nLineWidth, nLineHeight); + xGroupSection.setHeight(height + nLineHeight); + } + catch (com.sun.star.uno.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + + // hold the inner group together + if (aLastGroup != null) + { + doNotBreakInTable(aLastGroup); + } + } + if (m_aSortNames != null) + { + for (String[] sortFieldName : m_aSortNames) + { + try + { + final XGroup xGroup = xGroups.createGroup(); + xGroup.setExpression(sortFieldName[0]); + xGroup.setSortAscending(PropertyNames.ASC.equals(sortFieldName[1])); + xGroup.setHeaderOn(false); + int nCount = xGroups.getCount(); + xGroups.insertByIndex(nCount, xGroup); + } + catch (java.lang.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + return lastGroupPosition; + } + + + /** + * Give a list off all field title names to insert the field title names, call layout() + */ + public void insertFieldTitles(String[] _aFieldTitleNames) + { + m_aFieldTitleNames = _aFieldTitleNames; + } + + + private String getTitleFromFieldName(String _sField) + { + for (int i = 0; i < m_aFieldNames.length; i++) + { + if (m_aFieldNames[i].equals(_sField)) + { + return m_aFieldTitleNames[i]; + } + } + return PropertyNames.EMPTY_STRING; + } + + private int getTypeFromFieldName(String _sField) + { + for (int i = 0; i < m_aFieldNames.length; i++) + { + if (m_aFieldNames[i].equals(_sField)) + { + return m_aFieldTypes[i]; + } + } + return 0; + } + + private boolean listContains(String[] _aList, String _aValue) + { + for (int i = 0; i < _aList.length; i++) + { + if (_aList[i].equals(_aValue)) + { + return true; + } + } + return false; + } + + + /** + * Helper to get all field names without the names which are already in the group names + * @param _aList + * @param _aGetResultFrom + * @return + */ + private String[] getNamesWithoutGroupNames(String[] _aList, String[] _aGetResultFrom) + { + if (_aList == null) + { + return new String[] + { + }; /* empty list */ + } + if (getCountOfGroups() == 0) + { + if (_aGetResultFrom != null) + { + return _aGetResultFrom; + } + return _aList; + } + final int nNewLength = _aList.length - getCountOfGroups(); + String[] aNewList = new String[nNewLength]; + int j = 0; + for (int i = 0; i < _aList.length; i++) + { + final String sField = _aList[i]; + if (listContains(m_aGroupNames, sField)) + { + continue; + } + if (_aGetResultFrom != null) + { + aNewList[j++] = _aGetResultFrom[i]; + } + else + { + aNewList[j++] = sField; + } + if (j == nNewLength) + { + break; // Emergency break, we leave the result list. + } + } + return aNewList; + } + + + protected int calculateFieldWidth(int _nLeftIndent, int _nFieldCount) + { + int nWidth = 3000; + if (_nFieldCount > 0) + { + nWidth = (getPageWidth() - getLeftPageIndent() - getRightPageIndent() - _nLeftIndent) / _nFieldCount; + } + return nWidth; + } + + protected String[] getFieldTitleNames() + { + return getNamesWithoutGroupNames(m_aFieldNames, m_aFieldTitleNames); + } + + + abstract protected void insertDetailFieldTitles(int lastGroupPosition); + + + /** + * Give a list off all field names to insert the field names, call layout() + */ + public void insertFieldNames(String[] _aFieldNames) + { + m_aFieldNames = _aFieldNames; + } + + public void insertFieldTypes(int[] _aFieldTypes) + { + m_aFieldTypes = _aFieldTypes; + } + + public void insertFieldWidths(int[] _aFieldWidths) + { + m_aFieldWidths = _aFieldWidths; + } + + protected int getCountOfGroups() + { + return ((m_aGroupNames == null) ? 0 : m_aGroupNames.length); + } + + + protected String[] getFieldNames() + { + return getNamesWithoutGroupNames(m_aFieldNames, null); + } + + abstract protected void insertDetailFields(); + + protected void copyDetailProperties() + { + if (getDesignTemplate() != null) + { + try + { + XSection xForeignSection = getDesignTemplate().getDetail(); + if (xForeignSection != null) + { + XSection xSection = getReportDefinition().getDetail(); + + // copy Properties + copyProperties(xForeignSection, xSection); + } + } + catch (Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + + protected Rectangle insertLabel(XSection _xSection, String _sLabel, Rectangle _aRect, int _nWidth, SectionObject _aSO) + { + if (_xSection != null) + { + try + { + final Object aFixedText = getMSFofReportDefinition().createInstance("com.sun.star.report.FixedText"); + final XFixedText xFixedText = UnoRuntime.queryInterface(XFixedText.class, aFixedText); + + + int nHeight = LayoutConstants.LabelHeight; // default height of label is fixed. + if (_aSO != null) + { + if (_aSO instanceof SectionEmptyObject) + { + float fCharWeight = _aSO.getCharWeight(com.sun.star.awt.FontWeight.NORMAL); + if (fCharWeight > 0.1f) + { + xFixedText.setCharWeight(fCharWeight); + } + } + else + { +// TODO: there seems to be some problems with copy all properties from the design template to the current design + final FontDescriptor aFD = _aSO.getFontDescriptor(); + if (aFD != null) + { + xFixedText.setFontDescriptor(aFD); + copyProperties(_aSO.getParent(), xFixedText); + } + nHeight = _aSO.getHeight(LayoutConstants.LabelHeight); + } + } + xFixedText.setLabel(_sLabel); + + xFixedText.setPositionX(_aRect.X); + xFixedText.setPositionY(_aRect.Y); + + // Width will calculate from outside. + // We have to set, because there exist no right default (0) + xFixedText.setWidth(_nWidth); + _aRect.X += _nWidth; + xFixedText.setHeight(nHeight); + _xSection.add(xFixedText); + } + catch (com.sun.star.uno.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + return _aRect; + } + + + protected String convertToFieldName(String _sElementName) + { + final StringBuffer aDataField = new StringBuffer(32); + aDataField.append("field:[").append(_sElementName).append(']'); + return aDataField.toString(); + + } + + private String convertFromFieldName(String _sName) + { + if (_sName.startsWith("field:[")) + { + int nCloseBrace = _sName.lastIndexOf(']'); + return _sName.substring(7, nCloseBrace).trim(); + } + return _sName; + } + + + /** + * Insert an already formatted field name into a given section + * + * Use 'convertToFieldName(dbfield)' to convert a dbfield name in the right. + * + * @param _xSection in which section the formatted field will store + * @param _sFormattedfield as String a dbfield or another function + * @param _aRect .X, .Y are the absolute position (1/100mm) where the formatted field will set + * @param _nWidth the width of the field in 1/100mm + * @param _aSO + * @return a new Rectangle with the new Rect.X position, Rect.Y will not change. + */ + protected Rectangle insertFormattedField(XSection _xSection, String _sFormattedfield, Rectangle _aRect, int _nWidth, SectionObject _aSO) + { + return insertFormattedField(_xSection, _sFormattedfield, _aRect, _nWidth, _aSO, (short) com.sun.star.awt.TextAlign.LEFT); + } + + private Rectangle insertFormattedField(XSection _xSection, String _sFormattedfield, Rectangle _aRect, int _nWidth, SectionObject _aSO, short _nAlignment) + { + if (_xSection != null) + { + try + { + Object aField; + int nHeight = LayoutConstants.FormattedFieldHeight; + + int nType = getTypeFromFieldName(convertFromFieldName(_sFormattedfield)); + if (nType == DataType.BINARY + || nType == DataType.VARBINARY + || nType == DataType.LONGVARBINARY) + { + aField = getMSFofReportDefinition().createInstance("com.sun.star.report.ImageControl"); + nHeight = LayoutConstants.BinaryHeight; + } + else + { + aField = getMSFofReportDefinition().createInstance("com.sun.star.report.FormattedField"); + nHeight = LayoutConstants.FormattedFieldHeight; + if (nType == DataType.LONGVARCHAR) /* memo */ + + { + nHeight = LayoutConstants.MemoFieldHeight; // special case for memo + } + } + _aRect.Height = nHeight; + + final XReportControlModel xReportControlModel = UnoRuntime.queryInterface(XReportControlModel.class, aField); + if (xReportControlModel != null) + { + // #i86907# not documented right in idl description. + xReportControlModel.setDataField(_sFormattedfield); + if (_aSO != null) + { + // TODO: there seems to be some problems with copy all properties from the design template to the current design + final FontDescriptor aFD = _aSO.getFontDescriptor(); + if (aFD != null) + { + xReportControlModel.setFontDescriptor(aFD); + copyProperties(_aSO.getParent(), xReportControlModel); + } + nHeight = _aSO.getHeight(nHeight); + } + xReportControlModel.setPositionX(_aRect.X); + xReportControlModel.setPositionY(_aRect.Y); + xReportControlModel.setWidth(_nWidth); + _aRect.X += _nWidth; + xReportControlModel.setHeight(nHeight); + + if (nType == DataType.BINARY + || nType == DataType.VARBINARY + || nType == DataType.LONGVARBINARY) + { + final XImageControl xImageControl = UnoRuntime.queryInterface(XImageControl.class, xReportControlModel); + if (xImageControl != null) + { + xImageControl.setScaleMode(com.sun.star.awt.ImageScaleMode.ISOTROPIC); + } + } + else + { + try + { + xReportControlModel.setParaAdjust(_nAlignment); + } + catch (com.sun.star.beans.UnknownPropertyException ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + // spezial case rpt:now() (default date format) + if (_sFormattedfield.equals("rpt:now()")) + { + final XFormattedField xFormattedField = UnoRuntime.queryInterface(XFormattedField.class, xReportControlModel); + + XNumberFormatsSupplier x = xFormattedField.getFormatsSupplier(); + XNumberFormats xFormats = x.getNumberFormats(); + XNumberFormatTypes x3 = UnoRuntime.queryInterface(XNumberFormatTypes.class, xFormats); + com.sun.star.lang.Locale aLocale = new com.sun.star.lang.Locale(); + aLocale.Country = Locale.getDefault().getCountry(); + aLocale.Language = Locale.getDefault().getLanguage(); + + int nFormat = x3.getStandardFormat(com.sun.star.util.NumberFormat.DATE, aLocale); + xFormattedField.setFormatKey(nFormat); + } + _xSection.add(xReportControlModel); + } + } + catch (com.sun.star.uno.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + return _aRect; + } + + +// TODO: check with Query, this code will not work with Queries + public void setTableName(int _aType, String _sTableName) + { + m_aCommandType = _aType; + m_sTableName = _sTableName; + + getReportDefinition().setCommandType(_aType); + getReportDefinition().setCommand(_sTableName); + } + private XMultiServiceFactory m_xMSF; + + private XMultiServiceFactory getMSFofReportDefinition() + { + if (m_xMSF == null) + { + m_xMSF = UnoRuntime.queryInterface(XMultiServiceFactory.class, getReportDefinition()); + } + return m_xMSF; + } + + + + + private Rectangle insertHorizontalLine(XSection _xSection, Rectangle _aRect, int _nWidth, int _nHeight) + { + return insertLine(_xSection, _aRect, _nWidth, _nHeight, 0); + } + + private Rectangle insertLine(XSection _xSection, Rectangle _aRect, int _nWidth, int _nHeight, int _nOrientation) + { + if (_xSection != null) + { + try + { + final Object aFixedLine = getMSFofReportDefinition().createInstance("com.sun.star.report.FixedLine"); + final XFixedLine xFixedLine = UnoRuntime.queryInterface(XFixedLine.class, aFixedLine); + + xFixedLine.setOrientation(_nOrientation); + // TODO: line width is fixed + xFixedLine.setLineWidth(8); + + xFixedLine.setPositionX(_aRect.X); + xFixedLine.setPositionY(_aRect.Y); + + xFixedLine.setWidth(_nWidth); + _aRect.X += _nWidth; + xFixedLine.setHeight(_nHeight); + _xSection.add(xFixedLine); + } + catch (com.sun.star.uno.Exception ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + return _aRect; + } + + + private void clearReportHeader() + { + XSection xSection; + try + { + if (getReportDefinition().getReportHeaderOn()) + { + xSection = getReportDefinition().getReportHeader(); + emptySection(xSection); + } + } + catch (com.sun.star.container.NoSuchElementException ex) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private void insertReportHeader() + { + if (getDesignTemplate() != null) + { + if (getDesignTemplate().getReportHeaderOn()) + { + // copy all Section information from Page Header to our Header + try + { + XSection xForeignSection = getDesignTemplate().getReportHeader(); + + if (xForeignSection != null) + { + getReportDefinition().setReportHeaderOn(true); + XSection xSection = getReportDefinition().getReportHeader(); + + // copy Sections + copySection(xForeignSection, xSection); + } + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + else + { + // we won't a page header + getReportDefinition().setReportHeaderOn(false); + } + } + } + + private void clearReportFooter() + { + XSection xSection; + try + { + if (getReportDefinition().getReportFooterOn()) + { + xSection = getReportDefinition().getReportFooter(); + emptySection(xSection); + } + } + catch (com.sun.star.container.NoSuchElementException e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + + private void insertReportFooter() + { + if (getDesignTemplate() != null) + { + if (getDesignTemplate().getReportFooterOn()) + { + // copy all Section information from Page Header to our Header + try + { + XSection xForeignSection = getDesignTemplate().getReportFooter(); + + if (xForeignSection != null) + { + getReportDefinition().setReportFooterOn(true); + XSection xSection = getReportDefinition().getReportFooter(); + + // copy Sections + copySection(xForeignSection, xSection); + } + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + else + { + // we won't a page header + getReportDefinition().setReportFooterOn(false); + } + } + } + + + private void clearPageHeader() + { + XSection xSection; + try + { + if (getReportDefinition().getPageHeaderOn()) + { + xSection = getReportDefinition().getPageHeader(); + emptySection(xSection); + } + } + catch (com.sun.star.container.NoSuchElementException e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + + private void clearPageFooter() + { + XSection xSection; + try + { + if (getReportDefinition().getPageFooterOn()) + { + xSection = getReportDefinition().getPageFooter(); + emptySection(xSection); + } + } + catch (com.sun.star.container.NoSuchElementException e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + + public void setPageOrientation(int _nOrientation) + { + final int nWidth = getFromPageStyles(PropertyNames.PROPERTY_WIDTH, 0); + final int nHeight = getFromPageStyles(PropertyNames.PROPERTY_HEIGHT, 0); + + if (com.sun.star.wizards.report.ReportLayouter.SOOPTLANDSCAPE == _nOrientation) + { + setToPageStyles("IsLandscape", Boolean.TRUE); + if (nWidth < nHeight) + { + setToPageStyles(PropertyNames.PROPERTY_WIDTH, Integer.valueOf(nHeight)); + setToPageStyles(PropertyNames.PROPERTY_HEIGHT, Integer.valueOf(nWidth)); + } + } + else + { + setToPageStyles("IsLandscape", Boolean.FALSE); + if (nHeight < nWidth) + { + setToPageStyles(PropertyNames.PROPERTY_WIDTH, Integer.valueOf(nHeight)); + setToPageStyles(PropertyNames.PROPERTY_HEIGHT, Integer.valueOf(nWidth)); + } + } + // dirty the PageWidth + m_nPageWidth = -1; + } + + /** + * Returns the width and height of a given string (_sText) in 1/100mm drawn in the given font descriptor. + * TODO: This function is a performance leak, we could store already calculated values in a map, to build a cache. Access should be much faster then. + * + * @param _sText + * @param _aFont + * @return width of given text in 1/100mm + */ + private Size getPreferredSize(String _sText, FontDescriptor _aFont) + { + Size aSizeMM_100TH = new Size(0, 0); + try + { + + final Object aFixedTextModel = getGlobalMSF().createInstance("com.sun.star.awt.UnoControlFixedTextModel"); + final XControlModel xFixedTextModel = UnoRuntime.queryInterface(XControlModel.class, aFixedTextModel); + + final PropertySetHelper aPropertySetHelper = new PropertySetHelper(xFixedTextModel); + aPropertySetHelper.setPropertyValueDontThrow(PropertyNames.FONT_DESCRIPTOR, _aFont); + + final Object aUnoCtrlFixedText = getGlobalMSF().createInstance("com.sun.star.awt.UnoControlFixedText"); + + final XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, aUnoCtrlFixedText); + xWindow.setVisible(false); + + final XControl xControl = UnoRuntime.queryInterface(XControl.class, aUnoCtrlFixedText); + xControl.setModel(xFixedTextModel); + + final com.sun.star.awt.XFixedText xFixedText = UnoRuntime.queryInterface(com.sun.star.awt.XFixedText.class, aUnoCtrlFixedText); + xFixedText.setText(_sText); + + final XLayoutConstrains xLayoutConstraints = UnoRuntime.queryInterface(XLayoutConstrains.class, aUnoCtrlFixedText); + final Size aSizeInPixel = xLayoutConstraints.getPreferredSize(); + + final XWindowPeer xPeerOfReportDefinition = UnoRuntime.queryInterface(XWindowPeer.class, getReportDefinition().getCurrentController().getFrame().getComponentWindow()); + xControl.createPeer(null, xPeerOfReportDefinition); + + final XWindowPeer x = xControl.getPeer(); + + final XUnitConversion xConversion = UnoRuntime.queryInterface(XUnitConversion.class, x); + aSizeMM_100TH = xConversion.convertSizeToLogic(aSizeInPixel, com.sun.star.util.MeasureUnit.MM_100TH); + // we don't need the created objects any longer + final XComponent xFixedTextDeleter = UnoRuntime.queryInterface(XComponent.class, xFixedText); + xFixedTextDeleter.dispose(); + + final XComponent xFixedTextModelDeleter = UnoRuntime.queryInterface(XComponent.class, aFixedTextModel); + xFixedTextModelDeleter.dispose(); + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + return aSizeMM_100TH; + } + + private String getTableName() + { + if (m_sTableName != null) + { + return m_sTableName; + } + return PropertyNames.EMPTY_STRING; + } + + private String getUserNameFromConfiguration() + { + String sFirstName = PropertyNames.EMPTY_STRING; + String sLastName = PropertyNames.EMPTY_STRING; + try + { + Object oProdNameAccess = Configuration.getConfigurationRoot(getGlobalMSF(), "org.openoffice.UserProfile/Data", false); + sFirstName = (String) Helper.getUnoObjectbyName(oProdNameAccess, "givenname"); + sLastName = (String) Helper.getUnoObjectbyName(oProdNameAccess, "sn"); + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + return sFirstName + PropertyNames.SPACE + sLastName; + } + + /** + * Helper function, to copy all not read only properties of _xFromSection to _xToSection + * @param _aFrom + * @param _aTo + */ + private void copyProperties(Object _aFrom, Object _aTo) + { + XPropertySet xFrom = UnoRuntime.queryInterface(XPropertySet.class, _aFrom); + XPropertySet xTo = UnoRuntime.queryInterface(XPropertySet.class, _aTo); + + + XPropertySetInfo xForeignPropInfo = xFrom.getPropertySetInfo(); + XPropertySetInfo xSectionPropInfo = xTo.getPropertySetInfo(); + Property[] aAllProperties = xForeignPropInfo.getProperties(); + for (int i = 0; i < aAllProperties.length; i++) + { + String sPropertyName = aAllProperties[i].Name; + if (xSectionPropInfo.hasPropertyByName(sPropertyName)) + { + try + { + Property aDestProp = xForeignPropInfo.getPropertyByName(sPropertyName); + if ((aDestProp.Attributes & PropertyAttribute.READONLY) == 0) + { + xTo.setPropertyValue(sPropertyName, xFrom.getPropertyValue(sPropertyName)); + } + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + } + } + + /** + * Helper function to copy the whole content of _xFromSection to the _xToSection + * @param _xFromSection + * @param _xToSection + */ + private void copySection(XSection _xFromSection, XSection _xToSection) + { + copyProperties(_xFromSection, _xToSection); + + try + { + XEnumeration xEnum = _xFromSection.createEnumeration(); + while (xEnum.hasMoreElements()) + { + Object aEnumObj = xEnum.nextElement(); + XReportComponent aComponent = UnoRuntime.queryInterface(XReportComponent.class, aEnumObj); + + if (aComponent != null) + { + Object aClone = aComponent.createClone(); + if (aClone != null) + { + XShape aShape = UnoRuntime.queryInterface(XShape.class, aClone); + + // normally 'createClone' will create a real clone of the component, + // but there seems some problems, we have to control. + copyProperties(aComponent, aClone); + + // aShape.setPosition(aComponent.getPosition()); + // aShape.setSize(aComponent.getSize()); + _xToSection.add(aShape); + } + } + } + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + + private void insertPageHeader() + { + if (getDesignTemplate() != null) + { + if (getDesignTemplate().getPageHeaderOn()) + { + // copy all Section information from Page Header to our Header + try + { + XSection xForeignSection = getDesignTemplate().getPageHeader(); + + if (xForeignSection != null) + { + getReportDefinition().setPageHeaderOn(true); + XSection xSection = getReportDefinition().getPageHeader(); + + // copy Sections + copySection(xForeignSection, xSection); + } + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + else + { + // we won't a page header + // getReportDefinition().setPageHeaderOn(true); + getReportDefinition().setPageHeaderOn(false); + } + } + else + { + if (getReportDefinition() == null) + { + return; + } + // there is no foreign report definition + // TODO: #i86902# rpt:Title() out of the document + + // TODO: #i86902# rpt:Author() can't set with something like rpt:author() + // TODO: #i86902# more fieldnames need. + final String sTitleTitle = getResource().getResText("RID_REPORT_86"); // "Title:" + final String sTitle = getTableName(); // "Default title, this is a first draft report generated by the new report wizard."; + final String sAuthorTitle = getResource().getResText("RID_REPORT_87"); // "Author:" + final String sAuthor = getUserNameFromConfiguration(); // "You"; + final String sDateTitle = getResource().getResText("RID_REPORT_88"); // "Date:" + // TODO: #i86911# Date: we need to set the style of the date. + final String sDate = "rpt:now()"; + + try + { + getReportDefinition().setPageHeaderOn(true); + XSection xSection = null; + xSection = getReportDefinition().getPageHeader(); + + Rectangle aRect = new Rectangle(); + aRect.X = getLeftPageIndent(); + SectionObject aSOLabel = SectionEmptyObject.create(); + aSOLabel.setFontToBold(); + aRect.Y = aSOLabel.getHeight(LayoutConstants.LabelHeight); + + final int nWidth = 3000; + + aRect = insertLabel(xSection, sTitleTitle, aRect, nWidth, aSOLabel); + + final int nTitleWidth = getPageWidth() - getLeftPageIndent() - getRightPageIndent() - 3000; + aRect = insertLabel(xSection, sTitle, aRect, nTitleWidth, aSOLabel); + + aRect.Y += aSOLabel.getHeight(LayoutConstants.LabelHeight) + LayoutConstants.LineHeight; + + aRect.X = getLeftPageIndent(); + aRect = insertLabel(xSection, sAuthorTitle, aRect, nWidth, aSOLabel); + aRect = insertLabel(xSection, sAuthor, aRect, nTitleWidth, aSOLabel); + + aRect.Y += aSOLabel.getHeight(LayoutConstants.LabelHeight); + + aRect.X = getLeftPageIndent(); + aRect = insertLabel(xSection, sDateTitle, aRect, nWidth, aSOLabel); + aRect = insertFormattedField(xSection, sDate, aRect, nTitleWidth, aSOLabel); + + aRect.Y += aSOLabel.getHeight(LayoutConstants.FormattedFieldHeight) + LayoutConstants.LineHeight; + + // draw a line under the label/formattedfield + aRect.X = getLeftPageIndent(); + final int nLineWidth = getPageWidth() - getRightPageIndent() - aRect.X; + final int nLineHeight = LayoutConstants.LineHeight; + insertHorizontalLine(xSection, aRect, nLineWidth, nLineHeight); + + aRect.Y += nLineHeight; + + xSection.setHeight(aRect.Y); + } + catch (com.sun.star.uno.Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + } + + private void insertPageFooter() + { + if (getDesignTemplate() != null) + { + if (getDesignTemplate().getPageFooterOn()) + { + try + { + XSection xForeignSection = getDesignTemplate().getPageFooter(); + + if (xForeignSection != null) + { + getReportDefinition().setPageFooterOn(true); + XSection xSection = getReportDefinition().getPageFooter(); + + // copy Sections + copySection(xForeignSection, xSection); + } + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + else + { + getReportDefinition().setPageFooterOn(false); + } + } + else + { + if (getReportDefinition() == null) + { + return; + } + + // TODO: how should we arrive this code (set page and pagecount in the middle of the page footer) + // If there exists a design template, don't use it. + + // we don't have a default report definition + final String sPageOf = getResource().getResText("RID_REPORT_89"); // 'Page #page# of #count#' + + // Convert + // 'Page #page# of #count#' + // to something like + // '\"Page \" & PageNumber() & \" of \" & PageCount()' + // due to the fact that it is not fixed, where #page# or #count# occurs, we make it + // a little bit trickier. + // we first surround the string with double quotes, + // second, replace the #...# + // last, we remove double 'double quotes'. + final String sSurroundDoubleQuotes = "\"" + sPageOf + "\""; + final String sPageNumber = sSurroundDoubleQuotes.replaceAll("#page#", "\" & PageNumber() & \""); + final String sPageCount = sPageNumber.replaceAll("#count#", "\" & PageCount() & \""); + final String sNoLastUnusedQuotes = sPageCount.replaceAll(" & \\\"\\\"", PropertyNames.EMPTY_STRING); + final String sNoFirstUnusedQuotes = sNoLastUnusedQuotes.replaceAll("\\\"\\\" & ", PropertyNames.EMPTY_STRING); + + final int nUsablePageWidth = getPageWidth() - getLeftPageIndent() - getRightPageIndent(); + + try + { + getReportDefinition().setPageFooterOn(true); + XSection xSection = null; + xSection = getReportDefinition().getPageFooter(); + + Rectangle aRect = new Rectangle(); + aRect.X = getLeftPageIndent(); + + // draw a line over the label/formattedfield + final int nLineWidth = getPageWidth() - getRightPageIndent() - aRect.X; + final int nLineHeight = LayoutConstants.LineHeight; + insertHorizontalLine(xSection, aRect, nLineWidth, nLineHeight); + + aRect.Y += nLineHeight; + aRect.Y += LayoutConstants.LabelHeight; + + aRect.X = getLeftPageIndent(); + + aRect = insertFormattedField(xSection, "rpt:" + sNoFirstUnusedQuotes, aRect, nUsablePageWidth, null, (short) com.sun.star.awt.TextAlign.CENTER); + + aRect.Y += LayoutConstants.FormattedFieldHeight + LayoutConstants.LineHeight; + xSection.setHeight(aRect.Y); + } + catch (Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + } + + protected Resource getResource() + { + return m_aResource; + } + private int m_aCommandType; // Table or Query + private String m_sTableName; + private String[] m_aGroupNames; + private String[] m_aFieldNames; + private String[] m_aFieldTitleNames; + private int[] m_aFieldWidths; + private int[] m_aFieldTypes; + private DesignTemplate m_xDesignTemplate = null; + + public void initializeData(IReportBuilderLayouter _aOther) + { + if (_aOther instanceof ReportBuilderLayouter) + { + final ReportBuilderLayouter aOther = (ReportBuilderLayouter) _aOther; + m_aCommandType = aOther.m_aCommandType; + m_sTableName = aOther.m_sTableName; + m_aGroupNames = aOther.m_aGroupNames; + m_aFieldNames = aOther.m_aFieldNames; + m_aFieldTitleNames = aOther.m_aFieldTitleNames; + m_aFieldWidths = aOther.m_aFieldWidths; + m_aFieldTypes = aOther.m_aFieldTypes; + m_xDesignTemplate = aOther.m_xDesignTemplate; + + // dirty PageWidth + m_nPageWidth = -1; + } + } + + /** + * Get the maximal label width of all labels + * @return the width in 1/100mm + */ + protected int getMaxLabelWidth() + { + int nWidth = 0; + final String[] aFieldTitles = m_aFieldTitleNames; // we want all Field Titles here // getFieldTitleNames(); + for (int i = 0; i < aFieldTitles.length; i++) + { + final String sLabel = aFieldTitles[i]; + nWidth = Math.max(nWidth, getLabelWidth(sLabel)); + } + for (int i = 0; i < m_aGroupNames.length; i++) + { + final String sGroupName = m_aGroupNames[i]; + final SectionObject a = getDesignTemplate().getGroupLabel(i); + final FontDescriptor aFD = a.getFontDescriptor(); + nWidth = Math.max(nWidth, getLabelWidth(sGroupName, aFD)); + } + + if (nWidth == 0) + { + nWidth = 3000; + } + else + { + nWidth += 500; + } + return nWidth; + } + + /** + * Get width of a given string (Label) in 1/100mm + * @param _sLabel + * @return the width in 1/100mm + */ + private int getLabelWidth(String _sLabel) + { + return getLabelWidth(_sLabel, 0.0f, 0.0f); + } + private XFixedText m_aFixedTextHelper = null; + private HashMap<String, Integer> m_aLabelWidthMap; + + private int getLabelWidth(String _sLabel, FontDescriptor _aFD) + { + float fCharWeight = 0.0f; + float fCharHeight = 0.0f; + if (_aFD != null) + { + fCharWeight = _aFD.Weight; + fCharHeight = _aFD.Height; + } + return getLabelWidth(_sLabel, fCharWeight, fCharHeight); + } + + private int getLabelWidth(String _sLabel, float _nCharWeight, float _nCharHeight) + { + int nWidth = 0; + + if (m_aLabelWidthMap == null) + { + m_aLabelWidthMap = new HashMap<String, Integer>(); + } + // At first, try to get the Width out of a HashMap (Cache) + StringBuffer aKey = new StringBuffer(40); + final String sKey = aKey.append(_sLabel).append(_nCharWeight).append(_nCharHeight).toString(); + if (m_aLabelWidthMap.containsKey(sKey)) + { + final Object aWidth = m_aLabelWidthMap.get(sKey); + final Integer aIntegerWidth = (Integer) aWidth; + nWidth = aIntegerWidth.intValue(); + } + else + { + try + { + if (m_aFixedTextHelper == null) + { + final Object aFixedText = getMSFofReportDefinition().createInstance("com.sun.star.report.FixedText"); + m_aFixedTextHelper = UnoRuntime.queryInterface(XFixedText.class, aFixedText); + } + + m_aFixedTextHelper.setLabel(_sLabel); + if (_nCharWeight > 0.1f) + { + m_aFixedTextHelper.setCharWeight(_nCharWeight); + } + if (_nCharHeight > 0.1f) + { + m_aFixedTextHelper.setCharHeight(_nCharHeight); + } + + final FontDescriptor xFont = m_aFixedTextHelper.getFontDescriptor(); + final Size aSize = getPreferredSize(_sLabel, xFont); + nWidth = aSize.Width; + // cache the found width + m_aLabelWidthMap.put(sKey, Integer.valueOf(nWidth)); + } + catch (com.sun.star.uno.Exception e) + { + Logger.getLogger(ReportBuilderLayouter.class.getName()).log(Level.SEVERE, null, e); + } + } + return nWidth; + } + + protected void doNotBreakInTable(Object _xSectionOrGroup) + { + final PropertySetHelper aHelper = new PropertySetHelper(_xSectionOrGroup); + aHelper.setPropertyValueDontThrow("KeepTogether", Boolean.TRUE); + } + + protected DesignTemplate getDesignTemplate() + { + if (m_xDesignTemplate == null) + { + // initialise the report definition. + String sDefaultHeaderLayout = m_xReportDefinitionReadAccess.getDefaultHeaderLayout(); + loadAndSetBackgroundTemplate(sDefaultHeaderLayout); + } + return m_xDesignTemplate; + } + + /** + * If there already exists a foreign report definition, which we use to get the layout from + * close it. + * Veto is not allowed here. + */ + private void closeDesignTemplate() + { + if (m_xDesignTemplate != null) + { + m_xDesignTemplate.close(); + m_xDesignTemplate = null; + } + } + + /** + * load the given string as a template and use its content to paint the other + */ + public void loadAndSetBackgroundTemplate(String LayoutTemplatePath) + { + closeDesignTemplate(); + + String sName = FileAccess.getFilename(LayoutTemplatePath); + if (sName.equalsIgnoreCase("default.otr_") + || LayoutTemplatePath.equals("DefaultLayoutOfHeaders")) + { + // this is the default layout, we don't want to have a layout for this. + } + else + { + XMultiServiceFactory xMSF = getGlobalMSF(); + m_xDesignTemplate = DesignTemplate.create(xMSF, LayoutTemplatePath); + } + } +} |