/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 *  The Contents of this file are made available subject to the terms of
 *  the BSD license.
 *
 *  Copyright 2000, 2010 Oracle and/or its affiliates.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *************************************************************************/
import com.sun.star.awt.Rectangle;

import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.XPropertySet;

import com.sun.star.chart.XDiagram;
import com.sun.star.chart.XChartDocument;

import com.sun.star.container.XNameAccess;
import com.sun.star.container.XIndexAccess;

import com.sun.star.document.XEmbeddedObjectSupplier;

import com.sun.star.frame.XComponentLoader;

import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XMultiComponentFactory;

import com.sun.star.sheet.XSpreadsheets;
import com.sun.star.sheet.XSpreadsheet;
import com.sun.star.sheet.XSpreadsheetDocument;
import com.sun.star.sheet.XCellRangeAddressable;

import com.sun.star.table.XTableChart;
import com.sun.star.table.XTableCharts;
import com.sun.star.table.XCell;
import com.sun.star.table.XCellRange;
import com.sun.star.table.XTableChartsSupplier;
import com.sun.star.table.CellRangeAddress;

import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XInterface;
import com.sun.star.uno.XComponentContext;



/** This class loads an OpenOffice.org Calc document and changes the type of the
 * embedded chart.
 */
public class ChartTypeChange {

    /** Table chart, which type will be changed.
     */
    private XTableChart xtablechart = null;

    /** Service factory
     */
    private final XMultiComponentFactory xMCF;

    /** Component context
     */
    private final XComponentContext xCompContext;

    /** Beginning of the program.
     * @param args No arguments will be passed to the class.
     */
    public static void main(String args[]) {
        try {
            ChartTypeChange charttypechange = new ChartTypeChange();

            // Double array holding all values the chart should be based on.
            String[][] stringValues = {
                { "", "Jan", "Feb", "Mar", "Apr", "Mai" },
                { "Profit", "12.3", "43.2", "5.1", "76", "56.8" },
                { "Rival in business", "12.2", "12.6", "17.7", "20.4", "100" },
            };

            // Create the chart with
            charttypechange.getChart( stringValues );

            String[] stringChartType = {
                "com.sun.star.chart.LineDiagram",
                "com.sun.star.chart.BarDiagram",
                "com.sun.star.chart.PieDiagram",
                "com.sun.star.chart.NetDiagram",
                "com.sun.star.chart.XYDiagram",
                "com.sun.star.chart.StockDiagram",
                "com.sun.star.chart.AreaDiagram"
            };

            for ( int intCounter = 0; intCounter < stringChartType.length;
                  intCounter++ ) {
                charttypechange.changeChartType( stringChartType[ intCounter ],
                                                 false );
                Thread.sleep( 3000 );
            }

            System.exit(0);
        }
        catch( Exception exception ) {
            System.err.println( exception );
        }
    }

    /** The constructor connects to the OpenOffice.org.
     * @throws Exception All exceptions are thrown from this method.
     */
    public ChartTypeChange()
        throws Exception {

        /* Bootstraps a component context. Component context to be granted
           to a component for running. Arbitrary values can be retrieved
           from the context. */
        xCompContext = com.sun.star.comp.helper.Bootstrap.bootstrap();

        /* Gets the service manager instance to be used (or null). This method has
           been added for convenience, because the service manager is an often used
           object. */
        xMCF = xCompContext.getServiceManager();
    }

    /** This method will change the type of a specified chart.
     * @param stringType The chart will be converted to this type.
     * @param booleanIs3D If the chart should be displayed in 3D this parameter should be set to true.
     * @throws Exception All exceptions are thrown from this method.
     */
    public void changeChartType( String stringType, boolean booleanIs3D )
    throws Exception {
        XEmbeddedObjectSupplier xEmbeddedObjSupplier = UnoRuntime.queryInterface(XEmbeddedObjectSupplier.class, xtablechart);
        XInterface xInterface = xEmbeddedObjSupplier.getEmbeddedObject();

        XChartDocument xChartDoc = UnoRuntime.queryInterface(
            XChartDocument.class, xInterface);
        XDiagram xDiagram = xChartDoc.getDiagram();
        XMultiServiceFactory xMSF = UnoRuntime.queryInterface( XMultiServiceFactory.class, xChartDoc );
        Object object = xMSF.createInstance( stringType );
        xDiagram = UnoRuntime.queryInterface(XDiagram.class, object);

        XPropertySet xPropSet = UnoRuntime.queryInterface(
            XPropertySet.class, xDiagram );
        xPropSet.setPropertyValue( "Dim3D", Boolean.valueOf( booleanIs3D ) );

        xChartDoc.setDiagram(xDiagram);
    }

    /** Loading an OpenOffice.org Calc document and getting a chart by name.
     * @param stringFileName Name of the OpenOffice.org Calc document which should
     *                       be loaded.
     * @param stringChartName Name of the chart which should get a new chart type.
     */
    public void getChart( String stringFileName, String stringChartName ) {
        try {
            /* A desktop environment contains tasks with one or more
               frames in which components can be loaded. Desktop is the
               environment for components which can instantiate within
               frames. */
            XComponentLoader xComponentloader = UnoRuntime.queryInterface( XComponentLoader.class,
                xMCF.createInstanceWithContext("com.sun.star.frame.Desktop",
                                               xCompContext ) );

            // Load a Writer document, which will be automatically displayed
            XComponent xComponent = xComponentloader.loadComponentFromURL(
            "file:///" + stringFileName, "_blank", 0,
            new PropertyValue[0] );

            // Query for the interface XSpreadsheetDocument
            XSpreadsheetDocument xSpreadSheetDocument = UnoRuntime.queryInterface( XSpreadsheetDocument.class, xComponent );

            XSpreadsheets xSpreadsheets = xSpreadSheetDocument.getSheets() ;

            XIndexAccess xIndexAccess = UnoRuntime.queryInterface(XIndexAccess.class, xSpreadsheets );

            XSpreadsheet xSpreadsheet = UnoRuntime.queryInterface(
                XSpreadsheet.class, xIndexAccess.getByIndex(0));

            XTableChartsSupplier xTableChartsSupplier = UnoRuntime.queryInterface( XTableChartsSupplier.class, xSpreadsheet );

            xIndexAccess = UnoRuntime.queryInterface(
                XIndexAccess.class, xTableChartsSupplier.getCharts() );

            this.xtablechart = UnoRuntime.queryInterface(
                XTableChart.class,  xIndexAccess.getByIndex( 0 ) );
        }
        catch( Exception exception ) {
            System.err.println( exception );
        }
    }

    /** Creating an empty OpenOffice.org Calc document, inserting data, and getting a
     * chart by name.
     * @param stringValues Double array with the values for the chart.
     */
    public void getChart( String[][] stringValues ) {
        try {
            /* A desktop environment contains tasks with one or more
               frames in which components can be loaded. Desktop is the
               environment for components which can instantiate within
               frames. */
            XComponentLoader xcomponentloader = UnoRuntime.queryInterface( XComponentLoader.class,
                                       xMCF.createInstanceWithContext(
                                           "com.sun.star.frame.Desktop",
                                           xCompContext ) );

            // Create an empty calc document, which will be automatically displayed
            XComponent xComponent = xcomponentloader.loadComponentFromURL(
            "private:factory/scalc", "_blank", 0,
            new PropertyValue[0] );

            // Query for the interface XSpreadsheetDocument
            XSpreadsheetDocument xspreadsheetdocument = UnoRuntime.queryInterface( XSpreadsheetDocument.class, xComponent );

            // Get all sheets of the spreadsheet document.
            XSpreadsheets xspreadsheets = xspreadsheetdocument.getSheets() ;

            // Get the index of the spreadsheet document.
            XIndexAccess xindexaccess = UnoRuntime.queryInterface(
                XIndexAccess.class, xspreadsheets );

            // Get the first spreadsheet.
            XSpreadsheet xspreadsheet = UnoRuntime.queryInterface(
                XSpreadsheet.class, xindexaccess.getByIndex(0));

            // The double array will written to the spreadsheet
            for ( int intY = 0; intY < stringValues.length; intY++ ) {
                for ( int intX = 0; intX < stringValues[ intY ].length;
                intX++ ) {
                    // Insert the value to the cell, specified by intY and intX.
                    ChartTypeChange.insertIntoCell( intY, intX,
                    stringValues[ intY ][ intX ], xspreadsheet, "" );
                }
            }

            // Create a rectangle, which holds the size of the chart.
            Rectangle rectangle = new Rectangle();
            rectangle.X = 500;
            rectangle.Y = 3000;
            rectangle.Width = 25000;
            rectangle.Height = 11000;

            // Get the cell range of the spreadsheet.
            XCellRange xcellrange = UnoRuntime.queryInterface(
                XCellRange.class, xspreadsheet );

            // Create the Unicode of the character for the column name.
            char charRectangle = ( char ) ( 65 + stringValues.length - 1 );

            // Get maximum length all rows in the double array.
            int intMaximumWidthRow = 0;
            for ( int intRow = 0; intRow < stringValues.length; intRow++ ) {
                if ( stringValues[ intRow ].length > intMaximumWidthRow ) {
                    intMaximumWidthRow = stringValues[ intRow ].length;
                }
            }

            // Get the cell range of the written values.
            XCellRange xcellrangeChart = xcellrange.getCellRangeByName( "A1:" +
            charRectangle + intMaximumWidthRow );

            // Get the addressable cell range.
            XCellRangeAddressable xcellrangeaddressable =
            UnoRuntime.queryInterface(
                XCellRangeAddressable.class, xcellrangeChart );

            // Get the cell range address.
            CellRangeAddress cellrangeaddress = xcellrangeaddressable.getRangeAddress();

            // Create the cell range address for the chart.
            CellRangeAddress[] cellrangeaddressChart =
            new CellRangeAddress[ 1 ];
            cellrangeaddressChart[ 0 ] = cellrangeaddress;

            // Get the table charts supplier of the spreadsheet.
            XTableChartsSupplier xtablechartssupplier = UnoRuntime.queryInterface( XTableChartsSupplier.class, xspreadsheet );

            // Get all table charts of the spreadsheet.
            XTableCharts xtablecharts = xtablechartssupplier.getCharts();

            // Create a table chart with all written values.
            xtablecharts.addNewByName( "Example", rectangle,
            cellrangeaddressChart, true, true );

            // Get the created table chart.
            this.xtablechart = UnoRuntime.queryInterface(
                XTableChart.class, UnoRuntime.queryInterface(
                    XNameAccess.class, xtablecharts ).getByName( "Example" ));
        }
        catch( Exception exception ) {
            System.err.println( exception );
        }
    }

    /** Inserting a given value to a cell, that is specified by the parameters intX
     * and intY.
     * @param intX Column on the spreadsheet.
     * @param intY Row on the spreadsheet.
     * @param stringValue Value to be inserted to a cell.
     * @param xspreadsheet Spreadsheet of the cell, which will be changed.
     * @param stringFlag If the value of stringFlag is "V", the stringValue
     *                   will be converted to the
     * float type. Otherwise the stringValue will be written as a formula.
     */
    public static void insertIntoCell( int intX, int intY, String stringValue,
                                       XSpreadsheet xspreadsheet, String stringFlag )
    {
        XCell xcell = null;

        try {
            xcell = xspreadsheet.getCellByPosition( intX, intY );
        }
        catch ( com.sun.star.lang.IndexOutOfBoundsException exception ) {
            System.out.println( "Could not get cell." );
        }
        if ( stringFlag.equals( "V" ) ) {
            xcell.setValue( ( Float.valueOf( stringValue ) ).floatValue() );
        }
        else {
            xcell.setFormula( stringValue );
        }
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
