1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
30 
31 #include "ChartDropTargetHelper.hxx"
32 #include "DiagramHelper.hxx"
33 #include "DataSourceHelper.hxx"
34 
35 #include <com/sun/star/chart2/XChartDocument.hpp>
36 #include <com/sun/star/chart2/data/XDataProvider.hpp>
37 #include <com/sun/star/container/XChild.hpp>
38 
39 #include <sot/formats.hxx>
40 #include <vector>
41 
42 using namespace ::com::sun::star;
43 
44 using ::com::sun::star::uno::Reference;
45 using ::com::sun::star::uno::Sequence;
46 using ::rtl::OUString;
47 
48 namespace
49 {
50 
51 ::std::vector< OUString > lcl_getStringsFromByteSequence(
52     const Sequence< sal_Int8 > & aByteSequence )
53 {
54     ::std::vector< OUString > aResult;
55     const sal_Int32 nLength = aByteSequence.getLength();
56     const sal_Char * pBytes( reinterpret_cast< const sal_Char* >( aByteSequence.getConstArray()));
57     sal_Int32 nStartPos = 0;
58     for( sal_Int32 nPos=0; nPos<nLength; ++nPos )
59     {
60         if( pBytes[nPos] == '\0' )
61         {
62             aResult.push_back( OUString( pBytes + nStartPos, (nPos - nStartPos), RTL_TEXTENCODING_ASCII_US ));
63             nStartPos = nPos + 1;
64         }
65     }
66     return aResult;
67 }
68 
69 } // anonymous namespace
70 
71 namespace chart
72 {
73 
74 ChartDropTargetHelper::ChartDropTargetHelper(
75     const Reference< datatransfer::dnd::XDropTarget >& rxDropTarget,
76     const Reference< chart2::XChartDocument > & xChartDocument ) :
77         DropTargetHelper( rxDropTarget ),
78         m_xChartDocument( xChartDocument )
79 {}
80 
81 ChartDropTargetHelper::~ChartDropTargetHelper()
82 {}
83 
84 bool ChartDropTargetHelper::satisfiesPrerequisites() const
85 {
86     return  ( m_xChartDocument.is() &&
87               ! m_xChartDocument->hasInternalDataProvider());
88 }
89 
90 sal_Int8 ChartDropTargetHelper::AcceptDrop( const AcceptDropEvent& rEvt )
91 {
92     sal_Int8 nResult = DND_ACTION_NONE;
93 
94     if( ( rEvt.mnAction == DND_ACTION_COPY ||
95           rEvt.mnAction == DND_ACTION_MOVE ) &&
96         satisfiesPrerequisites() &&
97         IsDropFormatSupported( SOT_FORMATSTR_ID_LINK ) )
98     {
99         // @todo: check if the data is suitable. Is this possible without XTransferable?
100         nResult = rEvt.mnAction;
101     }
102 
103     return nResult;
104 }
105 
106 sal_Int8 ChartDropTargetHelper::ExecuteDrop( const ExecuteDropEvent& rEvt )
107 {
108     sal_Int8 nResult = DND_ACTION_NONE;
109 
110     if( ( rEvt.mnAction == DND_ACTION_COPY ||
111           rEvt.mnAction == DND_ACTION_MOVE ) &&
112         rEvt.maDropEvent.Transferable.is() &&
113         satisfiesPrerequisites())
114     {
115         TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable );
116         if( aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK ))
117         {
118             Sequence< sal_Int8 > aBytes;
119             if( aDataHelper.GetSequence( SOT_FORMATSTR_ID_LINK, aBytes ))
120             {
121                 ::std::vector< OUString > aStrings( lcl_getStringsFromByteSequence( aBytes ));
122                 if( aStrings.size() >= 3 &&
123                     aStrings[0].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "soffice" )))
124                 {
125                     OUString aDocName( aStrings[1] );
126                     OUString aRangeString( aStrings[2] );
127                     Reference< container::XChild > xChild( m_xChartDocument, uno::UNO_QUERY );
128                     if( xChild.is())
129                     {
130                         Reference< frame::XModel > xParentModel( xChild->getParent(), uno::UNO_QUERY );
131                         if( xParentModel.is() &&
132                             m_xChartDocument.is())
133                         {
134                             bool bDataComesFromParent = true;
135                             // @todo: get the title somehow and compare it to
136                             // aDocName if successful (the document is the
137                             // parent)
138                             if( bDataComesFromParent )
139                             {
140                                 Reference< chart2::XDiagram > xDiagram( m_xChartDocument->getFirstDiagram() );
141                                 Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider());
142                                 if( xDataProvider.is() && xDiagram.is() &&
143                                     DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument ))
144                                 {
145                                     Reference< chart2::data::XDataSource > xDataSource(
146                                         DataSourceHelper::pressUsedDataIntoRectangularFormat( m_xChartDocument ));
147                                     Sequence< beans::PropertyValue > aArguments(
148                                         xDataProvider->detectArguments( xDataSource ));
149 
150                                     OUString aOldRange;
151                                     beans::PropertyValue * pCellRange = 0;
152                                     for( sal_Int32 i=0; i<aArguments.getLength(); ++i )
153                                     {
154                                         if( aArguments[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CellRangeRepresentation")))
155                                         {
156                                             pCellRange = (aArguments.getArray() + i);
157                                             aArguments[i].Value >>= aOldRange;
158                                             break;
159                                         }
160                                     }
161                                     if( pCellRange )
162                                     {
163                                         // copy means add ranges, move means replace
164                                         if( rEvt.mnAction == DND_ACTION_COPY )
165                                         {
166                                             // @todo: using implcit knowledge that ranges can be
167                                             // merged with ";". This should be done more general
168                                             pCellRange->Value <<= (aOldRange + OUString( sal_Unicode(';')) + aRangeString );
169                                         }
170                                         // move means replace range
171                                         else
172                                         {
173                                             pCellRange->Value <<= aRangeString;
174                                         }
175 
176                                         xDataSource.set( xDataProvider->createDataSource( aArguments ));
177                                         xDiagram->setDiagramData( xDataSource, aArguments );
178 
179                                         // always return copy state to avoid deletion of the dragged range
180                                         nResult = DND_ACTION_COPY;
181                                     }
182                                 }
183                             }
184                         }
185                     }
186                 }
187             }
188         }
189     }
190     return nResult;
191 }
192 
193 } //  namespace chart
194