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  * To change this template, choose Tools | Templates
24  * and open the template in the editor.
25  */
26 
27 package complex.sfx2.undo;
28 
29 import com.sun.star.awt.Rectangle;
30 import com.sun.star.document.XUndoManager;
31 import com.sun.star.document.XUndoManagerSupplier;
32 import com.sun.star.document.XUndoAction;
33 import com.sun.star.awt.Point;
34 import com.sun.star.awt.Size;
35 import com.sun.star.beans.XPropertySet;
36 import com.sun.star.drawing.CircleKind;
37 import com.sun.star.drawing.XDrawPages;
38 import com.sun.star.drawing.XDrawPagesSupplier;
39 import com.sun.star.drawing.XShape;
40 import com.sun.star.drawing.XShapes;
41 import com.sun.star.lang.XMultiServiceFactory;
42 import com.sun.star.uno.UnoRuntime;
43 import org.openoffice.test.tools.DocumentType;
44 import static org.junit.Assert.*;
45 
46 /**
47  * implements the {@link DocumentTest} interface on top of a drawing document
48  * @author frank.schoenheit@oracle.com
49  */
50 public abstract class DrawingOrPresentationDocumentTest extends DocumentTestBase
51 {
DrawingOrPresentationDocumentTest( XMultiServiceFactory i_orb, final DocumentType i_docType )52     public DrawingOrPresentationDocumentTest( XMultiServiceFactory i_orb, final DocumentType i_docType ) throws com.sun.star.uno.Exception
53     {
54         super( i_orb, i_docType );
55     }
56 
initializeDocument()57     public void initializeDocument() throws com.sun.star.uno.Exception
58     {
59         // remove all shapes - Impress has two default shapes in a new doc; just get rid of them
60         final XShapes firstPageShapes = getFirstPageShapes();
61         while ( firstPageShapes.getCount() > 0 )
62             firstPageShapes.remove( UnoRuntime.queryInterface( XShape.class, firstPageShapes.getByIndex( 0 ) ) );
63     }
64 
doSingleModification()65     public void doSingleModification() throws com.sun.star.uno.Exception
66     {
67         // add a simple centered shape to the first page
68         Rectangle pagePlayground = impl_getFirstPagePlayground();
69         impl_createCircleShape(
70             ( pagePlayground.X + ( pagePlayground.Width - BIG_CIRCLE_SIZE ) / 2 ),
71             ( pagePlayground.Y + ( pagePlayground.Height - BIG_CIRCLE_SIZE ) / 2 ),
72             BIG_CIRCLE_SIZE,
73             FILL_COLOR
74         );
75     }
76 
verifyInitialDocumentState()77     public void verifyInitialDocumentState() throws com.sun.star.uno.Exception
78     {
79         final XShapes firstPageShapes = getFirstPageShapes();
80         assertEquals( "there should be no shapes at all", 0, firstPageShapes.getCount() );
81     }
82 
verifySingleModificationDocumentState()83     public void verifySingleModificationDocumentState() throws com.sun.star.uno.Exception
84     {
85         final XShapes firstPageShapes = getFirstPageShapes();
86         assertEquals( "there should be one shape, not more, not less", 1, firstPageShapes.getCount() );
87 
88         final Object shape = firstPageShapes.getByIndex(0);
89         verifyShapeGeometry( shape, BIG_CIRCLE_SIZE, BIG_CIRCLE_SIZE );
90         final XPropertySet shapeProps = UnoRuntime.queryInterface( XPropertySet.class, shape );
91         assertEquals( "wrong circle tpye", CIRCLE_TYPE.getValue(), ((CircleKind)shapeProps.getPropertyValue( "CircleKind" )).getValue() );
92         //assertEquals( "wrong circle fill color", FILL_COLOR, ((Integer)shapeProps.getPropertyValue( "FillColor" )).intValue() );
93             // disable this particular check: A bug in the drawing layer API restores the FillColor to its
94             // default value upon re-insertion. This is issue #i115080#
95     }
96 
doMultipleModifications()97     public int doMultipleModifications() throws com.sun.star.uno.Exception
98     {
99         // add a simple centered shape to the first page
100         Rectangle pagePlayground = impl_getFirstPagePlayground();
101         impl_createCircleShape(
102             pagePlayground.X,
103             pagePlayground.Y,
104             SMALL_CIRCLE_SIZE,
105             ALTERNATE_FILL_COLOR
106         );
107         impl_createCircleShape(
108             pagePlayground.X + pagePlayground.Width - SMALL_CIRCLE_SIZE,
109             pagePlayground.Y,
110             SMALL_CIRCLE_SIZE,
111             ALTERNATE_FILL_COLOR
112         );
113         impl_createCircleShape(
114             pagePlayground.X,
115             pagePlayground.Y + pagePlayground.Height - SMALL_CIRCLE_SIZE,
116             SMALL_CIRCLE_SIZE,
117             ALTERNATE_FILL_COLOR
118         );
119         impl_createCircleShape(
120             pagePlayground.X + pagePlayground.Width - SMALL_CIRCLE_SIZE,
121             pagePlayground.Y + pagePlayground.Height - SMALL_CIRCLE_SIZE,
122             SMALL_CIRCLE_SIZE,
123             ALTERNATE_FILL_COLOR
124         );
125         return 4;
126     }
127 
impl_createCircleShape( final int i_x, final int i_y, final int i_size, final int i_color )128     private void impl_createCircleShape( final int i_x, final int i_y, final int i_size, final int i_color ) throws com.sun.star.uno.Exception
129     {
130         final XPropertySet shapeProps = getDocument().createInstance( "com.sun.star.drawing.EllipseShape", XPropertySet.class );
131         shapeProps.setPropertyValue( "CircleKind", CIRCLE_TYPE );
132         shapeProps.setPropertyValue( "FillColor", i_color );
133 
134         final XShape shape = UnoRuntime.queryInterface( XShape.class, shapeProps );
135         final Size shapeSize = new Size( i_size, i_size );
136         shape.setSize( shapeSize );
137         final Point shapePos = new Point( i_x, i_y );
138         shape.setPosition( shapePos );
139 
140         final XShapes pageShapes = UnoRuntime.queryInterface( XShapes.class, getFirstPageShapes() );
141         pageShapes.add( shape );
142 
143         // Sadly, Draw/Impress currently do not create Undo actions for programmatic changes to the document.
144         // Which renders the test here slightly useless ... unless we fake the Undo actions ourself.
145         final XUndoManagerSupplier suppUndoManager = UnoRuntime.queryInterface( XUndoManagerSupplier.class, getDocument().getDocument() );
146         final XUndoManager undoManager = suppUndoManager.getUndoManager();
147         undoManager.addUndoAction( new ShapeInsertionUndoAction( shape, pageShapes ) );
148     }
149 
impl_getFirstPagePlayground()150     private Rectangle impl_getFirstPagePlayground() throws com.sun.star.uno.Exception
151     {
152         final XShapes firstPageShapes = getFirstPageShapes();
153         final XPropertySet firstPageProps = UnoRuntime.queryInterface( XPropertySet.class, firstPageShapes );
154         final int pageWidth = ((Integer)firstPageProps.getPropertyValue( "Width" )).intValue();
155         final int pageHeight = ((Integer)firstPageProps.getPropertyValue( "Height" )).intValue();
156         final int borderLeft = ((Integer)firstPageProps.getPropertyValue( "BorderLeft" )).intValue();
157         final int borderTop = ((Integer)firstPageProps.getPropertyValue( "BorderTop" )).intValue();
158         final int borderRight = ((Integer)firstPageProps.getPropertyValue( "BorderRight" )).intValue();
159         final int borderBottom = ((Integer)firstPageProps.getPropertyValue( "BorderBottom" )).intValue();
160         return new Rectangle( borderLeft, borderTop, pageWidth - borderLeft - borderRight, pageHeight - borderTop - borderBottom );
161     }
162 
163     /**
164      * returns the XShapes interface of the first page of our drawing document
165      */
getFirstPageShapes()166     private XShapes getFirstPageShapes() throws com.sun.star.uno.Exception
167     {
168         final XDrawPagesSupplier suppPages = UnoRuntime.queryInterface( XDrawPagesSupplier.class, getDocument().getDocument() );
169         final XDrawPages pages = suppPages.getDrawPages();
170         return UnoRuntime.queryInterface( XShapes.class, pages.getByIndex( 0 ) );
171     }
172 
173     /**
174      * verifies the given shape has the given size
175      */
verifyShapeGeometry( final Object i_shapeObject, final int i_expectedWidth, final int i_expectedHeight )176     private void verifyShapeGeometry( final Object i_shapeObject, final int i_expectedWidth, final int i_expectedHeight )
177          throws com.sun.star.uno.Exception
178     {
179         final XShape shape = UnoRuntime.queryInterface( XShape.class, i_shapeObject );
180         final Size shapeSize = shape.getSize();
181         assertEquals( "unexpected shape width", i_expectedWidth, shapeSize.Width );
182         assertEquals( "unexpected shape height", i_expectedHeight, shapeSize.Height );
183     }
184 
185     private static class ShapeInsertionUndoAction implements XUndoAction
186     {
ShapeInsertionUndoAction( final XShape i_shape, final XShapes i_shapeCollection )187         ShapeInsertionUndoAction( final XShape i_shape, final XShapes i_shapeCollection )
188         {
189             m_shape = i_shape;
190             m_shapeCollection = i_shapeCollection;
191         }
192 
getTitle()193         public String getTitle()
194         {
195             return "insert shape";
196         }
197 
undo()198         public void undo()
199         {
200             m_shapeCollection.remove( m_shape );
201         }
202 
redo()203         public void redo()
204         {
205             m_shapeCollection.add( m_shape );
206         }
207 
208         private final XShape m_shape;
209         private final XShapes m_shapeCollection;
210     }
211 
212     private static CircleKind   CIRCLE_TYPE = CircleKind.FULL;
213     private static int          FILL_COLOR = 0xCC2244;
214     private static int          ALTERNATE_FILL_COLOR = 0x44CC22;
215     private static int          BIG_CIRCLE_SIZE = 5000;
216     private static int          SMALL_CIRCLE_SIZE = 2000;
217 }
218