1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package complex.sfx2.undo;
25 
26 import com.sun.star.chart2.XAxis;
27 import com.sun.star.chart2.XCoordinateSystem;
28 import com.sun.star.chart2.XCoordinateSystemContainer;
29 import com.sun.star.awt.Size;
30 import com.sun.star.beans.NamedValue;
31 import com.sun.star.beans.XPropertySet;
32 import com.sun.star.chart2.XChartDocument;
33 import com.sun.star.chart2.XDiagram;
34 import com.sun.star.container.XIndexAccess;
35 import com.sun.star.document.UndoFailedException;
36 import com.sun.star.document.XUndoAction;
37 import com.sun.star.document.XUndoManager;
38 import com.sun.star.document.XUndoManagerSupplier;
39 import com.sun.star.drawing.XShape;
40 import com.sun.star.embed.EmbedStates;
41 import com.sun.star.embed.EmbedVerbs;
42 import com.sun.star.embed.VerbDescriptor;
43 import com.sun.star.embed.WrongStateException;
44 import com.sun.star.embed.XEmbeddedObject;
45 import com.sun.star.embed.XStateChangeBroadcaster;
46 import com.sun.star.embed.XStateChangeListener;
47 import com.sun.star.lang.EventObject;
48 import com.sun.star.lang.IndexOutOfBoundsException;
49 import com.sun.star.lang.WrappedTargetException;
50 import com.sun.star.lang.XMultiServiceFactory;
51 import com.sun.star.text.XTextContent;
52 import com.sun.star.text.XTextRange;
53 import com.sun.star.uno.UnoRuntime;
54 import com.sun.star.view.XSelectionSupplier;
55 import org.openoffice.test.tools.DocumentType;
56 import org.openoffice.test.tools.OfficeDocument;
57 import static org.junit.Assert.*;
58 
59 /**
60  * @author frank.schoenheit@oracle.com
61  */
62 public class ChartDocumentTest implements DocumentTest
63 {
ChartDocumentTest( final XMultiServiceFactory i_orb )64     public ChartDocumentTest( final XMultiServiceFactory i_orb ) throws com.sun.star.uno.Exception, InterruptedException
65     {
66         m_textDocument = OfficeDocument.blankDocument( i_orb, DocumentType.WRITER );
67 
68         // create a OLE shape in the document
69         final XMultiServiceFactory factory = UnoRuntime.queryInterface( XMultiServiceFactory.class, m_textDocument.getDocument() );
70         final String shapeServiceName = "com.sun.star.text.TextEmbeddedObject";
71         final XPropertySet shapeProps = UnoRuntime.queryInterface( XPropertySet.class, factory.createInstance( shapeServiceName ) );
72         shapeProps.setPropertyValue("CLSID", "12dcae26-281f-416f-a234-c3086127382e");
73 
74         final XShape shape = UnoRuntime.queryInterface( XShape.class, shapeProps );
75         shape.setSize( new Size( 16000, 9000 ) );
76 
77         final XTextContent chartTextContent = UnoRuntime.queryInterface( XTextContent.class, shapeProps );
78 
79         final XSelectionSupplier selSupplier = UnoRuntime.queryInterface( XSelectionSupplier.class,
80                 m_textDocument.getCurrentView().getController() );
81         final Object selection = selSupplier.getSelection();
82         final XTextRange textRange = getAssociatedTextRange( selection );
83         if ( textRange == null )
84             throw new RuntimeException( "can't locate a text range" );
85 
86         // insert the chart
87         textRange.getText().insertTextContent(textRange, chartTextContent, false);
88 
89         // retrieve the chart model
90         XChartDocument chartDoc = UnoRuntime.queryInterface( XChartDocument.class, shapeProps.getPropertyValue( "Model" ) );
91         m_chartDocument = new OfficeDocument( i_orb, chartDoc );
92 
93         // actually activate the object
94         final XEmbeddedObject embeddedChart = UnoRuntime.queryInterface( XEmbeddedObject.class,
95             shapeProps.getPropertyValue( "EmbeddedObject" ) );
96         embeddedChart.doVerb( EmbedVerbs.MS_OLEVERB_SHOW );
97 
98         final int state = embeddedChart.getCurrentState();
99         if ( state != EmbedStates.UI_ACTIVE )
100             fail( "unable to activate the embedded chart" );
101     }
102 
getDocumentDescription()103     public String getDocumentDescription()
104     {
105         return "chart document";
106     }
107 
initializeDocument()108     public void initializeDocument() throws com.sun.star.uno.Exception
109     {
110         final XPropertySet wallProperties = impl_getWallProperties();
111         wallProperties.setPropertyValue( "FillStyle", com.sun.star.drawing.FillStyle.SOLID );
112         wallProperties.setPropertyValue( "FillColor", 0x00FFFFFF );
113     }
114 
closeDocument()115     public void closeDocument()
116     {
117         m_textDocument.close();
118     }
119 
impl_getWallProperties()120     private XPropertySet impl_getWallProperties()
121     {
122         final XChartDocument chartDoc = UnoRuntime.queryInterface( XChartDocument.class, m_chartDocument.getDocument() );
123         final XDiagram diagram = chartDoc.getFirstDiagram();
124         final XPropertySet wallProperties = diagram.getWall();
125         return wallProperties;
126     }
127 
impl_getYAxisProperties()128     private XPropertySet impl_getYAxisProperties()
129     {
130         XPropertySet axisProperties = null;
131         try
132         {
133             final XChartDocument chartDoc = UnoRuntime.queryInterface( XChartDocument.class, m_chartDocument.getDocument() );
134             final XDiagram diagram = chartDoc.getFirstDiagram();
135             final XCoordinateSystemContainer coordContainer = UnoRuntime.queryInterface( XCoordinateSystemContainer.class, diagram );
136             final XCoordinateSystem[] coordSystems = coordContainer.getCoordinateSystems();
137             final XCoordinateSystem coordSystem = coordSystems[0];
138             final XAxis primaryYAxis = coordSystem.getAxisByDimension( 1, 0 );
139             axisProperties = UnoRuntime.queryInterface( XPropertySet.class, primaryYAxis );
140         }
141         catch ( Exception ex )
142         {
143             fail( "internal error: could not retrieve primary Y axis properties" );
144         }
145         return axisProperties;
146     }
147 
impl_getUndoManager()148     private XUndoManager impl_getUndoManager()
149     {
150         final XUndoManagerSupplier undoManagerSupp = UnoRuntime.queryInterface( XUndoManagerSupplier.class, m_chartDocument.getDocument() );
151         final XUndoManager undoManager = undoManagerSupp.getUndoManager();
152         return undoManager;
153     }
154 
doSingleModification()155     public void doSingleModification() throws com.sun.star.uno.Exception
156     {
157         final XPropertySet wallProperties = impl_getWallProperties();
158 
159         // simulate an Undo action, as long as the chart implementation doesn't add Undo actions itself
160         final XUndoManager undoManager = impl_getUndoManager();
161         undoManager.addUndoAction( new PropertyUndoAction( wallProperties, "FillColor", 0xCCFF44 ) );
162             // (the UndoAction will actually set the property value)
163     }
164 
verifyInitialDocumentState()165     public void verifyInitialDocumentState() throws com.sun.star.uno.Exception
166     {
167         final XPropertySet wallProperties = impl_getWallProperties();
168         assertEquals( 0x00FFFFFF, ((Integer)wallProperties.getPropertyValue( "FillColor" )).intValue() );
169     }
170 
verifySingleModificationDocumentState()171     public void verifySingleModificationDocumentState() throws com.sun.star.uno.Exception
172     {
173         final XPropertySet wallProperties = impl_getWallProperties();
174         assertEquals( 0xCCFF44, ((Integer)wallProperties.getPropertyValue( "FillColor" )).intValue() );
175     }
176 
doMultipleModifications()177     public int doMultipleModifications() throws com.sun.star.uno.Exception
178     {
179         final XPropertySet axisProperties = impl_getYAxisProperties();
180 
181         final XUndoManager undoManager = impl_getUndoManager();
182         undoManager.addUndoAction( new PropertyUndoAction( axisProperties, "LineWidth", 300 ) );
183         undoManager.addUndoAction( new PropertyUndoAction( axisProperties, "LineColor", 0x000000 ) );
184 
185         return 2;
186     }
187 
getDocument()188     public OfficeDocument getDocument()
189     {
190         return m_chartDocument;
191     }
192 
getAssociatedTextRange( final Object i_object )193     private XTextRange getAssociatedTextRange( final Object i_object ) throws WrappedTargetException, IndexOutOfBoundsException
194     {
195         // possible cases:
196         // 1. a container of other objects - e.g. selection of 0 to n text portions, or 1 to n drawing objects
197         final XIndexAccess indexer = UnoRuntime.queryInterface( XIndexAccess.class, i_object );
198         if ((indexer != null) && indexer.getCount() > 0) {
199             final int count = indexer.getCount();
200             for (int i = 0; i < count; ++i) {
201                 final XTextRange range = getAssociatedTextRange( indexer.getByIndex(i) );
202                 if (range != null) {
203                     return range;
204                 }
205             }
206         }
207         // 2. another TextContent, having an anchor we can use
208         final XTextContent textContent = UnoRuntime.queryInterface(XTextContent.class, i_object);
209         if (textContent != null) {
210             final XTextRange range = textContent.getAnchor();
211             if (range != null) {
212                 return range;
213             }
214         }
215 
216         // an object which supports XTextRange directly
217         final XTextRange range = UnoRuntime.queryInterface(XTextRange.class, i_object);
218         if (range != null) {
219             return range;
220         }
221 
222         return null;
223     }
224 
225     private static class PropertyUndoAction implements XUndoAction
226     {
PropertyUndoAction( final XPropertySet i_component, final String i_propertyName, final Object i_newValue )227         PropertyUndoAction( final XPropertySet i_component, final String i_propertyName, final Object i_newValue ) throws com.sun.star.uno.Exception
228         {
229             m_component = i_component;
230             m_propertyName = i_propertyName;
231             m_newValue = i_newValue;
232 
233             m_oldValue = i_component.getPropertyValue( m_propertyName );
234             i_component.setPropertyValue( m_propertyName, m_newValue );
235         }
236 
getTitle()237         public String getTitle()
238         {
239             return "some dummy Undo Action";
240         }
241 
undo()242         public void undo() throws UndoFailedException
243         {
244             try
245             {
246                 m_component.setPropertyValue( m_propertyName, m_oldValue );
247             }
248             catch ( com.sun.star.uno.Exception ex )
249             {
250                 throw new UndoFailedException( "", this, ex );
251             }
252         }
253 
redo()254         public void redo() throws UndoFailedException
255         {
256             try
257             {
258                 m_component.setPropertyValue( m_propertyName, m_newValue );
259             }
260             catch ( com.sun.star.uno.Exception ex )
261             {
262                 throw new UndoFailedException( "", this, ex );
263             }
264         }
265 
266         private final XPropertySet  m_component;
267         private final String        m_propertyName;
268         private final Object        m_oldValue;
269         private final Object        m_newValue;
270     }
271 
272     private final OfficeDocument    m_textDocument;
273     private final OfficeDocument    m_chartDocument;
274 }
275