1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 #include "vbaview.hxx"
20 #include <vbahelper/vbahelper.hxx>
21 #include <basic/sberrors.hxx>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
24 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
25 #include <com/sun/star/text/XText.hpp>
26 #include <com/sun/star/text/XTextDocument.hpp>
27 #include <com/sun/star/text/XFootnotesSupplier.hpp>
28 #include <com/sun/star/text/XEndnotesSupplier.hpp>
29 #include <com/sun/star/text/XPageCursor.hpp>
30 #include <com/sun/star/container/XIndexAccess.hpp>
31 #include <com/sun/star/frame/XController.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <ooo/vba/word/WdSpecialPane.hpp>
34 #include <ooo/vba/word/WdViewType.hpp>
35 #include <ooo/vba/word/WdSeekView.hpp>
36 
37 #include "wordvbahelper.hxx"
38 #include "vbaheaderfooterhelper.hxx"
39 #include <view.hxx>
40 
41 using namespace ::ooo::vba;
42 using namespace ::com::sun::star;
43 
44 const sal_Int32 DEFAULT_BODY_DISTANCE = 500;
45 
SwVbaView(const uno::Reference<ooo::vba::XHelperInterface> & rParent,const uno::Reference<uno::XComponentContext> & rContext,const uno::Reference<frame::XModel> & rModel)46 SwVbaView::SwVbaView( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext,
47     const uno::Reference< frame::XModel >& rModel ) :
48     SwVbaView_BASE( rParent, rContext ), mxModel( rModel )
49 {
50     uno::Reference< frame::XController > xController = mxModel->getCurrentController();
51 
52     uno::Reference< text::XTextViewCursorSupplier > xTextViewCursorSupp( xController, uno::UNO_QUERY_THROW );
53     mxViewCursor = xTextViewCursorSupp->getViewCursor();
54 
55     uno::Reference< view::XViewSettingsSupplier > xViewSettingSupp( xController, uno::UNO_QUERY_THROW );
56     mxViewSettings.set( xViewSettingSupp->getViewSettings(), uno::UNO_SET_THROW );
57 }
58 
~SwVbaView()59 SwVbaView::~SwVbaView()
60 {
61 }
62 
63 ::sal_Int32 SAL_CALL
getSeekView()64 SwVbaView::getSeekView()
65 {
66     // FIXME: if the view cursor is in table, field, section and frame
67     // handle if the cursor is in table
68     uno::Reference< text::XText > xCurrentText = mxViewCursor->getText();
69     uno::Reference< beans::XPropertySet > xCursorProps( mxViewCursor, uno::UNO_QUERY_THROW );
70     uno::Reference< text::XTextContent > xTextContent;
71     while( xCursorProps->getPropertyValue("TextTable") >>= xTextContent )
72     {
73         xCurrentText = xTextContent->getAnchor()->getText();
74         xCursorProps.set( xCurrentText->createTextCursor(), uno::UNO_QUERY_THROW );
75     }
76     uno::Reference< lang::XServiceInfo > xServiceInfo( xCurrentText, uno::UNO_QUERY_THROW );
77     OUString aImplName = xServiceInfo->getImplementationName();
78     if ( aImplName == "SwXBodyText" )
79     {
80         return word::WdSeekView::wdSeekMainDocument;
81     }
82     else if ( aImplName == "SwXHeadFootText" )
83     {
84         if( HeaderFooterHelper::isHeader( mxModel ) )
85         {
86             if( HeaderFooterHelper::isFirstPageHeader( mxModel ) )
87                 return word::WdSeekView::wdSeekFirstPageHeader;
88             else if( HeaderFooterHelper::isEvenPagesHeader( mxModel ) )
89                 return word::WdSeekView::wdSeekEvenPagesHeader;
90             else
91                 return word::WdSeekView::wdSeekPrimaryHeader;
92         }
93         else
94         {
95             if( HeaderFooterHelper::isFirstPageFooter( mxModel ) )
96                 return word::WdSeekView::wdSeekFirstPageFooter;
97             else if( HeaderFooterHelper::isEvenPagesFooter( mxModel ) )
98                 return word::WdSeekView::wdSeekEvenPagesFooter;
99             else
100                 return word::WdSeekView::wdSeekPrimaryFooter;
101         }
102     }
103     else if ( aImplName == "SwXFootnote" )
104     {
105         if( xServiceInfo->supportsService("com.sun.star.text.Endnote") )
106             return word::WdSeekView::wdSeekEndnotes;
107         else
108             return word::WdSeekView::wdSeekFootnotes;
109     }
110 
111     return word::WdSeekView::wdSeekMainDocument;
112 }
113 
114 void SAL_CALL
setSeekView(::sal_Int32 _seekview)115 SwVbaView::setSeekView( ::sal_Int32 _seekview )
116 {
117     // FIXME: save the current cursor position, if the cursor is in the main
118     // document, so we can jump back to this position, if the macro sets
119     // the ViewMode back to wdSeekMainDocument
120 
121     word::gotoSelectedObjectAnchor( mxModel );
122     switch( _seekview )
123     {
124         case word::WdSeekView::wdSeekFirstPageFooter:
125         case word::WdSeekView::wdSeekFirstPageHeader:
126         case word::WdSeekView::wdSeekCurrentPageFooter:
127         case word::WdSeekView::wdSeekCurrentPageHeader:
128         case word::WdSeekView::wdSeekPrimaryFooter:
129         case word::WdSeekView::wdSeekPrimaryHeader:
130         case word::WdSeekView::wdSeekEvenPagesFooter:
131         case word::WdSeekView::wdSeekEvenPagesHeader:
132         {
133             // need to test
134             mxViewCursor->gotoRange( getHFTextRange( _seekview ), false );
135             break;
136         }
137         case word::WdSeekView::wdSeekFootnotes:
138         {
139             uno::Reference< text::XFootnotesSupplier > xFootnotesSupp( mxModel, uno::UNO_QUERY_THROW );
140             uno::Reference< container::XIndexAccess > xFootnotes( xFootnotesSupp->getFootnotes(), uno::UNO_SET_THROW );
141             if( xFootnotes->getCount() > 0 )
142             {
143                 uno::Reference< text::XText > xText( xFootnotes->getByIndex(0), uno::UNO_QUERY_THROW );
144                 mxViewCursor->gotoRange( xText->getStart(), false );
145             }
146             else
147             {
148                 DebugHelper::runtimeexception( ERRCODE_BASIC_NO_ACTIVE_OBJECT );
149             }
150             break;
151         }
152         case word::WdSeekView::wdSeekEndnotes:
153         {
154             uno::Reference< text::XEndnotesSupplier > xEndnotesSupp( mxModel, uno::UNO_QUERY_THROW );
155             uno::Reference< container::XIndexAccess > xEndnotes( xEndnotesSupp->getEndnotes(), uno::UNO_SET_THROW );
156             if( xEndnotes->getCount() > 0 )
157             {
158                 uno::Reference< text::XText > xText( xEndnotes->getByIndex(0), uno::UNO_QUERY_THROW );
159                 mxViewCursor->gotoRange( xText->getStart(), false );
160             }
161             else
162             {
163                 DebugHelper::runtimeexception( ERRCODE_BASIC_NO_ACTIVE_OBJECT );
164             }
165             break;
166         }
167         case word::WdSeekView::wdSeekMainDocument:
168         {
169             uno::Reference< text::XTextDocument > xTextDocument( mxModel, uno::UNO_QUERY_THROW );
170             uno::Reference< text::XText > xText = xTextDocument->getText();
171             mxViewCursor->gotoRange( word::getFirstObjectPosition( xText ), false );
172             break;
173         }
174     }
175 }
176 
177 ::sal_Int32 SAL_CALL
getSplitSpecial()178 SwVbaView::getSplitSpecial()
179 {
180     return word::WdSpecialPane::wdPaneNone;
181 }
182 
183 void SAL_CALL
setSplitSpecial(::sal_Int32)184 SwVbaView::setSplitSpecial( ::sal_Int32/* _splitspecial */)
185 {
186     // not support in Writer
187 }
188 
189 sal_Bool SAL_CALL
getTableGridLines()190 SwVbaView::getTableGridLines()
191 {
192     bool bShowTableGridLine = false;
193     mxViewSettings->getPropertyValue("ShowTableBoundaries") >>= bShowTableGridLine;
194     return bShowTableGridLine;
195 }
196 
197 void SAL_CALL
setTableGridLines(sal_Bool _tablegridlines)198 SwVbaView::setTableGridLines( sal_Bool _tablegridlines )
199 {
200     mxViewSettings->setPropertyValue("ShowTableBoundaries", uno::makeAny( _tablegridlines ) );
201 }
202 
203 ::sal_Int32 SAL_CALL
getType()204 SwVbaView::getType()
205 {
206     // FIXME: handle wdPrintPreview type
207     bool bOnlineLayout = false;
208     mxViewSettings->getPropertyValue("ShowOnlineLayout") >>= bOnlineLayout;
209     return bOnlineLayout ? word::WdViewType::wdWebView : word::WdViewType::wdPrintView;
210 }
211 
212 void SAL_CALL
setType(::sal_Int32 _type)213 SwVbaView::setType( ::sal_Int32 _type )
214 {
215     // FIXME: handle wdPrintPreview type
216     switch( _type )
217     {
218         case word::WdViewType::wdPrintView:
219         case word::WdViewType::wdNormalView:
220         {
221             mxViewSettings->setPropertyValue("ShowOnlineLayout", uno::makeAny( false ) );
222             break;
223         }
224         case word::WdViewType::wdWebView:
225         {
226             mxViewSettings->setPropertyValue("ShowOnlineLayout", uno::makeAny( true ) );
227             break;
228         }
229         case word::WdViewType::wdPrintPreview:
230         {
231             PrintPreviewHelper( uno::Any(),word::getView( mxModel ) );
232             break;
233         }
234         default:
235             DebugHelper::runtimeexception( ERRCODE_BASIC_NOT_IMPLEMENTED );
236 
237     }
238 }
239 
getHFTextRange(sal_Int32 nType)240 uno::Reference< text::XTextRange > SwVbaView::getHFTextRange( sal_Int32 nType )
241 {
242     mxModel->lockControllers();
243 
244     OUString aPropIsOn;
245     OUString aPropIsShared;
246     OUString aPropBodyDistance;
247     OUString aPropText;
248 
249     switch( nType )
250     {
251         case word::WdSeekView::wdSeekCurrentPageFooter:
252         case word::WdSeekView::wdSeekFirstPageFooter:
253         case word::WdSeekView::wdSeekPrimaryFooter:
254         case word::WdSeekView::wdSeekEvenPagesFooter:
255         {
256             aPropIsOn = "FooterIsOn";
257             aPropIsShared = "FooterIsShared";
258             aPropBodyDistance = "FooterBodyDistance";
259             aPropText = "FooterText";
260             break;
261         }
262         case word::WdSeekView::wdSeekCurrentPageHeader:
263         case word::WdSeekView::wdSeekFirstPageHeader:
264         case word::WdSeekView::wdSeekPrimaryHeader:
265         case word::WdSeekView::wdSeekEvenPagesHeader:
266         {
267             aPropIsOn = "HeaderIsOn";
268             aPropIsShared = "HeaderIsShared";
269             aPropBodyDistance = "HeaderBodyDistance";
270             aPropText = "HeaderText";
271             break;
272         }
273     }
274 
275     uno::Reference< text::XPageCursor > xPageCursor( mxViewCursor, uno::UNO_QUERY_THROW );
276 
277     if( nType == word::WdSeekView::wdSeekFirstPageFooter
278         || nType == word::WdSeekView::wdSeekFirstPageHeader )
279     {
280         xPageCursor->jumpToFirstPage();
281     }
282 
283     uno::Reference< style::XStyle > xStyle;
284     uno::Reference< text::XText > xText;
285     switch( nType )
286     {
287         case word::WdSeekView::wdSeekPrimaryFooter:
288         case word::WdSeekView::wdSeekPrimaryHeader:
289         case word::WdSeekView::wdSeekEvenPagesFooter:
290         case word::WdSeekView::wdSeekEvenPagesHeader:
291         {
292             // The primary header is the first header of the section.
293             // If the header is not shared between odd and even pages
294             // the odd page's header is the primary header. If the
295             // first page's header is different from the rest of the
296             // document, it is NOT the primary header ( the next primary
297             // header would be on page 3 )
298             // The even pages' header is only available if the header is
299             // not shared and the current style is applied to a page with
300             // an even page number
301             uno::Reference< beans::XPropertySet > xCursorProps( mxViewCursor, uno::UNO_QUERY_THROW );
302             OUString aPageStyleName;
303             xCursorProps->getPropertyValue("PageStyleName") >>= aPageStyleName;
304             if ( aPageStyleName == "First Page" )
305             {
306                 // go to the beginning of where the next style is used
307                 bool hasNextPage = false;
308                 xStyle = word::getCurrentPageStyle( mxModel );
309                 do
310                 {
311                     hasNextPage = xPageCursor->jumpToNextPage();
312                 }
313                 while( hasNextPage && ( xStyle == word::getCurrentPageStyle( mxModel ) ) );
314 
315                 if( !hasNextPage )
316                     DebugHelper::basicexception( ERRCODE_BASIC_BAD_ACTION, {} );
317             }
318             break;
319         }
320         default:
321         {
322             break;
323         }
324     }
325 
326     xStyle = word::getCurrentPageStyle( mxModel );
327     uno::Reference< beans::XPropertySet > xPageProps( xStyle, uno::UNO_QUERY_THROW );
328     bool isOn = false;
329     xPageProps->getPropertyValue( aPropIsOn ) >>= isOn;
330     bool isShared =  false;
331     xPageProps->getPropertyValue( aPropIsShared ) >>= isShared;
332     if( !isOn )
333     {
334         xPageProps->setPropertyValue( aPropIsOn, uno::makeAny( true ) );
335         xPageProps->setPropertyValue( aPropBodyDistance, uno::makeAny( DEFAULT_BODY_DISTANCE ) );
336     }
337     if( !isShared )
338     {
339         OUString aTempPropText = aPropText;
340         if( nType == word::WdSeekView::wdSeekEvenPagesFooter
341             || nType == word::WdSeekView::wdSeekEvenPagesHeader )
342         {
343             aTempPropText += "Left";
344         }
345         else
346         {
347             aTempPropText += "Right";
348         }
349         xText.set( xPageProps->getPropertyValue( aTempPropText), uno::UNO_QUERY_THROW );
350     }
351     else
352     {
353         if( nType == word::WdSeekView::wdSeekEvenPagesFooter
354             || nType == word::WdSeekView::wdSeekEvenPagesHeader )
355         {
356             DebugHelper::basicexception( ERRCODE_BASIC_BAD_ACTION, {} );
357         }
358         xText.set( xPageProps->getPropertyValue( aPropText ), uno::UNO_QUERY_THROW );
359     }
360 
361     mxModel->unlockControllers();
362     if( !xText.is() )
363     {
364         DebugHelper::basicexception( ERRCODE_BASIC_INTERNAL_ERROR, {} );
365     }
366     uno::Reference< text::XTextRange > xTextRange = word::getFirstObjectPosition( xText );
367     return xTextRange;
368 }
369 
370 OUString
getServiceImplName()371 SwVbaView::getServiceImplName()
372 {
373     return "SwVbaView";
374 }
375 
376 uno::Sequence< OUString >
getServiceNames()377 SwVbaView::getServiceNames()
378 {
379     static uno::Sequence< OUString > const aServiceNames
380     {
381         "ooo.vba.word.View"
382     };
383     return aServiceNames;
384 }
385 
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
387