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 <memory>
21 #include <DrawDocShell.hxx>
22 #include <svx/svdpagv.hxx>
23 #include <svx/svxdlg.hxx>
24
25 #include <helpids.h>
26 #include <ViewShell.hxx>
27 #include <FrameView.hxx>
28 #include <drawdoc.hxx>
29 #include <sdpage.hxx>
30 #include <ClientView.hxx>
31 #include <Window.hxx>
32 #include <strings.hrc>
33
34 #include <sdresid.hxx>
35 #include <fupoor.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/virdev.hxx>
38 #include <rtl/character.hxx>
39 #include <tools/debug.hxx>
40
41 namespace sd {
42
43 /**
44 * Drawing of DocShell (with the helper class SdDrawViewShell)
45 */
Draw(OutputDevice * pOut,const JobSetup &,sal_uInt16 nAspect)46 void DrawDocShell::Draw(OutputDevice* pOut, const JobSetup&, sal_uInt16 nAspect)
47 {
48 if (nAspect == ASPECT_THUMBNAIL)
49 {
50 // THUMBNAIL: here we may can set the draft mode
51 }
52
53 std::unique_ptr<ClientView> pView( new ClientView(this, pOut) );
54
55 pView->SetHlplVisible(false);
56 pView->SetGridVisible(false);
57 pView->SetBordVisible(false);
58 pView->SetPageVisible(false);
59 pView->SetGlueVisible(false);
60
61 SdPage* pSelectedPage = nullptr;
62
63 const std::vector<std::unique_ptr<sd::FrameView>> &rViews = mpDoc->GetFrameViewList();
64 if( !rViews.empty() )
65 {
66 sd::FrameView* pFrameView = rViews[0].get();
67 if( pFrameView->GetPageKind() == PageKind::Standard )
68 {
69 sal_uInt16 nSelectedPage = pFrameView->GetSelectedPage();
70 pSelectedPage = mpDoc->GetSdPage(nSelectedPage, PageKind::Standard);
71 }
72 }
73
74 if( nullptr == pSelectedPage )
75 {
76 SdPage* pPage = nullptr;
77 sal_uInt16 nPageCnt = mpDoc->GetSdPageCount(PageKind::Standard);
78
79 for (sal_uInt16 i = 0; i < nPageCnt; i++)
80 {
81 pPage = mpDoc->GetSdPage(i, PageKind::Standard);
82
83 if ( pPage->IsSelected() )
84 pSelectedPage = pPage;
85 }
86
87 if( nullptr == pSelectedPage )
88 pSelectedPage = mpDoc->GetSdPage(0, PageKind::Standard);
89 }
90
91 ::tools::Rectangle aVisArea = GetVisArea(nAspect);
92 pOut->IntersectClipRegion(aVisArea);
93 pView->ShowSdrPage(pSelectedPage);
94
95 if (pOut->GetOutDevType() == OUTDEV_WINDOW)
96 return;
97
98 MapMode aOldMapMode = pOut->GetMapMode();
99
100 if (pOut->GetOutDevType() == OUTDEV_PRINTER)
101 {
102 MapMode aMapMode = aOldMapMode;
103 Point aOrigin = aMapMode.GetOrigin();
104 aOrigin.AdjustX(1 );
105 aOrigin.AdjustY(1 );
106 aMapMode.SetOrigin(aOrigin);
107 pOut->SetMapMode(aMapMode);
108 }
109
110 vcl::Region aRegion(aVisArea);
111 pView->CompleteRedraw(pOut, aRegion);
112
113 if (pOut->GetOutDevType() == OUTDEV_PRINTER)
114 {
115 pOut->SetMapMode(aOldMapMode);
116 }
117 }
118
GetVisArea(sal_uInt16 nAspect) const119 ::tools::Rectangle DrawDocShell::GetVisArea(sal_uInt16 nAspect) const
120 {
121 ::tools::Rectangle aVisArea;
122
123 if( ( ASPECT_THUMBNAIL == nAspect ) || ( ASPECT_DOCPRINT == nAspect ) )
124 {
125 // provide size of first page
126 MapMode aSrcMapMode(MapUnit::MapPixel);
127 MapMode aDstMapMode(MapUnit::Map100thMM);
128 Size aSize = mpDoc->GetSdPage(0, PageKind::Standard)->GetSize();
129 aSrcMapMode.SetMapUnit(MapUnit::Map100thMM);
130
131 aSize = Application::GetDefaultDevice()->LogicToLogic(aSize, &aSrcMapMode, &aDstMapMode);
132 aVisArea.SetSize(aSize);
133 }
134 else
135 {
136 aVisArea = SfxObjectShell::GetVisArea(nAspect);
137 }
138
139 if (aVisArea.IsEmpty() && mpViewShell)
140 {
141 vcl::Window* pWin = mpViewShell->GetActiveWindow();
142
143 if (pWin)
144 {
145 aVisArea = pWin->PixelToLogic(::tools::Rectangle(Point(0,0), pWin->GetOutputSizePixel()));
146 }
147 }
148
149 return aVisArea;
150 }
151
Connect(ViewShell * pViewSh)152 void DrawDocShell::Connect(ViewShell* pViewSh)
153 {
154 mpViewShell = pViewSh;
155 }
156
Disconnect(ViewShell const * pViewSh)157 void DrawDocShell::Disconnect(ViewShell const * pViewSh)
158 {
159 if (mpViewShell == pViewSh)
160 {
161 mpViewShell = nullptr;
162 }
163 }
164
GetFrameView()165 FrameView* DrawDocShell::GetFrameView()
166 {
167 FrameView* pFrameView = nullptr;
168
169 if (mpViewShell)
170 {
171 pFrameView = mpViewShell->GetFrameView();
172 }
173
174 return pFrameView;
175 }
176
177 /**
178 * Creates a bitmap of an arbitrary page
179 */
GetPagePreviewBitmap(SdPage * pPage)180 BitmapEx DrawDocShell::GetPagePreviewBitmap(SdPage* pPage)
181 {
182 const sal_uInt16 nMaxEdgePixel = 90;
183 MapMode aMapMode( MapUnit::Map100thMM );
184 const Size aSize( pPage->GetSize() );
185 const Point aNullPt;
186 ScopedVclPtrInstance< VirtualDevice > pVDev( *Application::GetDefaultDevice() );
187
188 pVDev->SetMapMode( aMapMode );
189
190 const Size aPixSize( pVDev->LogicToPixel( aSize ) );
191 const sal_uLong nMaxEdgePix = std::max( aPixSize.Width(), aPixSize.Height() );
192 Fraction aFrac( nMaxEdgePixel, nMaxEdgePix );
193
194 aMapMode.SetScaleX( aFrac );
195 aMapMode.SetScaleY( aFrac );
196 pVDev->SetMapMode( aMapMode );
197 pVDev->SetOutputSize( aSize );
198
199 // that we also get the dark lines at the right and bottom page margin
200 aFrac = Fraction( nMaxEdgePixel - 1, nMaxEdgePix );
201 aMapMode.SetScaleX( aFrac );
202 aMapMode.SetScaleY( aFrac );
203 pVDev->SetMapMode( aMapMode );
204
205 std::unique_ptr<ClientView> pView(new ClientView( this, pVDev ));
206 FrameView* pFrameView = GetFrameView();
207 pView->ShowSdrPage( pPage );
208
209 if ( GetFrameView() )
210 {
211 // initialize the drawing-(screen) attributes
212 pView->SetGridCoarse( pFrameView->GetGridCoarse() );
213 pView->SetGridFine( pFrameView->GetGridFine() );
214 pView->SetSnapGridWidth(pFrameView->GetSnapGridWidthX(), pFrameView->GetSnapGridWidthY());
215 pView->SetGridVisible( pFrameView->IsGridVisible() );
216 pView->SetGridFront( pFrameView->IsGridFront() );
217 pView->SetSnapAngle( pFrameView->GetSnapAngle() );
218 pView->SetGridSnap( pFrameView->IsGridSnap() );
219 pView->SetBordSnap( pFrameView->IsBordSnap() );
220 pView->SetHlplSnap( pFrameView->IsHlplSnap() );
221 pView->SetOFrmSnap( pFrameView->IsOFrmSnap() );
222 pView->SetOPntSnap( pFrameView->IsOPntSnap() );
223 pView->SetOConSnap( pFrameView->IsOConSnap() );
224 pView->SetDragStripes( pFrameView->IsDragStripes() );
225 pView->SetFrameDragSingles( pFrameView->IsFrameDragSingles() );
226 pView->SetSnapMagneticPixel( pFrameView->GetSnapMagneticPixel() );
227 pView->SetMarkedHitMovesAlways( pFrameView->IsMarkedHitMovesAlways() );
228 pView->SetMoveOnlyDragging( pFrameView->IsMoveOnlyDragging() );
229 pView->SetSlantButShear( pFrameView->IsSlantButShear() );
230 pView->SetNoDragXorPolys( pFrameView->IsNoDragXorPolys() );
231 pView->SetCrookNoContortion( pFrameView->IsCrookNoContortion() );
232 pView->SetAngleSnapEnabled( pFrameView->IsAngleSnapEnabled() );
233 pView->SetBigOrtho( pFrameView->IsBigOrtho() );
234 pView->SetOrtho( pFrameView->IsOrtho() );
235
236 SdrPageView* pPageView = pView->GetSdrPageView();
237
238 if (pPageView)
239 {
240 if ( pPageView->GetVisibleLayers() != pFrameView->GetVisibleLayers() )
241 pPageView->SetVisibleLayers( pFrameView->GetVisibleLayers() );
242
243 if ( pPageView->GetPrintableLayers() != pFrameView->GetPrintableLayers() )
244 pPageView->SetPrintableLayers( pFrameView->GetPrintableLayers() );
245
246 if ( pPageView->GetLockedLayers() != pFrameView->GetLockedLayers() )
247 pPageView->SetLockedLayers( pFrameView->GetLockedLayers() );
248
249 pPageView->SetHelpLines( pFrameView->GetStandardHelpLines() );
250 }
251
252 if ( pView->GetActiveLayer() != pFrameView->GetActiveLayer() )
253 pView->SetActiveLayer( pFrameView->GetActiveLayer() );
254 }
255
256 pView->CompleteRedraw( pVDev, vcl::Region(::tools::Rectangle(aNullPt, aSize)) );
257
258 // IsRedrawReady() always gives sal_True while ( !pView->IsRedrawReady() ) {}
259 pView.reset();
260
261 pVDev->SetMapMode( MapMode() );
262
263 BitmapEx aPreview( pVDev->GetBitmapEx( aNullPt, pVDev->GetOutputSizePixel() ) );
264
265 DBG_ASSERT(!!aPreview, "Preview-Bitmap could not be generated");
266
267 return aPreview;
268 }
269
270 /**
271 * Checks if the page exists. If so, we force the user to enter a not yet used
272 * name.
273 * @return sal_False if the user cancels the action.
274 */
CheckPageName(weld::Window * pWin,OUString & rName)275 bool DrawDocShell::CheckPageName(weld::Window* pWin, OUString& rName)
276 {
277 const OUString aStrForDlg( rName );
278 bool bIsNameValid = IsNewPageNameValid( rName, true );
279
280 if( ! bIsNameValid )
281 {
282 OUString aDesc;
283 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
284
285 if (GetDocumentType() == DocumentType::Draw)
286 aDesc = SdResId( STR_WARN_PAGE_EXISTS_DRAW );
287 else
288 aDesc = SdResId( STR_WARN_PAGE_EXISTS );
289
290 ScopedVclPtr<AbstractSvxNameDialog> aNameDlg(pFact->CreateSvxNameDialog(pWin, aStrForDlg, aDesc));
291 aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE );
292
293 aNameDlg->SetCheckNameHdl( LINK( this, DrawDocShell, RenameSlideHdl ) );
294
295 rtl::Reference<FuPoor> xFunc( mpViewShell->GetCurrentFunction() );
296 if( xFunc.is() )
297 xFunc->cancel();
298
299 if( aNameDlg->Execute() == RET_OK )
300 {
301 aNameDlg->GetName( rName );
302 bIsNameValid = IsNewPageNameValid( rName );
303 }
304 }
305
306 return bIsNameValid;
307 }
308
IsNewPageNameValid(OUString & rInOutPageName,bool bResetStringIfStandardName)309 bool DrawDocShell::IsNewPageNameValid( OUString & rInOutPageName, bool bResetStringIfStandardName /* = false */ )
310 {
311 bool bCanUseNewName = false;
312
313 // check if name is something like 'Slide n'
314 OUString aStrPage(SdResId(STR_SD_PAGE) + " ");
315
316 bool bIsStandardName = false;
317
318 // prevent also _future_ slide names of the form "'STR_SD_PAGE' + ' ' + '[0-9]+|[a-z]|[A-Z]|[CDILMVX]+|[cdilmvx]+'"
319 // (arabic, lower- and upper case single letter, lower- and upper case roman numbers)
320 if (rInOutPageName.startsWith(aStrPage) &&
321 rInOutPageName.getLength() > aStrPage.getLength())
322 {
323 sal_Int32 nIdx{ aStrPage.getLength() };
324 OUString sRemainder = rInOutPageName.getToken(0, ' ', nIdx);
325 if (sRemainder[0] >= '0' && sRemainder[0] <= '9')
326 {
327 // check for arabic numbering
328
329 sal_Int32 nIndex = 1;
330 // skip all following numbers
331 while (nIndex < sRemainder.getLength() &&
332 sRemainder[nIndex] >= '0' && sRemainder[nIndex] <= '9')
333 {
334 nIndex++;
335 }
336
337 // EOL? Reserved name!
338 if (nIndex >= sRemainder.getLength())
339 {
340 bIsStandardName = true;
341 }
342 }
343 else if (sRemainder.getLength() == 1 &&
344 rtl::isAsciiLowerCase(sRemainder[0]))
345 {
346 // lower case, single character: reserved
347 bIsStandardName = true;
348 }
349 else if (sRemainder.getLength() == 1 &&
350 rtl::isAsciiUpperCase(sRemainder[0]))
351 {
352 // upper case, single character: reserved
353 bIsStandardName = true;
354 }
355 else
356 {
357 // check for upper/lower case roman numbering
358 OUString sReserved("cdilmvx");
359
360 // skip all following characters contained in one reserved class
361 if (sReserved.indexOf(sRemainder[0]) == -1)
362 sReserved = sReserved.toAsciiUpperCase();
363
364 sal_Int32 nIndex = 0;
365 while (nIndex < sRemainder.getLength() &&
366 sReserved.indexOf(sRemainder[nIndex]) != -1)
367 {
368 nIndex++;
369 }
370
371 // EOL? Reserved name!
372 if (nIndex >= sRemainder.getLength())
373 {
374 bIsStandardName = true;
375 }
376 }
377 }
378
379 if( bIsStandardName )
380 {
381 if( bResetStringIfStandardName )
382 {
383 // this is for insertion of slides from other files with standard
384 // name. They get a new standard name, if the string is set to an
385 // empty one.
386 rInOutPageName.clear();
387 bCanUseNewName = true;
388 }
389 else
390 bCanUseNewName = false;
391 }
392 else
393 {
394 if (!rInOutPageName.isEmpty())
395 {
396 bool bOutDummy;
397 sal_uInt16 nExistingPageNum = mpDoc->GetPageByName( rInOutPageName, bOutDummy );
398 bCanUseNewName = ( nExistingPageNum == SDRPAGE_NOTFOUND );
399 }
400 else
401 bCanUseNewName = false;
402 }
403
404 return bCanUseNewName;
405 }
406
IsPageNameUnique(const OUString & rPageName) const407 bool DrawDocShell::IsPageNameUnique( const OUString & rPageName ) const
408 {
409 return mpDoc->IsPageNameUnique(rPageName);
410 }
411
IMPL_LINK(DrawDocShell,RenameSlideHdl,AbstractSvxNameDialog &,rDialog,bool)412 IMPL_LINK( DrawDocShell, RenameSlideHdl, AbstractSvxNameDialog&, rDialog, bool )
413 {
414 OUString aNewName;
415 rDialog.GetName( aNewName );
416 return IsNewPageNameValid( aNewName );
417 }
418
419 } // end of namespace sd
420
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
422