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 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <memory>
24 #include <utility>
25 
26 #include <DrawDocShell.hxx>
27 #include <com/sun/star/document/PrinterIndependentLayout.hpp>
28 #include <editeng/outlobj.hxx>
29 #include <tools/urlobj.hxx>
30 #include <svx/svxids.hrc>
31 #include <editeng/editeng.hxx>
32 #include <editeng/editstat.hxx>
33 #include <editeng/flstitem.hxx>
34 #include <svl/flagitem.hxx>
35 #include <sot/storage.hxx>
36 #include <sfx2/dinfdlg.hxx>
37 #include <sfx2/docfile.hxx>
38 #include <sfx2/docfilt.hxx>
39 #include <sfx2/dispatch.hxx>
40 #include <svx/svdotext.hxx>
41 #include <sfx2/printer.hxx>
42 #include <svtools/ctrltool.hxx>
43 #include <comphelper/classids.hxx>
44 #include <sot/formats.hxx>
45 #include <sfx2/viewfrm.hxx>
46 #include <vcl/syswin.hxx>
47 #include <com/sun/star/drawing/XDrawPage.hpp>
48 #include <com/sun/star/drawing/XDrawView.hpp>
49 
50 #include <app.hrc>
51 #include <strings.hrc>
52 #include <FrameView.hxx>
53 #include <optsitem.hxx>
54 #include <Outliner.hxx>
55 #include <sdattr.hrc>
56 #include <drawdoc.hxx>
57 #include <ViewShell.hxx>
58 #include <sdmod.hxx>
59 #include <View.hxx>
60 #include <EffectMigration.hxx>
61 #include <CustomAnimationEffect.hxx>
62 #include <sdpage.hxx>
63 #include <sdresid.hxx>
64 #include <DrawViewShell.hxx>
65 #include <ViewShellBase.hxx>
66 #include <OutlineView.hxx>
67 #include <OutlineViewShell.hxx>
68 #include <sdxmlwrp.hxx>
69 #include <sdpptwrp.hxx>
70 #include <sdcgmfilter.hxx>
71 #include <sdgrffilter.hxx>
72 #include <sdhtmlfilter.hxx>
73 #include <sdpdffilter.hxx>
74 #include <framework/FrameworkHelper.hxx>
75 
76 #include <sfx2/zoomitem.hxx>
77 
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::uno;
80 using ::sd::framework::FrameworkHelper;
81 
82 // PowerPoint-Filter
83 constexpr OUStringLiteral pFilterPowerPoint97( u"MS PowerPoint 97" );
84 constexpr OUStringLiteral pFilterPowerPoint97Template( u"MS PowerPoint 97 Vorlage" );
85 constexpr OUStringLiteral pFilterPowerPoint97AutoPlay( u"MS PowerPoint 97 AutoPlay" );
86 
87 namespace sd {
88 
89 /**
90  * Creates (if necessary) and returns a SfxPrinter
91  */
GetPrinter(bool bCreate)92 SfxPrinter* DrawDocShell::GetPrinter(bool bCreate)
93 {
94     if (bCreate && !mpPrinter)
95     {
96         // create ItemSet with special pool area
97         auto pSet = std::make_unique<SfxItemSet>( GetPool(),
98                             svl::Items<SID_PRINTER_NOTFOUND_WARN,  SID_PRINTER_NOTFOUND_WARN,
99                             SID_PRINTER_CHANGESTODOC,   SID_PRINTER_CHANGESTODOC,
100                             ATTR_OPTIONS_PRINT,         ATTR_OPTIONS_PRINT>{} );
101         // set PrintOptionsSet
102         SdOptionsPrintItem aPrintItem( SD_MOD()->GetSdOptions(mpDoc->GetDocumentType()) );
103         SfxFlagItem aFlagItem( SID_PRINTER_CHANGESTODOC );
104         SfxPrinterChangeFlags nFlags =
105                 (aPrintItem.GetOptionsPrint().IsWarningSize() ? SfxPrinterChangeFlags::CHG_SIZE : SfxPrinterChangeFlags::NONE) |
106                 (aPrintItem.GetOptionsPrint().IsWarningOrientation() ? SfxPrinterChangeFlags::CHG_ORIENTATION : SfxPrinterChangeFlags::NONE);
107         aFlagItem.SetValue( static_cast<int>(nFlags) );
108 
109         pSet->Put( aPrintItem );
110         pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aPrintItem.GetOptionsPrint().IsWarningPrinter() ) );
111         pSet->Put( aFlagItem );
112 
113         mpPrinter = VclPtr<SfxPrinter>::Create(std::move(pSet));
114         mbOwnPrinter = true;
115 
116         // set output quality
117         sal_uInt16 nQuality = aPrintItem.GetOptionsPrint().GetOutputQuality();
118 
119         DrawModeFlags nMode = DrawModeFlags::Default;
120         // 1 == Grayscale, 2 == Black & White (with grayscale images)
121         if( nQuality == 1 )
122             nMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient;
123         else if( nQuality == 2 )
124             nMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap | DrawModeFlags::WhiteGradient;
125 
126         mpPrinter->SetDrawMode( nMode );
127 
128         MapMode aMM (mpPrinter->GetMapMode());
129         aMM.SetMapUnit(MapUnit::Map100thMM);
130         mpPrinter->SetMapMode(aMM);
131         UpdateRefDevice();
132     }
133     return mpPrinter;
134 }
135 
136 /**
137  * Set new SfxPrinter (transfer of ownership)
138  */
SetPrinter(SfxPrinter * pNewPrinter)139 void DrawDocShell::SetPrinter(SfxPrinter *pNewPrinter)
140 {
141     if ( mpViewShell )
142     {
143         ::sd::View* pView = mpViewShell->GetView();
144         if ( pView->IsTextEdit() )
145             pView->SdrEndTextEdit();
146     }
147 
148     if ( mpPrinter && mbOwnPrinter && (mpPrinter.get() != pNewPrinter) )
149         mpPrinter.disposeAndClear();
150 
151     mpPrinter = pNewPrinter;
152     mbOwnPrinter = true;
153     if ( mpDoc->GetPrinterIndependentLayout() == css::document::PrinterIndependentLayout::DISABLED )
154         UpdateFontList();
155     UpdateRefDevice();
156 }
157 
UpdateFontList()158 void DrawDocShell::UpdateFontList()
159 {
160     mpFontList.reset();
161     OutputDevice* pRefDevice = nullptr;
162     if ( mpDoc->GetPrinterIndependentLayout() == css::document::PrinterIndependentLayout::DISABLED )
163         pRefDevice = GetPrinter(true);
164     else
165         pRefDevice = SD_MOD()->GetVirtualRefDevice();
166     mpFontList.reset( new FontList(pRefDevice, nullptr) );
167     SvxFontListItem aFontListItem( mpFontList.get(), SID_ATTR_CHAR_FONTLIST );
168     PutItem( aFontListItem );
169 }
170 
GetDocumentPrinter()171 Printer* DrawDocShell::GetDocumentPrinter()
172 {
173     return GetPrinter(false);
174 }
175 
OnDocumentPrinterChanged(Printer * pNewPrinter)176 void DrawDocShell::OnDocumentPrinterChanged(Printer* pNewPrinter)
177 {
178     // if we already have a printer, see if it's the same
179     if( mpPrinter )
180     {
181         // easy case
182         if( mpPrinter == pNewPrinter )
183             return;
184 
185         // compare if it's the same printer with the same job setup
186         if( (mpPrinter->GetName() == pNewPrinter->GetName()) &&
187             (mpPrinter->GetJobSetup() == pNewPrinter->GetJobSetup()))
188             return;
189     }
190 
191     SfxPrinter* const pSfxPrinter = dynamic_cast<SfxPrinter*>(pNewPrinter);
192     if (pSfxPrinter)
193     {
194         SetPrinter(pSfxPrinter);
195 
196         // container owns printer
197         mbOwnPrinter = false;
198     }
199 }
200 
UpdateRefDevice()201 void DrawDocShell::UpdateRefDevice()
202 {
203     if( !mpDoc )
204         return;
205 
206     // Determine the device for which the output will be formatted.
207     VclPtr< OutputDevice > pRefDevice;
208     switch (mpDoc->GetPrinterIndependentLayout())
209     {
210         case css::document::PrinterIndependentLayout::DISABLED:
211             pRefDevice = mpPrinter.get();
212             break;
213 
214         case css::document::PrinterIndependentLayout::ENABLED:
215             pRefDevice = SD_MOD()->GetVirtualRefDevice();
216             break;
217 
218         default:
219             // We are confronted with an invalid or un-implemented
220             // layout mode.  Use the printer as formatting device
221             // as a fall-back.
222             SAL_WARN( "sd", "DrawDocShell::UpdateRefDevice(): Unexpected printer layout mode");
223 
224             pRefDevice = mpPrinter.get();
225             break;
226     }
227     mpDoc->SetRefDevice( pRefDevice.get() );
228 
229     SdOutliner* pOutl = mpDoc->GetOutliner( false );
230 
231     if( pOutl )
232         pOutl->SetRefDevice( pRefDevice );
233 
234     SdOutliner* pInternalOutl = mpDoc->GetInternalOutliner( false );
235 
236     if( pInternalOutl )
237         pInternalOutl->SetRefDevice( pRefDevice );
238 }
239 
240 /**
241  * Creates new document, opens streams
242  */
InitNew(const css::uno::Reference<css::embed::XStorage> & xStorage)243 bool DrawDocShell::InitNew( const css::uno::Reference< css::embed::XStorage >& xStorage )
244 {
245     bool bRet = SfxObjectShell::InitNew( xStorage );
246 
247     ::tools::Rectangle aVisArea( Point(0, 0), Size(14100, 10000) );
248     SetVisArea(aVisArea);
249 
250     if (bRet)
251     {
252         if( !mbSdDataObj )
253             mpDoc->NewOrLoadCompleted(DocCreationMode::New);  // otherwise calling
254                                                 // NewOrLoadCompleted(NEW_LOADED) in
255                                                 // SdDrawDocument::AllocModel()
256     }
257     return bRet;
258 }
259 
260 /**
261  * loads pools and document
262  */
Load(SfxMedium & rMedium)263 bool DrawDocShell::Load( SfxMedium& rMedium )
264 {
265     // If this is an ODF file being loaded, then by default, use legacy processing
266     // for tdf#99729 (if required, it will be overridden in *::ReadUserDataSequence())
267     if (IsOwnStorageFormat(rMedium))
268     {
269         mpDoc->SetAnchoredTextOverflowLegacy(true);
270     }
271 
272     bool       bRet = false;
273     bool       bStartPresentation = false;
274     ErrCode nError = ERRCODE_NONE;
275 
276     SfxItemSet* pSet = rMedium.GetItemSet();
277 
278     if( pSet )
279     {
280         if( (  SfxItemState::SET == pSet->GetItemState(SID_PREVIEW ) ) && pSet->Get( SID_PREVIEW ).GetValue() )
281         {
282             mpDoc->SetStarDrawPreviewMode( true );
283         }
284 
285         if( SfxItemState::SET == pSet->GetItemState(SID_DOC_STARTPRESENTATION)&&
286             pSet->Get( SID_DOC_STARTPRESENTATION ).GetValue() )
287         {
288             bStartPresentation = true;
289             mpDoc->SetStartWithPresentation( true );
290         }
291     }
292 
293     bRet = SfxObjectShell::Load( rMedium );
294     if (bRet)
295     {
296         comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getEmbeddedObjectContainer();
297         rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);
298         bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Normal, SotStorage::GetVersion( rMedium.GetStorage() ) ).Import( nError );
299     }
300 
301     if( bRet )
302     {
303         // for legacy markup in OOoXML filter, convert the animations now
304         EffectMigration::DocumentLoaded(*GetDoc());
305         UpdateTablePointers();
306 
307         // If we're an embedded OLE object, use tight bounds
308         // for our visArea. No point in showing the user lots of empty
309         // space. Had to remove the check for empty VisArea below,
310         // since XML load always sets a VisArea before.
311         //TODO/LATER: looks a little bit strange!
312         if( ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) && SfxObjectShell::GetVisArea( ASPECT_CONTENT ).IsEmpty() )
313         {
314             SdPage* pPage = mpDoc->GetSdPage( 0, PageKind::Standard );
315 
316             if( pPage )
317                 SetVisArea( pPage->GetAllObjBoundRect() );
318         }
319 
320         FinishedLoading();
321 
322         const INetURLObject aUrl;
323         SfxObjectShell::SetAutoLoad( aUrl, 0, false );
324     }
325     else
326     {
327         if( nError == ERRCODE_IO_BROKENPACKAGE )
328             SetError(ERRCODE_IO_BROKENPACKAGE);
329 
330         // TODO/LATER: correct error handling?!
331         //pStore->SetError(SVSTREAM_WRONGVERSION);
332         else
333             SetError(ERRCODE_ABORT);
334     }
335 
336     // tell SFX to change viewshell when in preview mode
337     if( IsPreview() || bStartPresentation )
338     {
339         SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
340         if( pMediumSet )
341             pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, bStartPresentation ? 1 : 5 ) );
342     }
343 
344     return bRet;
345 }
346 
347 /**
348  * loads content for organizer
349  */
LoadFrom(SfxMedium & rMedium)350 bool DrawDocShell::LoadFrom( SfxMedium& rMedium )
351 {
352     std::unique_ptr<weld::WaitObject> pWait;
353     if( mpViewShell )
354         pWait.reset(new weld::WaitObject(mpViewShell->GetFrameWeld()));
355 
356     mpDoc->NewOrLoadCompleted( DocCreationMode::New );
357     mpDoc->CreateFirstPages();
358     mpDoc->StopWorkStartupDelay();
359 
360     // TODO/LATER: nobody is interested in the error code?!
361     ErrCode nError = ERRCODE_NONE;
362     bool bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Organizer, SotStorage::GetVersion( rMedium.GetStorage() ) ).Import( nError );
363 
364     // tell SFX to change viewshell when in preview mode
365     if( IsPreview() )
366     {
367         SfxItemSet *pSet = GetMedium()->GetItemSet();
368 
369         if( pSet )
370             pSet->Put( SfxUInt16Item( SID_VIEW_ID, 5 ) );
371     }
372 
373     return bRet;
374 }
375 
376 /**
377  * load from 3rd party format
378  */
ImportFrom(SfxMedium & rMedium,uno::Reference<text::XTextRange> const & xInsertPosition)379 bool DrawDocShell::ImportFrom(SfxMedium &rMedium,
380         uno::Reference<text::XTextRange> const& xInsertPosition)
381 {
382     const OUString aFilterName( rMedium.GetFilter()->GetFilterName() );
383     if (aFilterName == "Impress MS PowerPoint 2007 XML" ||
384         aFilterName == "Impress MS PowerPoint 2007 XML AutoPlay" ||
385         aFilterName == "Impress MS PowerPoint 2007 XML VBA")
386     {
387         // As this is a MSFT format, we should use the "MS Compat"
388         // mode for spacing before and after paragraphs.
389 
390         // This is copied from what is done for .ppt import in
391         // ImplSdPPTImport::Import() in sd/source/filter/ppt/pptin.cxx
392         // in. We need to tell both the edit engine of the draw outliner,
393         // and the document, to do "summation of paragraphs".
394         SdrOutliner& rOutl = mpDoc->GetDrawOutliner();
395         EEControlBits nControlWord = rOutl.GetEditEngine().GetControlWord();
396         nControlWord |=  EEControlBits::ULSPACESUMMATION;
397         const_cast<EditEngine&>(rOutl.GetEditEngine()).SetControlWord( nControlWord );
398 
399         mpDoc->SetSummationOfParagraphs();
400     }
401 
402     const bool bRet = SfxObjectShell::ImportFrom(rMedium, xInsertPosition);
403 
404     SfxItemSet* pSet = rMedium.GetItemSet();
405     if( pSet )
406     {
407         if( SfxItemState::SET == pSet->GetItemState(SID_DOC_STARTPRESENTATION)&&
408             pSet->Get( SID_DOC_STARTPRESENTATION ).GetValue() )
409         {
410             mpDoc->SetStartWithPresentation( true );
411 
412             // tell SFX to change viewshell when in preview mode
413             if( IsPreview() )
414             {
415                 SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
416                 if( pMediumSet )
417                     pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, 1 ) );
418             }
419         }
420     }
421 
422     return bRet;
423 }
424 
425 /**
426  * load from a foreign format
427  */
ConvertFrom(SfxMedium & rMedium)428 bool DrawDocShell::ConvertFrom( SfxMedium& rMedium )
429 {
430     const OUString  aFilterName( rMedium.GetFilter()->GetFilterName() );
431     bool            bRet = false;
432     bool            bStartPresentation = false;
433 
434     SetWaitCursor( true );
435 
436     SfxItemSet* pSet = rMedium.GetItemSet();
437     if( pSet )
438     {
439         if( (  SfxItemState::SET == pSet->GetItemState(SID_PREVIEW ) ) && pSet->Get( SID_PREVIEW ).GetValue() )
440         {
441             mpDoc->SetStarDrawPreviewMode( true );
442         }
443 
444         if( SfxItemState::SET == pSet->GetItemState(SID_DOC_STARTPRESENTATION)&&
445             pSet->Get( SID_DOC_STARTPRESENTATION ).GetValue() )
446         {
447             bStartPresentation = true;
448             mpDoc->SetStartWithPresentation( true );
449         }
450     }
451 
452     if( aFilterName == pFilterPowerPoint97
453         || aFilterName == pFilterPowerPoint97Template
454         || aFilterName == pFilterPowerPoint97AutoPlay)
455     {
456         mpDoc->StopWorkStartupDelay();
457         bRet = SdPPTFilter( rMedium, *this ).Import();
458     }
459     else if (aFilterName.indexOf("impress8") >= 0 ||
460              aFilterName.indexOf("draw8") >= 0)
461     {
462         // TODO/LATER: nobody is interested in the error code?!
463         mpDoc->CreateFirstPages();
464         mpDoc->StopWorkStartupDelay();
465         ErrCode nError = ERRCODE_NONE;
466         bRet = SdXMLFilter( rMedium, *this ).Import( nError );
467 
468     }
469     else if (aFilterName.indexOf("StarOffice XML (Draw)") >= 0 ||
470              aFilterName.indexOf("StarOffice XML (Impress)") >= 0)
471     {
472         // TODO/LATER: nobody is interested in the error code?!
473         mpDoc->CreateFirstPages();
474         mpDoc->StopWorkStartupDelay();
475         ErrCode nError = ERRCODE_NONE;
476         bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Normal, SOFFICE_FILEFORMAT_60 ).Import( nError );
477     }
478     else if (aFilterName == "CGM - Computer Graphics Metafile")
479     {
480         mpDoc->CreateFirstPages();
481         mpDoc->StopWorkStartupDelay();
482         bRet = SdCGMFilter( rMedium, *this ).Import();
483     }
484     else if (aFilterName == "draw_pdf_import")
485     {
486         mpDoc->CreateFirstPages();
487         mpDoc->StopWorkStartupDelay();
488         bRet = SdPdfFilter(rMedium, *this).Import();
489     }
490     else
491     {
492         mpDoc->CreateFirstPages();
493         mpDoc->StopWorkStartupDelay();
494         bRet = SdGRFFilter( rMedium, *this ).Import();
495     }
496 
497     FinishedLoading();
498 
499     // tell SFX to change viewshell when in preview mode
500     if( IsPreview() )
501     {
502         SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
503 
504         if( pMediumSet )
505             pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, 5 ) );
506     }
507     SetWaitCursor( false );
508 
509     // tell SFX to change viewshell when in preview mode
510     if( IsPreview() || bStartPresentation )
511     {
512         SfxItemSet *pMediumSet = GetMedium()->GetItemSet();
513         if( pMediumSet )
514             pMediumSet->Put( SfxUInt16Item( SID_VIEW_ID, bStartPresentation ? 1 : 5 ) );
515     }
516 
517     return bRet;
518 }
519 
520 /**
521  * Writes pools and document to the open streams
522  */
Save()523 bool DrawDocShell::Save()
524 {
525     mpDoc->StopWorkStartupDelay();
526 
527     //TODO/LATER: why this?!
528     if( GetCreateMode() == SfxObjectCreateMode::STANDARD )
529         SfxObjectShell::SetVisArea( ::tools::Rectangle() );
530 
531     bool bRet = SfxObjectShell::Save();
532 
533     if( bRet )
534         bRet = SdXMLFilter( *GetMedium(), *this, SdXMLFilterMode::Normal, SotStorage::GetVersion( GetMedium()->GetStorage() ) ).Export();
535 
536     return bRet;
537 }
538 
539 /**
540  * Writes pools and document to the provided storage
541  */
SaveAs(SfxMedium & rMedium)542 bool DrawDocShell::SaveAs( SfxMedium& rMedium )
543 {
544     mpDoc->setDocAccTitle(OUString());
545     if (SfxViewFrame* pFrame1 = SfxViewFrame::GetFirst(this))
546     {
547         if (vcl::Window* pSysWin = pFrame1->GetWindow().GetSystemWindow())
548         {
549             pSysWin->SetAccessibleName(OUString());
550         }
551     }
552     mpDoc->StopWorkStartupDelay();
553 
554     //With custom animation, if Outliner is modified, update text before saving
555     if( mpViewShell )
556     {
557         SdPage* pPage = mpViewShell->getCurrentPage();
558         if( pPage && pPage->getMainSequence()->getCount() )
559         {
560             SdrObject* pObj = mpViewShell->GetView()->GetTextEditObject();
561             SdrOutliner* pOutl = mpViewShell->GetView()->GetTextEditOutliner();
562             if( pObj && pOutl && pOutl->IsModified() )
563             {
564                 std::unique_ptr<OutlinerParaObject> pNewText = pOutl->CreateParaObject( 0, pOutl->GetParagraphCount() );
565                 pObj->SetOutlinerParaObject( std::move(pNewText) );
566                 pOutl->ClearModifyFlag();
567             }
568         }
569     }
570 
571     //TODO/LATER: why this?!
572     if( GetCreateMode() == SfxObjectCreateMode::STANDARD )
573         SfxObjectShell::SetVisArea( ::tools::Rectangle() );
574 
575     bool bRet = SfxObjectShell::SaveAs( rMedium );
576 
577     if( bRet )
578         bRet = SdXMLFilter( rMedium, *this, SdXMLFilterMode::Normal, SotStorage::GetVersion( rMedium.GetStorage() ) ).Export();
579 
580     if( GetError() == ERRCODE_NONE )
581         SetError(ERRCODE_NONE);
582 
583     return bRet;
584 }
585 
586 /**
587  * save to foreign format
588  */
ConvertTo(SfxMedium & rMedium)589 bool DrawDocShell::ConvertTo( SfxMedium& rMedium )
590 {
591     bool bRet = false;
592 
593     if( mpDoc->GetPageCount() )
594     {
595         std::shared_ptr<const SfxFilter> pMediumFilter = rMedium.GetFilter();
596         const OUString aTypeName( pMediumFilter->GetTypeName() );
597         std::unique_ptr<SdFilter> xFilter;
598 
599         if( aTypeName.indexOf( "graphic_HTML" ) >= 0 )
600         {
601             xFilter = std::make_unique<SdHTMLFilter>(rMedium, *this);
602         }
603         else if( aTypeName.indexOf( "MS_PowerPoint_97" ) >= 0 )
604         {
605             xFilter = std::make_unique<SdPPTFilter>(rMedium, *this);
606             static_cast<SdPPTFilter*>(xFilter.get())->PreSaveBasic();
607         }
608         else if ( aTypeName.indexOf( "CGM_Computer_Graphics_Metafile" ) >= 0 )
609         {
610             xFilter = std::make_unique<SdCGMFilter>(rMedium, *this);
611         }
612         else if( aTypeName.indexOf( "draw8" ) >= 0 ||
613                  aTypeName.indexOf( "impress8" ) >= 0 )
614         {
615             xFilter = std::make_unique<SdXMLFilter>(rMedium, *this);
616         }
617         else if( aTypeName.indexOf( "StarOffice_XML_Impress" ) >= 0 ||
618                  aTypeName.indexOf( "StarOffice_XML_Draw" ) >= 0 )
619         {
620             xFilter = std::make_unique<SdXMLFilter>(rMedium, *this, SdXMLFilterMode::Normal, SOFFICE_FILEFORMAT_60);
621         }
622         else
623         {
624             xFilter = std::make_unique<SdGRFFilter>(rMedium, *this);
625         }
626 
627         if (xFilter)
628         {
629             if ( mpViewShell )
630             {
631                 ::sd::View* pView = mpViewShell->GetView();
632                 if ( pView->IsTextEdit() )
633                     pView->SdrEndTextEdit();
634             }
635 
636             bRet = xFilter->Export();
637         }
638     }
639 
640     return bRet;
641 }
642 
643 /**
644  * Reopen own streams to ensure that nobody else can prevent use from opening
645  * them.
646  */
SaveCompleted(const css::uno::Reference<css::embed::XStorage> & xStorage)647 bool DrawDocShell::SaveCompleted( const css::uno::Reference< css::embed::XStorage >& xStorage )
648 {
649     bool bRet = false;
650 
651     if( SfxObjectShell::SaveCompleted(xStorage) )
652     {
653         mpDoc->NbcSetChanged( false );
654 
655         if( mpViewShell )
656         {
657             if( dynamic_cast< OutlineViewShell *>( mpViewShell ) !=  nullptr )
658                 static_cast<OutlineView*>(mpViewShell->GetView())
659                     ->GetOutliner().ClearModifyFlag();
660 
661             SdrOutliner* pOutl = mpViewShell->GetView()->GetTextEditOutliner();
662             if( pOutl )
663             {
664                 SdrObject* pObj = mpViewShell->GetView()->GetTextEditObject();
665                 if( pObj )
666                     pObj->NbcSetOutlinerParaObject( pOutl->CreateParaObject() );
667 
668                 pOutl->ClearModifyFlag();
669             }
670         }
671 
672         bRet = true;
673 
674         SfxViewFrame* pFrame = ( mpViewShell && mpViewShell->GetViewFrame() ) ?
675                                mpViewShell->GetViewFrame() :
676                                SfxViewFrame::Current();
677 
678         if( pFrame )
679             pFrame->GetBindings().Invalidate( SID_NAVIGATOR_STATE, true );
680     }
681     return bRet;
682 }
683 
GetStyleSheetPool()684 SfxStyleSheetBasePool* DrawDocShell::GetStyleSheetPool()
685 {
686     return mpDoc->GetStyleSheetPool();
687 }
688 
GotoBookmark(const OUString & rBookmark)689 void DrawDocShell::GotoBookmark(const OUString& rBookmark)
690 {
691     auto pDrawViewShell = dynamic_cast<DrawViewShell *>( mpViewShell );
692     if (!pDrawViewShell)
693         return;
694 
695     ViewShellBase& rBase (mpViewShell->GetViewShellBase());
696 
697     bool bIsMasterPage = false;
698     sal_uInt16 nPageNumber = SDRPAGE_NOTFOUND;
699     SdrObject* pObj = nullptr;
700 
701     static const OUStringLiteral sInteraction( u"action?" );
702     if ( rBookmark.match( sInteraction ) )
703     {
704         static const OUStringLiteral sJump( u"jump=" );
705         if ( rBookmark.match( sJump, sInteraction.getLength() ) )
706         {
707             OUString aDestination( rBookmark.copy( sInteraction.getLength() + sJump.getLength() ) );
708             if ( aDestination.match( "firstslide" ) )
709             {
710                 nPageNumber = 1;
711             }
712             else if ( aDestination.match( "lastslide" ) )
713             {
714                 nPageNumber = mpDoc->GetPageCount() - 2;
715             }
716             else if ( aDestination.match( "previousslide" ) )
717             {
718                 SdPage* pPage = pDrawViewShell->GetActualPage();
719                 nPageNumber = pPage->GetPageNum();
720                 nPageNumber = nPageNumber > 2 ? nPageNumber - 2 : SDRPAGE_NOTFOUND;
721             }
722             else if ( aDestination.match( "nextslide" ) )
723             {
724                 SdPage* pPage = pDrawViewShell->GetActualPage();
725                 nPageNumber = pPage->GetPageNum() + 2;
726                 if ( nPageNumber >= mpDoc->GetPageCount() )
727                     nPageNumber = SDRPAGE_NOTFOUND;
728             }
729         }
730     }
731     else
732     {
733         // Is the bookmark a page?
734         nPageNumber = mpDoc->GetPageByName( rBookmark, bIsMasterPage );
735 
736         if (nPageNumber == SDRPAGE_NOTFOUND)
737         {
738             // Is the bookmark an object?
739             pObj = mpDoc->GetObj(rBookmark);
740 
741             if (pObj)
742             {
743                 nPageNumber = pObj->getSdrPageFromSdrObject()->GetPageNum();
744             }
745         }
746     }
747     if (nPageNumber != SDRPAGE_NOTFOUND)
748     {
749         // Jump to the bookmarked page.  This is done in three steps.
750 
751         SdPage* pPage;
752         if (bIsMasterPage)
753             pPage = static_cast<SdPage*>( mpDoc->GetMasterPage(nPageNumber) );
754         else
755             pPage = static_cast<SdPage*>( mpDoc->GetPage(nPageNumber) );
756 
757         // 1.) Change the view shell to the edit view, the notes view,
758         // or the handout view.
759         PageKind eNewPageKind = pPage->GetPageKind();
760 
761         if( (eNewPageKind != PageKind::Standard) && (mpDoc->GetDocumentType() == DocumentType::Draw) )
762             return;
763 
764         if (eNewPageKind != pDrawViewShell->GetPageKind())
765         {
766             // change work area
767             GetFrameView()->SetPageKind(eNewPageKind);
768             OUString sViewURL;
769             switch (eNewPageKind)
770             {
771                 case PageKind::Standard:
772                     sViewURL = FrameworkHelper::msImpressViewURL;
773                     break;
774                 case PageKind::Notes:
775                     sViewURL = FrameworkHelper::msNotesViewURL;
776                     break;
777                 case PageKind::Handout:
778                     sViewURL = FrameworkHelper::msHandoutViewURL;
779                     break;
780                 default:
781                     break;
782             }
783             if (!sViewURL.isEmpty())
784             {
785                 std::shared_ptr<FrameworkHelper> pHelper (
786                     FrameworkHelper::Instance(rBase));
787                 pHelper->RequestView(
788                     sViewURL,
789                     FrameworkHelper::msCenterPaneURL);
790                 pHelper->WaitForUpdate();
791 
792                 // Get the new DrawViewShell.
793                 mpViewShell = pHelper->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
794                 pDrawViewShell = dynamic_cast<sd::DrawViewShell*>(mpViewShell);
795             }
796             else
797             {
798                 pDrawViewShell = nullptr;
799             }
800         }
801 
802         if (pDrawViewShell != nullptr)
803         {
804             setEditMode(pDrawViewShell, bIsMasterPage);
805 
806             // Make the bookmarked page the current page.  This is done
807             // by using the API because this takes care of all the
808             // little things to be done.  Especially writing the view
809             // data to the frame view.
810             sal_uInt16 nSdPgNum = (nPageNumber - 1) / 2;
811             Reference<drawing::XDrawView> xController (rBase.GetController(), UNO_QUERY);
812             if (xController.is())
813             {
814                 Reference<drawing::XDrawPage> xDrawPage (pPage->getUnoPage(), UNO_QUERY);
815                 xController->setCurrentPage (xDrawPage);
816             }
817             else
818             {
819                 // As a fall back switch to the page via the core.
820                 DBG_ASSERT (xController.is(),
821                     "DrawDocShell::GotoBookmark: can't switch page via API");
822                 pDrawViewShell->SwitchPage(nSdPgNum);
823             }
824 
825             if (pDrawViewShell->GetDispatcher())
826             {
827                 // show page
828                 SvxZoomItem aZoom;
829                 aZoom.SetType( SvxZoomType::WHOLEPAGE );
830                 pDrawViewShell->GetDispatcher()->ExecuteList(SID_ATTR_ZOOM, SfxCallMode::ASYNCHRON, { &aZoom });
831             }
832 
833             if (pObj != nullptr)
834             {
835                 // select object
836                 pDrawViewShell->GetView()->UnmarkAll();
837                 pDrawViewShell->GetView()->MarkObj(
838                     pObj,
839                     pDrawViewShell->GetView()->GetSdrPageView());
840             }
841         }
842     }
843 
844     SfxBindings& rBindings = ((pDrawViewShell && pDrawViewShell->GetViewFrame()!=nullptr)
845         ? pDrawViewShell->GetViewFrame()
846         : SfxViewFrame::Current() )->GetBindings();
847 
848     rBindings.Invalidate(SID_NAVIGATOR_STATE, true);
849     rBindings.Invalidate(SID_NAVIGATOR_PAGENAME);
850 }
851 
852 /**
853  * If it should become a document template.
854  */
SaveAsOwnFormat(SfxMedium & rMedium)855 bool DrawDocShell::SaveAsOwnFormat( SfxMedium& rMedium )
856 {
857 
858     std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
859 
860     if (pFilter->IsOwnTemplateFormat())
861     {
862         /* now the StarDraw specialty:
863            we assign known layout names to the layout template of the first
864            page, we set the layout names of the affected masterpages and pages.
865            We inform all text objects of the affected standard, note and
866            masterpages about the name change.
867         */
868 
869         OUString aLayoutName;
870 
871         SfxStringItem const * pLayoutItem;
872         if( rMedium.GetItemSet()->GetItemState(SID_TEMPLATE_NAME, false, reinterpret_cast<const SfxPoolItem**>(& pLayoutItem) ) == SfxItemState::SET )
873         {
874             aLayoutName = pLayoutItem->GetValue();
875         }
876         else
877         {
878             INetURLObject aURL( rMedium.GetName() );
879             aURL.removeExtension();
880             aLayoutName = aURL.getName();
881         }
882 
883         if (aLayoutName.isEmpty())
884         {
885             sal_uInt32 nCount = mpDoc->GetMasterSdPageCount(PageKind::Standard);
886             for (sal_uInt32 i = 0; i < nCount; ++i)
887             {
888                 OUString aOldPageLayoutName = mpDoc->GetMasterSdPage(i, PageKind::Standard)->GetLayoutName();
889                 OUString aNewLayoutName = aLayoutName;
890                 // Don't add suffix for the first master page
891                 if( i > 0 )
892                     aNewLayoutName += OUString::number(i);
893 
894                 mpDoc->RenameLayoutTemplate(aOldPageLayoutName, aNewLayoutName);
895             }
896         }
897     }
898 
899     return SfxObjectShell::SaveAsOwnFormat(rMedium);
900 }
901 
FillClass(SvGlobalName * pClassName,SotClipboardFormatId * pFormat,OUString * pFullTypeName,sal_Int32 nFileFormat,bool bTemplate) const902 void DrawDocShell::FillClass(SvGlobalName* pClassName,
903                                         SotClipboardFormatId* pFormat,
904                                         OUString* pFullTypeName,
905                                         sal_Int32 nFileFormat,
906                                         bool bTemplate /* = false */) const
907 {
908     if (nFileFormat == SOFFICE_FILEFORMAT_60)
909     {
910         if ( meDocType == DocumentType::Draw )
911         {
912             *pClassName = SvGlobalName(SO3_SDRAW_CLASSID_60);
913             *pFormat = SotClipboardFormatId::STARDRAW_60;
914             *pFullTypeName = SdResId(STR_GRAPHIC_DOCUMENT_FULLTYPE_60);
915         }
916         else
917         {
918             *pClassName = SvGlobalName(SO3_SIMPRESS_CLASSID_60);
919             *pFormat = SotClipboardFormatId::STARIMPRESS_60;
920             *pFullTypeName = SdResId(STR_IMPRESS_DOCUMENT_FULLTYPE_60);
921         }
922     }
923     else if (nFileFormat == SOFFICE_FILEFORMAT_8)
924     {
925         if ( meDocType == DocumentType::Draw )
926         {
927             *pClassName = SvGlobalName(SO3_SDRAW_CLASSID_60);
928             *pFormat = bTemplate ? SotClipboardFormatId::STARDRAW_8_TEMPLATE : SotClipboardFormatId::STARDRAW_8;
929             *pFullTypeName = SdResId(STR_GRAPHIC_DOCUMENT_FULLTYPE_80); // HACK: method will be removed with new storage API
930         }
931         else
932         {
933             *pClassName = SvGlobalName(SO3_SIMPRESS_CLASSID_60);
934             *pFormat = bTemplate ? SotClipboardFormatId::STARIMPRESS_8_TEMPLATE : SotClipboardFormatId::STARIMPRESS_8;
935             *pFullTypeName = SdResId(STR_IMPRESS_DOCUMENT_FULLTYPE_80); // HACK: method will be removed with new storage API
936         }
937     }
938 }
939 
GetDocumentRefDev()940 OutputDevice* DrawDocShell::GetDocumentRefDev()
941 {
942     OutputDevice* pReferenceDevice = SfxObjectShell::GetDocumentRefDev ();
943     // Only when our parent does not have a reference device then we return
944     // our own.
945     if (pReferenceDevice == nullptr && mpDoc != nullptr)
946         pReferenceDevice = mpDoc->GetRefDevice ();
947     return pReferenceDevice;
948 }
949 
950 /** executes the SID_OPENDOC slot to let the framework open a document
951     with the given URL and this document as a referer */
OpenBookmark(const OUString & rBookmarkURL)952 void DrawDocShell::OpenBookmark( const OUString& rBookmarkURL )
953 {
954     SfxStringItem   aStrItem( SID_FILE_NAME, rBookmarkURL );
955     SfxStringItem   aReferer( SID_REFERER, GetMedium()->GetName() );
956     const SfxPoolItem* ppArgs[] = { &aStrItem, &aReferer, nullptr };
957     ( mpViewShell ? mpViewShell->GetViewFrame() : SfxViewFrame::Current() )->GetBindings().Execute( SID_OPENHYPERLINK, ppArgs );
958 }
959 
CreateDocumentInfoDialog(weld::Window * pParent,const SfxItemSet & rSet)960 std::shared_ptr<SfxDocumentInfoDialog> DrawDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet)
961 {
962     std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet);
963     DrawDocShell* pDocSh = dynamic_cast<DrawDocShell*>(SfxObjectShell::Current());
964     if( pDocSh == this )
965     {
966         xDlg->AddFontTabPage();
967     }
968     return xDlg;
969 }
970 
setEditMode(DrawViewShell * pDrawViewShell,bool isMasterPage)971 void DrawDocShell::setEditMode(DrawViewShell* pDrawViewShell, bool isMasterPage)
972 {
973     // Set the edit mode to either the normal edit mode or the
974     // master page mode.
975     EditMode eNewEditMode = EditMode::Page;
976     if (isMasterPage)
977     {
978         eNewEditMode = EditMode::MasterPage;
979     }
980 
981     if (eNewEditMode != pDrawViewShell->GetEditMode())
982     {
983         // Set EditMode
984         pDrawViewShell->ChangeEditMode(eNewEditMode, false);
985     }
986 }
987 } // end of namespace sd
988 
989 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
990