Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name print3.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx

/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx

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 <vcl/weld.hxx>
21#include <vcl/print.hxx>
22#include <vcl/svapp.hxx>
23#include <vcl/metaact.hxx>
24#include <configsettings.hxx>
25#include <tools/urlobj.hxx>
26#include <comphelper/processfactory.hxx>
27#include <comphelper/sequence.hxx>
28#include <sal/types.h>
29#include <sal/log.hxx>
30#include <tools/debug.hxx>
31#include <tools/diagnose_ex.h>
32
33#include <printdlg.hxx>
34#include <svdata.hxx>
35#include <salinst.hxx>
36#include <salprn.hxx>
37#include <strings.hrc>
38
39#include <com/sun/star/ui/dialogs/FilePicker.hpp>
40#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
41#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
42#include <com/sun/star/view/DuplexMode.hpp>
43#include <com/sun/star/lang/IllegalArgumentException.hpp>
44#include <com/sun/star/awt/Size.hpp>
45
46#include <unordered_map>
47#include <unordered_set>
48
49using namespace vcl;
50
51namespace {
52
53class ImplPageCache
54{
55 struct CacheEntry
56 {
57 GDIMetaFile aPage;
58 PrinterController::PageSize aSize;
59 };
60
61 std::vector< CacheEntry > maPages;
62 std::vector< sal_Int32 > maPageNumbers;
63 std::vector< sal_Int32 > maCacheRanking;
64
65 static const sal_Int32 nCacheSize = 6;
66
67 void updateRanking( sal_Int32 nLastHit )
68 {
69 if( maCacheRanking[0] != nLastHit )
70 {
71 for( sal_Int32 i = nCacheSize-1; i > 0; i-- )
72 maCacheRanking[i] = maCacheRanking[i-1];
73 maCacheRanking[0] = nLastHit;
74 }
75 }
76
77public:
78 ImplPageCache()
79 : maPages( nCacheSize )
80 , maPageNumbers( nCacheSize, -1 )
81 , maCacheRanking( nCacheSize )
82 {
83 for( sal_Int32 i = 0; i < nCacheSize; i++ )
84 maCacheRanking[i] = nCacheSize - i - 1;
85 }
86
87 // caution: does not ensure uniqueness
88 void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize )
89 {
90 sal_Int32 nReplacePage = maCacheRanking.back();
91 maPages[ nReplacePage ].aPage = i_rPage;
92 maPages[ nReplacePage ].aSize = i_rSize;
93 maPageNumbers[ nReplacePage ] = i_nPageNo;
94 // cache insertion means in our case, the page was just queried
95 // so update the ranking
96 updateRanking( nReplacePage );
97 }
98
99 // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6
100 // this needs to be urgently rewritten. However do NOT increase the cache size lightly,
101 // whole pages can be rather memory intensive
102 bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize )
103 {
104 for( sal_Int32 i = 0; i < nCacheSize; ++i )
105 {
106 if( maPageNumbers[i] == i_nPageNo )
107 {
108 updateRanking( i );
109 o_rPageFile = maPages[i].aPage;
110 o_rSize = maPages[i].aSize;
111 return true;
112 }
113 }
114 return false;
115 }
116
117 void invalidate()
118 {
119 for( sal_Int32 i = 0; i < nCacheSize; ++i )
120 {
121 maPageNumbers[i] = -1;
122 maPages[i].aPage.Clear();
123 maCacheRanking[i] = nCacheSize - i - 1;
124 }
125 }
126};
127
128}
129
130class vcl::ImplPrinterControllerData
131{
132public:
133 struct ControlDependency
134 {
135 OUString maDependsOnName;
136 sal_Int32 mnDependsOnEntry;
137
138 ControlDependency() : mnDependsOnEntry( -1 ) {}
139 };
140
141 typedef std::unordered_map< OUString, size_t > PropertyToIndexMap;
142 typedef std::unordered_map< OUString, ControlDependency > ControlDependencyMap;
143 typedef std::unordered_map< OUString, css::uno::Sequence< sal_Bool > > ChoiceDisableMap;
144
145 VclPtr< Printer > mxPrinter;
146 weld::Window* mpWindow;
147 css::uno::Sequence< css::beans::PropertyValue > maUIOptions;
148 std::vector< css::beans::PropertyValue > maUIProperties;
149 std::vector< bool > maUIPropertyEnabled;
150 PropertyToIndexMap maPropertyToIndex;
151 ControlDependencyMap maControlDependencies;
152 ChoiceDisableMap maChoiceDisableMap;
153 bool mbFirstPage;
154 bool mbLastPage;
155 bool mbReversePageOrder;
156 bool mbPapersizeFromSetup;
157 bool mbPapersizeFromUser;
158 bool mbPrinterModified;
159 css::view::PrintableState meJobState;
160
161 vcl::PrinterController::MultiPageSetup maMultiPage;
162
163 std::shared_ptr<vcl::PrintProgressDialog> mxProgress;
164
165 ImplPageCache maPageCache;
166
167 // set by user through printer properties subdialog of printer settings dialog
168 Size maDefaultPageSize;
169 // set by user through print dialog
170 Size maUserPageSize;
171 // set by user through printer properties subdialog of printer settings dialog
172 sal_Int32 mnDefaultPaperBin;
173 // Set by user through printer properties subdialog of print dialog.
174 // Overrides application-set tray for a page.
175 sal_Int32 mnFixedPaperBin;
176
177 // N.B. Apparently we have three levels of paper tray settings
178 // (latter overrides former):
179 // 1. default tray
180 // 2. tray set for a concrete page by an application, e.g., writer
181 // allows setting a printer tray (for the default printer) for a
182 // page style. This setting can be overridden by user by selecting
183 // "Use only paper tray from printer preferences" on the Options
184 // page in the print dialog, in which case the default tray is
185 // used for all pages.
186 // 3. tray set in printer properties the printer dialog
187 // I'm not quite sure why 1. and 3. are distinct, but the commit
188 // history suggests this is intentional...
189
190 ImplPrinterControllerData() :
191 mpWindow( nullptr ),
192 mbFirstPage( true ),
193 mbLastPage( false ),
194 mbReversePageOrder( false ),
195 mbPapersizeFromSetup( false ),
196 mbPapersizeFromUser( false ),
197 mbPrinterModified( false ),
198 meJobState( css::view::PrintableState_JOB_STARTED ),
199 mnDefaultPaperBin( -1 ),
200 mnFixedPaperBin( -1 )
201 {}
202
203 ~ImplPrinterControllerData()
204 {
205 if (mxProgress)
206 {
207 mxProgress->response(RET_CANCEL);
208 mxProgress.reset();
209 }
210 }
211
212 const Size& getRealPaperSize( const Size& i_rPageSize, bool bNoNUP ) const
213 {
214 if ( mbPapersizeFromUser )
215 return maUserPageSize;
216 if( mbPapersizeFromSetup )
217 return maDefaultPageSize;
218 if( maMultiPage.nRows * maMultiPage.nColumns > 1 && ! bNoNUP )
219 return maMultiPage.aPaperSize;
220 return i_rPageSize;
221 }
222 PrinterController::PageSize modifyJobSetup( const css::uno::Sequence< css::beans::PropertyValue >& i_rProps );
223 void resetPaperToLastConfigured();
224};
225
226PrinterController::PrinterController(const VclPtr<Printer>& i_xPrinter, weld::Window* i_pWindow)
227 : mpImplData( new ImplPrinterControllerData )
228{
229 mpImplData->mxPrinter = i_xPrinter;
230 mpImplData->mpWindow = i_pWindow;
231}
232
233static OUString queryFile( Printer const * pPrinter )
234{
235 OUString aResult;
236
237 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
238 css::uno::Reference< css::ui::dialogs::XFilePicker3 > xFilePicker = css::ui::dialogs::FilePicker::createWithMode(xContext, css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION);
239
240 try
241 {
242#ifdef UNX1
243 // add PostScript and PDF
244 bool bPS = true, bPDF = true;
245 if( pPrinter )
246 {
247 if( pPrinter->GetCapabilities( PrinterCapType::PDF ) )
248 bPS = false;
249 else
250 bPDF = false;
251 }
252 if( bPS )
253 xFilePicker->appendFilter( "PostScript", "*.ps" );
254 if( bPDF )
255 xFilePicker->appendFilter( "Portable Document Format", "*.pdf" );
256#elif defined _WIN32
257 (void)pPrinter;
258 xFilePicker->appendFilter( "*.PRN", "*.prn" );
259#endif
260 // add arbitrary files
261 xFilePicker->appendFilter(VclResId(SV_STDTEXT_ALLFILETYPESreinterpret_cast<char const *>("SV_STDTEXT_ALLFILETYPES"
"\004" u8"Any type")
), "*.*");
262 }
263 catch (const css::lang::IllegalArgumentException&)
264 {
265 TOOLS_WARN_EXCEPTION( "vcl.gdi", "caught IllegalArgumentException when registering filter" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "caught IllegalArgumentException when registering filter"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "265" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "caught IllegalArgumentException when registering filter"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught IllegalArgumentException when registering filter"
<< " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "265" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught IllegalArgumentException when registering filter"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "265" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "caught IllegalArgumentException when registering filter"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught IllegalArgumentException when registering filter"
<< " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "265" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
266 }
267
268 if( xFilePicker->execute() == css::ui::dialogs::ExecutableDialogResults::OK )
269 {
270 css::uno::Sequence< OUString > aPathSeq( xFilePicker->getSelectedFiles() );
271 INetURLObject aObj( aPathSeq[0] );
272 aResult = aObj.PathToFileName();
273 }
274 return aResult;
275}
276
277namespace {
278
279struct PrintJobAsync
280{
281 std::shared_ptr<PrinterController> mxController;
282 JobSetup maInitSetup;
283
284 PrintJobAsync(const std::shared_ptr<PrinterController>& i_xController,
285 const JobSetup& i_rInitSetup)
286 : mxController( i_xController ), maInitSetup( i_rInitSetup )
287 {}
288
289 DECL_LINK( ExecJob, void*, void )static void LinkStubExecJob(void *, void*); void ExecJob(void
*)
;
290};
291
292}
293
294IMPL_LINK_NOARG(PrintJobAsync, ExecJob, void*, void)void PrintJobAsync::LinkStubExecJob(void * instance, void* data
) { return static_cast<PrintJobAsync *>(instance)->ExecJob
(data); } void PrintJobAsync::ExecJob(__attribute__ ((unused)
) void*)
295{
296 Printer::ImplPrintJob(mxController, maInitSetup);
297
298 // clean up, do not access members after this
299 delete this;
300}
301
302void Printer::PrintJob(const std::shared_ptr<PrinterController>& i_xController,
303 const JobSetup& i_rInitSetup)
304{
305 bool bSynchronous = false;
306 css::beans::PropertyValue* pVal = i_xController->getValue( "Wait" );
307 if( pVal )
308 pVal->Value >>= bSynchronous;
309
310 if( bSynchronous )
311 ImplPrintJob(i_xController, i_rInitSetup);
312 else
313 {
314 PrintJobAsync* pAsync = new PrintJobAsync(i_xController, i_rInitSetup);
315 Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob )::tools::detail::makeLink( ::tools::detail::castTo<PrintJobAsync
*>(pAsync), &PrintJobAsync::LinkStubExecJob)
);
316 }
317}
318
319bool Printer::PreparePrintJob(std::shared_ptr<PrinterController> xController,
320 const JobSetup& i_rInitSetup)
321{
322 // check if there is a default printer; if not, show an error box (if appropriate)
323 if( GetDefaultPrinterName().isEmpty() )
324 {
325 if (xController->isShowDialogs())
326 {
327 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(xController->getWindow(), "vcl/ui/errornoprinterdialog.ui"));
328 std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("ErrorNoPrinterDialog"));
329 xBox->run();
330 }
331 xController->setValue( "IsDirect",
332 css::uno::makeAny( false ) );
333 }
334
335 // setup printer
336
337 // #i114306# changed behavior back from persistence
338 // if no specific printer is already set, create the default printer
339 if (!xController->getPrinter())
340 {
341 OUString aPrinterName( i_rInitSetup.GetPrinterName() );
342 VclPtrInstance<Printer> xPrinter( aPrinterName );
343 xPrinter->SetJobSetup(i_rInitSetup);
344 xController->setPrinter(xPrinter);
345 xController->setPapersizeFromSetup(xPrinter->GetPrinterSettingsPreferred());
346 }
347
348 // reset last page property
349 xController->setLastPage(false);
350
351 // update "PageRange" property inferring from other properties:
352 // case 1: "Pages" set from UNO API ->
353 // setup "Print Selection" and insert "PageRange" attribute
354 // case 2: "All pages" is selected
355 // update "Page range" attribute to have a sensible default,
356 // but leave "All" as selected
357
358 // "Pages" attribute from API is now equivalent to "PageRange"
359 // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
360 // Argh ! That sure needs cleaning up
361 css::beans::PropertyValue* pContentVal = xController->getValue("PrintRange");
362 if( ! pContentVal )
363 pContentVal = xController->getValue("PrintContent");
364
365 // case 1: UNO API has set "Pages"
366 css::beans::PropertyValue* pPagesVal = xController->getValue("Pages");
367 if( pPagesVal )
368 {
369 OUString aPagesVal;
370 pPagesVal->Value >>= aPagesVal;
371 if( !aPagesVal.isEmpty() )
372 {
373 // "Pages" attribute from API is now equivalent to "PageRange"
374 // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
375 // Argh ! That sure needs cleaning up
376 if( pContentVal )
377 {
378 pContentVal->Value <<= sal_Int32( 1 );
379 xController->setValue("PageRange", pPagesVal->Value);
380 }
381 }
382 }
383 // case 2: is "All" selected ?
384 else if( pContentVal )
385 {
386 sal_Int32 nContent = -1;
387 if( pContentVal->Value >>= nContent )
388 {
389 if( nContent == 0 )
390 {
391 // do not overwrite PageRange if it is already set
392 css::beans::PropertyValue* pRangeVal = xController->getValue("PageRange");
393 OUString aRange;
394 if( pRangeVal )
395 pRangeVal->Value >>= aRange;
396 if( aRange.isEmpty() )
397 {
398 sal_Int32 nPages = xController->getPageCount();
399 if( nPages > 0 )
400 {
401 OUStringBuffer aBuf( 32 );
402 aBuf.append( "1" );
403 if( nPages > 1 )
404 {
405 aBuf.append( "-" );
406 aBuf.append( nPages );
407 }
408 xController->setValue("PageRange", css::uno::makeAny(aBuf.makeStringAndClear()));
409 }
410 }
411 }
412 }
413 }
414
415 css::beans::PropertyValue* pReverseVal = xController->getValue("PrintReverse");
416 if( pReverseVal )
417 {
418 bool bReverse = false;
419 pReverseVal->Value >>= bReverse;
420 xController->setReversePrint( bReverse );
421 }
422
423 css::beans::PropertyValue* pPapersizeFromSetupVal = xController->getValue("PapersizeFromSetup");
424 if( pPapersizeFromSetupVal )
425 {
426 bool bPapersizeFromSetup = false;
427 pPapersizeFromSetupVal->Value >>= bPapersizeFromSetup;
428 xController->setPapersizeFromSetup(bPapersizeFromSetup);
429 }
430
431 // setup NUp printing from properties
432 sal_Int32 nRows = xController->getIntProperty("NUpRows", 1);
433 sal_Int32 nCols = xController->getIntProperty("NUpColumns", 1);
434 if( nRows > 1 || nCols > 1 )
435 {
436 PrinterController::MultiPageSetup aMPS;
437 aMPS.nRows = std::max<sal_Int32>(nRows, 1);
438 aMPS.nColumns = std::max<sal_Int32>(nCols, 1);
439 sal_Int32 nValue = xController->getIntProperty("NUpPageMarginLeft", aMPS.nLeftMargin);
440 if( nValue >= 0 )
441 aMPS.nLeftMargin = nValue;
442 nValue = xController->getIntProperty("NUpPageMarginRight", aMPS.nRightMargin);
443 if( nValue >= 0 )
444 aMPS.nRightMargin = nValue;
445 nValue = xController->getIntProperty( "NUpPageMarginTop", aMPS.nTopMargin );
446 if( nValue >= 0 )
447 aMPS.nTopMargin = nValue;
448 nValue = xController->getIntProperty( "NUpPageMarginBottom", aMPS.nBottomMargin );
449 if( nValue >= 0 )
450 aMPS.nBottomMargin = nValue;
451 nValue = xController->getIntProperty( "NUpHorizontalSpacing", aMPS.nHorizontalSpacing );
452 if( nValue >= 0 )
453 aMPS.nHorizontalSpacing = nValue;
454 nValue = xController->getIntProperty( "NUpVerticalSpacing", aMPS.nVerticalSpacing );
455 if( nValue >= 0 )
456 aMPS.nVerticalSpacing = nValue;
457 aMPS.bDrawBorder = xController->getBoolProperty( "NUpDrawBorder", aMPS.bDrawBorder );
458 aMPS.nOrder = static_cast<NupOrderType>(xController->getIntProperty( "NUpSubPageOrder", static_cast<sal_Int32>(aMPS.nOrder) ));
459 aMPS.aPaperSize = xController->getPrinter()->PixelToLogic( xController->getPrinter()->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) );
460 css::beans::PropertyValue* pPgSizeVal = xController->getValue( "NUpPaperSize" );
461 css::awt::Size aSizeVal;
462 if( pPgSizeVal && (pPgSizeVal->Value >>= aSizeVal) )
463 {
464 aMPS.aPaperSize.setWidth( aSizeVal.Width );
465 aMPS.aPaperSize.setHeight( aSizeVal.Height );
466 }
467
468 xController->setMultipage( aMPS );
469 }
470
471 // in direct print case check whether there is anything to print.
472 // if not, show an errorbox (if appropriate)
473 if( xController->isShowDialogs() && xController->isDirectPrint() )
474 {
475 if( xController->getFilteredPageCount() == 0 )
476 {
477 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(xController->getWindow(), "vcl/ui/errornocontentdialog.ui"));
478 std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("ErrorNoContentDialog"));
479 xBox->run();
480 return false;
481 }
482 }
483
484 // check if the printer brings up its own dialog
485 // in that case leave the work to that dialog
486 if( ! xController->getPrinter()->GetCapabilities( PrinterCapType::ExternalDialog ) &&
487 ! xController->isDirectPrint() &&
488 xController->isShowDialogs()
489 )
490 {
491 try
492 {
493 PrintDialog aDlg(xController->getWindow(), xController);
494 if (!aDlg.run())
495 {
496 xController->abortJob();
497 return false;
498 }
499 if (aDlg.isPrintToFile())
500 {
501 OUString aFile = queryFile( xController->getPrinter().get() );
502 if( aFile.isEmpty() )
503 {
504 xController->abortJob();
505 return false;
506 }
507 xController->setValue( "LocalFileName",
508 css::uno::makeAny( aFile ) );
509 }
510 else if (aDlg.isSingleJobs())
511 {
512 xController->setValue( "PrintCollateAsSingleJobs",
513 css::uno::makeAny( true ) );
514 }
515 }
516 catch (const std::bad_alloc&)
517 {
518 }
519 }
520
521 xController->pushPropertiesToPrinter();
522 return true;
523}
524
525bool Printer::ExecutePrintJob(const std::shared_ptr<PrinterController>& xController)
526{
527 OUString aJobName;
528 css::beans::PropertyValue* pJobNameVal = xController->getValue( "JobName" );
529 if( pJobNameVal )
530 pJobNameVal->Value >>= aJobName;
531
532 return xController->getPrinter()->StartJob( aJobName, xController );
533}
534
535void Printer::FinishPrintJob(const std::shared_ptr<PrinterController>& xController)
536{
537 xController->resetPaperToLastConfigured();
538 xController->jobFinished( xController->getJobState() );
539}
540
541void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& xController,
542 const JobSetup& i_rInitSetup)
543{
544 if (PreparePrintJob(xController, i_rInitSetup))
545 {
546 ExecutePrintJob(xController);
547 }
548 FinishPrintJob(xController);
549}
550
551bool Printer::StartJob( const OUString& i_rJobName, std::shared_ptr<vcl::PrinterController> const & i_xController)
552{
553 mnError = ERRCODE_NONEErrCode(0);
554
555 if ( IsDisplayPrinter() )
556 return false;
557
558 if ( IsJobActive() || IsPrinting() )
559 return false;
560
561 sal_uInt32 nCopies = mnCopyCount;
562 bool bCollateCopy = mbCollateCopy;
563 bool bUserCopy = false;
564
565 if ( nCopies > 1 )
566 {
567 const sal_uInt32 nDevCopy = GetCapabilities( bCollateCopy
568 ? PrinterCapType::CollateCopies
569 : PrinterCapType::Copies );
570
571 // need to do copies by hand ?
572 if ( nCopies > nDevCopy )
573 {
574 bUserCopy = true;
575 nCopies = 1;
576 bCollateCopy = false;
577 }
578 }
579 else
580 bCollateCopy = false;
581
582 ImplSVData* pSVData = ImplGetSVData();
583 mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
584
585 if (!mpPrinter)
586 return false;
587
588 bool bSinglePrintJobs = false;
589 css::beans::PropertyValue* pSingleValue = i_xController->getValue("PrintCollateAsSingleJobs");
590 if( pSingleValue )
591 {
592 pSingleValue->Value >>= bSinglePrintJobs;
593 }
594
595 css::beans::PropertyValue* pFileValue = i_xController->getValue("LocalFileName");
596 if( pFileValue )
597 {
598 OUString aFile;
599 pFileValue->Value >>= aFile;
600 if( !aFile.isEmpty() )
601 {
602 mbPrintFile = true;
603 maPrintFile = aFile;
604 bSinglePrintJobs = false;
605 }
606 }
607
608 OUString* pPrintFile = nullptr;
609 if ( mbPrintFile )
610 pPrintFile = &maPrintFile;
611 mpPrinterOptions->ReadFromConfig( mbPrintFile );
612
613 mbPrinting = true;
614 if( GetCapabilities( PrinterCapType::UsePullModel ) )
615 {
616 mbJobActive = true;
617 // SAL layer does all necessary page printing
618 // and also handles showing a dialog
619 // that also means it must call jobStarted when the dialog is finished
620 // it also must set the JobState of the Controller
621 if( mpPrinter->StartJob( pPrintFile,
622 i_rJobName,
623 Application::GetDisplayName(),
624 &maJobSetup.ImplGetData(),
625 *i_xController) )
626 {
627 EndJob();
628 }
629 else
630 {
631 mnError = ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode());
632 if ( !mnError )
633 mnError = PRINTER_GENERALERRORErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 );
634 mbPrinting = false;
635 mpPrinter.reset();
636 mbJobActive = false;
637
638 GDIMetaFile aDummyFile;
639 i_xController->setLastPage(true);
640 i_xController->getFilteredPageFile(0, aDummyFile);
641
642 return false;
643 }
644 }
645 else
646 {
647 // possibly a dialog has been shown
648 // now the real job starts
649 i_xController->setJobState( css::view::PrintableState_JOB_STARTED );
650 i_xController->jobStarted();
651
652 int nJobs = 1;
653 int nOuterRepeatCount = 1;
654 int nInnerRepeatCount = 1;
655 if( bUserCopy )
656 {
657 if( mbCollateCopy )
658 nOuterRepeatCount = mnCopyCount;
659 else
660 nInnerRepeatCount = mnCopyCount;
661 }
662 if( bSinglePrintJobs )
663 {
664 nJobs = mnCopyCount;
665 nCopies = 1;
666 nOuterRepeatCount = nInnerRepeatCount = 1;
667 }
668
669 for( int nJobIteration = 0; nJobIteration < nJobs; nJobIteration++ )
670 {
671 bool bError = false;
672 if( mpPrinter->StartJob( pPrintFile,
673 i_rJobName,
674 Application::GetDisplayName(),
675 nCopies,
676 bCollateCopy,
677 i_xController->isDirectPrint(),
678 &maJobSetup.ImplGetData() ) )
679 {
680 bool bAborted = false;
681 mbJobActive = true;
682 i_xController->createProgressDialog();
683 const int nPages = i_xController->getFilteredPageCount();
684 // abort job, if no pages will be printed.
685 if ( nPages == 0 )
686 {
687 i_xController->abortJob();
688 bAborted = true;
689 }
690 for( int nOuterIteration = 0; nOuterIteration < nOuterRepeatCount && ! bAborted; nOuterIteration++ )
691 {
692 for( int nPage = 0; nPage < nPages && ! bAborted; nPage++ )
693 {
694 for( int nInnerIteration = 0; nInnerIteration < nInnerRepeatCount && ! bAborted; nInnerIteration++ )
695 {
696 if( nPage == nPages-1 &&
697 nOuterIteration == nOuterRepeatCount-1 &&
698 nInnerIteration == nInnerRepeatCount-1 &&
699 nJobIteration == nJobs-1 )
700 {
701 i_xController->setLastPage(true);
702 }
703 i_xController->printFilteredPage(nPage);
704 if (i_xController->isProgressCanceled())
705 {
706 i_xController->abortJob();
707 }
708 if (i_xController->getJobState() ==
709 css::view::PrintableState_JOB_ABORTED)
710 {
711 bAborted = true;
712 }
713 }
714 }
715 // FIXME: duplex ?
716 }
717 EndJob();
718
719 if( nJobIteration < nJobs-1 )
720 {
721 mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
722
723 if ( mpPrinter )
724 mbPrinting = true;
725 else
726 bError = true;
727 }
728 }
729 else
730 bError = true;
731
732 if( bError )
733 {
734 mnError = mpPrinter ? ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode()) : ERRCODE_NONEErrCode(0);
735 if ( !mnError )
736 mnError = PRINTER_GENERALERRORErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 );
737 i_xController->setJobState( mnError == PRINTER_ABORTErrCode( ErrCodeArea::Io, ErrCodeClass::Abort, 27 )
738 ? css::view::PrintableState_JOB_ABORTED
739 : css::view::PrintableState_JOB_FAILED );
740 mbPrinting = false;
741 mpPrinter.reset();
742
743 return false;
744 }
745 }
746
747 if (i_xController->getJobState() == css::view::PrintableState_JOB_STARTED)
748 i_xController->setJobState(css::view::PrintableState_JOB_SPOOLED);
749 }
750
751 // make last used printer persistent for UI jobs
752 if (i_xController->isShowDialogs() && !i_xController->isDirectPrint())
753 {
754 SettingsConfigItem* pItem = SettingsConfigItem::get();
755 pItem->setValue( "PrintDialog",
756 "LastPrinterUsed",
757 GetName()
758 );
759 }
760
761 return true;
762}
763
764PrinterController::~PrinterController()
765{
766}
767
768css::view::PrintableState PrinterController::getJobState() const
769{
770 return mpImplData->meJobState;
771}
772
773void PrinterController::setJobState( css::view::PrintableState i_eState )
774{
775 mpImplData->meJobState = i_eState;
776}
777
778const VclPtr<Printer>& PrinterController::getPrinter() const
779{
780 return mpImplData->mxPrinter;
781}
782
783weld::Window* PrinterController::getWindow() const
784{
785 return mpImplData->mpWindow;
786}
787
788void PrinterController::setPrinter( const VclPtr<Printer>& i_rPrinter )
789{
790 VclPtr<Printer> xPrinter = mpImplData->mxPrinter;
791
792 Size aPaperSize; // Save current paper size
793 Orientation eOrientation = Orientation::Portrait; // Save current paper orientation
794 bool bSavedSizeOrientation = false;
795
796 // #tdf 126744 Transfer paper size and orientation settings to newly selected printer
797 if ( xPrinter )
798 {
799 aPaperSize = xPrinter->GetPaperSize();
800 eOrientation = xPrinter->GetOrientation();
801 bSavedSizeOrientation = true;
802 }
803
804 mpImplData->mxPrinter = i_rPrinter;
805 setValue( "Name",
806 css::uno::makeAny( i_rPrinter->GetName() ) );
807 mpImplData->mnDefaultPaperBin = mpImplData->mxPrinter->GetPaperBin();
808 mpImplData->mxPrinter->Push();
809 mpImplData->mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
810 mpImplData->maDefaultPageSize = mpImplData->mxPrinter->GetPaperSize();
811
812 if ( bSavedSizeOrientation )
813 {
814 mpImplData->mxPrinter->SetPaperSizeUser(aPaperSize);
815 mpImplData->mxPrinter->SetOrientation(eOrientation);
816 }
817
818 mpImplData->mbPapersizeFromUser = false;
819 mpImplData->mxPrinter->Pop();
820 mpImplData->mnFixedPaperBin = -1;
821}
822
823void PrinterController::resetPrinterOptions( bool i_bFileOutput )
824{
825 PrinterOptions aOpt;
826 aOpt.ReadFromConfig( i_bFileOutput );
827 mpImplData->mxPrinter->SetPrinterOptions( aOpt );
828}
829
830void PrinterController::setupPrinter( weld::Window* i_pParent )
831{
832 bool bRet = false;
833
834 // Important to hold printer alive while doing setup etc.
835 VclPtr< Printer > xPrinter = mpImplData->mxPrinter;
1
Calling implicit copy constructor for 'VclPtr<Printer>'
2
Calling copy constructor for 'Reference<Printer>'
5
Returning from copy constructor for 'Reference<Printer>'
6
Returning from copy constructor for 'VclPtr<Printer>'
836
837 if( !xPrinter )
7
Taking false branch
838 return;
839
840 xPrinter->Push();
841 xPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
842
843 // get current data
844 Size aPaperSize(xPrinter->GetPaperSize());
845 Orientation eOrientation = xPrinter->GetOrientation();
846 sal_uInt16 nPaperBin = xPrinter->GetPaperBin();
847
848 // reset paper size back to last configured size, not
849 // whatever happens to be the current page
850 // (but only if the printer config has changed, otherwise
851 // don't override printer page auto-detection - tdf#91362)
852 if (getPrinterModified() || getPapersizeFromSetup())
8
Assuming the condition is false
9
Assuming the condition is false
10
Taking false branch
853 {
854 resetPaperToLastConfigured();
855 }
856
857 // call driver setup
858 bRet = xPrinter->Setup( i_pParent, PrinterSetupMode::SingleJob );
859 SAL_WARN_IF(xPrinter != mpImplData->mxPrinter, "vcl.gdi",do { if (true && (xPrinter != mpImplData->mxPrinter
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Printer changed underneath us during setup"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Printer changed underneath us during setup"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer changed underneath us during setup"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer changed underneath us during setup") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Printer changed underneath us during setup"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer changed underneath us during setup"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
11
Taking false branch
12
Loop condition is false. Exiting loop
860 "Printer changed underneath us during setup")do { if (true && (xPrinter != mpImplData->mxPrinter
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Printer changed underneath us during setup"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Printer changed underneath us during setup"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer changed underneath us during setup"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer changed underneath us during setup") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Printer changed underneath us during setup"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer changed underneath us during setup"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "860" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
861 xPrinter = mpImplData->mxPrinter;
13
Calling implicit copy assignment operator for 'VclPtr<Printer>'
14
Calling copy assignment operator for 'Reference<Printer>'
24
Returning; memory was released
25
Returning; memory was released
862
863 Size aNewPaperSize(xPrinter->GetPaperSize());
26
Calling 'VclPtr::operator->'
864 if (bRet)
865 {
866 bool bInvalidateCache = false;
867 setPapersizeFromSetup(xPrinter->GetPrinterSettingsPreferred());
868
869 // was papersize overridden ? if so we need to take action if we're
870 // configured to use the driver papersize
871 if (aNewPaperSize != mpImplData->maDefaultPageSize)
872 {
873 mpImplData->maDefaultPageSize = aNewPaperSize;
874 bInvalidateCache = getPapersizeFromSetup();
875 }
876
877 // was bin overridden ? if so we need to take action
878 sal_uInt16 nNewPaperBin = xPrinter->GetPaperBin();
879 if (nNewPaperBin != nPaperBin)
880 {
881 mpImplData->mnFixedPaperBin = nNewPaperBin;
882 bInvalidateCache = true;
883 }
884
885 if (bInvalidateCache)
886 {
887 mpImplData->maPageCache.invalidate();
888 }
889 }
890 else
891 {
892 //restore to whatever it was before we entered this method
893 xPrinter->SetOrientation( eOrientation );
894 if (aPaperSize != aNewPaperSize)
895 xPrinter->SetPaperSizeUser(aPaperSize);
896 }
897 xPrinter->Pop();
898}
899
900PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const css::uno::Sequence< css::beans::PropertyValue >& i_rProps )
901{
902 PrinterController::PageSize aPageSize;
903 aPageSize.aSize = mxPrinter->GetPaperSize();
904 css::awt::Size aSetSize, aIsSize;
905 sal_Int32 nPaperBin = mnDefaultPaperBin;
906 for( const auto& rProp : i_rProps )
907 {
908 if ( rProp.Name == "PreferredPageSize" )
909 {
910 rProp.Value >>= aSetSize;
911 }
912 else if ( rProp.Name == "PageSize" )
913 {
914 rProp.Value >>= aIsSize;
915 }
916 else if ( rProp.Name == "PageIncludesNonprintableArea" )
917 {
918 bool bVal = false;
919 rProp.Value >>= bVal;
920 aPageSize.bFullPaper = bVal;
921 }
922 else if ( rProp.Name == "PrinterPaperTray" )
923 {
924 sal_Int32 nBin = -1;
925 rProp.Value >>= nBin;
926 if( nBin >= 0 && nBin < static_cast<sal_Int32>(mxPrinter->GetPaperBinCount()) )
927 nPaperBin = nBin;
928 }
929 }
930
931 Size aCurSize( mxPrinter->GetPaperSize() );
932 if( aSetSize.Width && aSetSize.Height )
933 {
934 Size aSetPaperSize( aSetSize.Width, aSetSize.Height );
935 Size aRealPaperSize( getRealPaperSize( aSetPaperSize, true/*bNoNUP*/ ) );
936 if( aRealPaperSize != aCurSize )
937 aIsSize = aSetSize;
938 }
939
940 if( aIsSize.Width && aIsSize.Height )
941 {
942 aPageSize.aSize.setWidth( aIsSize.Width );
943 aPageSize.aSize.setHeight( aIsSize.Height );
944
945 Size aRealPaperSize( getRealPaperSize( aPageSize.aSize, true/*bNoNUP*/ ) );
946 if( aRealPaperSize != aCurSize )
947 mxPrinter->SetPaperSizeUser( aRealPaperSize );
948 }
949
950 // paper bin set from properties in print dialog overrides
951 // application default for a page
952 if ( mnFixedPaperBin != -1 )
953 nPaperBin = mnFixedPaperBin;
954
955 if( nPaperBin != -1 && nPaperBin != mxPrinter->GetPaperBin() )
956 mxPrinter->SetPaperBin( nPaperBin );
957
958 return aPageSize;
959}
960
961//fdo#61886
962
963//when printing is finished, set the paper size of the printer to either what
964//the user explicitly set as the desired paper size, or fallback to whatever
965//the printer had before printing started. That way it doesn't contain the last
966//paper size of a multiple paper size using document when we are in our normal
967//auto accept document paper size mode and end up overwriting the original
968//paper size setting for file->printer_settings just by pressing "ok" in the
969//print dialog
970void vcl::ImplPrinterControllerData::resetPaperToLastConfigured()
971{
972 mxPrinter->Push();
973 mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
974 Size aCurSize(mxPrinter->GetPaperSize());
975 if (aCurSize != maDefaultPageSize)
976 mxPrinter->SetPaperSizeUser(maDefaultPageSize);
977 mxPrinter->Pop();
978}
979
980int PrinterController::getPageCountProtected() const
981{
982 const MapMode aMapMode( MapUnit::Map100thMM );
983
984 mpImplData->mxPrinter->Push();
985 mpImplData->mxPrinter->SetMapMode( aMapMode );
986 int nPages = getPageCount();
987 mpImplData->mxPrinter->Pop();
988 return nPages;
989}
990
991css::uno::Sequence< css::beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const
992{
993 const MapMode aMapMode( MapUnit::Map100thMM );
994
995 mpImplData->mxPrinter->Push();
996 mpImplData->mxPrinter->SetMapMode( aMapMode );
997 css::uno::Sequence< css::beans::PropertyValue > aResult( getPageParameters( i_nPage ) );
998 mpImplData->mxPrinter->Pop();
999 return aResult;
1000}
1001
1002PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
1003{
1004 // update progress if necessary
1005 if( mpImplData->mxProgress )
1006 {
1007 // do nothing if printing is canceled
1008 if( mpImplData->mxProgress->isCanceled() )
1009 return PrinterController::PageSize();
1010 mpImplData->mxProgress->tick();
1011 Application::Reschedule( true );
1012 }
1013
1014 if( i_bMayUseCache )
1015 {
1016 PrinterController::PageSize aPageSize;
1017 if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) )
1018 {
1019 return aPageSize;
1020 }
1021 }
1022 else
1023 mpImplData->maPageCache.invalidate();
1024
1025 o_rMtf.Clear();
1026
1027 // get page parameters
1028 css::uno::Sequence< css::beans::PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) );
1029 const MapMode aMapMode( MapUnit::Map100thMM );
1030
1031 mpImplData->mxPrinter->Push();
1032 mpImplData->mxPrinter->SetMapMode( aMapMode );
1033
1034 // modify job setup if necessary
1035 PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm );
1036
1037 o_rMtf.SetPrefSize( aPageSize.aSize );
1038 o_rMtf.SetPrefMapMode( aMapMode );
1039
1040 mpImplData->mxPrinter->EnableOutput( false );
1041
1042 o_rMtf.Record( mpImplData->mxPrinter.get() );
1043
1044 printPage( i_nUnfilteredPage );
1045
1046 o_rMtf.Stop();
1047 o_rMtf.WindStart();
1048 mpImplData->mxPrinter->Pop();
1049
1050 if( i_bMayUseCache )
1051 mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize );
1052
1053 // reset "FirstPage" property to false now we've gotten at least our first one
1054 mpImplData->mbFirstPage = false;
1055
1056 return aPageSize;
1057}
1058
1059static void appendSubPage( GDIMetaFile& o_rMtf, const tools::Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder )
1060{
1061 // intersect all clipregion actions with our clip rect
1062 io_rSubPage.WindStart();
1063 io_rSubPage.Clip( i_rClipRect );
1064
1065 // save gstate
1066 o_rMtf.AddAction( new MetaPushAction( PushFlags::ALL ) );
1067
1068 // clip to page rect
1069 o_rMtf.AddAction( new MetaClipRegionAction( vcl::Region( i_rClipRect ), true ) );
1070
1071 // append the subpage
1072 io_rSubPage.WindStart();
1073 io_rSubPage.Play( o_rMtf );
1074
1075 // restore gstate
1076 o_rMtf.AddAction( new MetaPopAction() );
1077
1078 // draw a border
1079 if( !i_bDrawBorder )
1080 return;
1081
1082 // save gstate
1083 o_rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR | PushFlags::FILLCOLOR | PushFlags::CLIPREGION | PushFlags::MAPMODE ) );
1084 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MapUnit::Map100thMM ) ) );
1085
1086 tools::Rectangle aBorderRect( i_rClipRect );
1087 o_rMtf.AddAction( new MetaLineColorAction( COL_BLACK, true ) );
1088 o_rMtf.AddAction( new MetaFillColorAction( COL_TRANSPARENT, false ) );
1089 o_rMtf.AddAction( new MetaRectAction( aBorderRect ) );
1090
1091 // restore gstate
1092 o_rMtf.AddAction( new MetaPopAction() );
1093}
1094
1095PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
1096{
1097 const MultiPageSetup& rMPS( mpImplData->maMultiPage );
1098 int nSubPages = rMPS.nRows * rMPS.nColumns;
1099 if( nSubPages < 1 )
1100 nSubPages = 1;
1101
1102 // reverse sheet order
1103 if( mpImplData->mbReversePageOrder )
1104 {
1105 int nDocPages = getFilteredPageCount();
1106 i_nFilteredPage = nDocPages - 1 - i_nFilteredPage;
1107 }
1108
1109 // there is no filtering to be done (and possibly the page size of the
1110 // original page is to be set), when N-Up is "neutral" that is there is
1111 // only one subpage and the margins are 0
1112 if( nSubPages == 1 &&
1113 rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 &&
1114 rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 )
1115 {
1116 PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache );
1117 if (mpImplData->meJobState != css::view::PrintableState_JOB_STARTED)
1118 { // rhbz#657394: check that we are still printing...
1119 return PrinterController::PageSize();
1120 }
1121 Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize, true );
1122 mpImplData->mxPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) );
1123 mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize );
1124 if( aPaperSize != aPageSize.aSize )
1125 {
1126 // user overridden page size, center Metafile
1127 o_rMtf.WindStart();
1128 long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2;
1129 long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2;
1130 o_rMtf.Move( nDX, nDY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1131 o_rMtf.WindStart();
1132 o_rMtf.SetPrefSize( aPaperSize );
1133 aPageSize.aSize = aPaperSize;
1134 }
1135 return aPageSize;
1136 }
1137
1138 // set last page property really only on the very last page to be rendered
1139 // that is on the last subpage of a NUp run
1140 bool bIsLastPage = mpImplData->mbLastPage;
1141 mpImplData->mbLastPage = false;
1142
1143 Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize, false ) );
1144
1145 // multi page area: page size minus margins + one time spacing right and down
1146 // the added spacing is so each subpage can be calculated including its spacing
1147 Size aMPArea( aPaperSize );
1148 aMPArea.AdjustWidth( -(rMPS.nLeftMargin + rMPS.nRightMargin) );
1149 aMPArea.AdjustWidth(rMPS.nHorizontalSpacing );
1150 aMPArea.AdjustHeight( -(rMPS.nTopMargin + rMPS.nBottomMargin) );
1151 aMPArea.AdjustHeight(rMPS.nVerticalSpacing );
1152
1153 // determine offsets
1154 long nAdvX = aMPArea.Width() / rMPS.nColumns;
1155 long nAdvY = aMPArea.Height() / rMPS.nRows;
1156
1157 // determine size of a "cell" subpage, leave a little space around pages
1158 Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing );
1159
1160 o_rMtf.Clear();
1161 o_rMtf.SetPrefSize( aPaperSize );
1162 o_rMtf.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
1163 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MapUnit::Map100thMM ) ) );
1164
1165 int nDocPages = getPageCountProtected();
1166 if (mpImplData->meJobState != css::view::PrintableState_JOB_STARTED)
1167 { // rhbz#657394: check that we are still printing...
1168 return PrinterController::PageSize();
1169 }
1170 for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ )
1171 {
1172 // map current sub page to real page
1173 int nPage = i_nFilteredPage * nSubPages + nSubPage;
1174 if( nSubPage == nSubPages-1 ||
1175 nPage == nDocPages-1 )
1176 {
1177 mpImplData->mbLastPage = bIsLastPage;
1178 }
1179 if( nPage >= 0 && nPage < nDocPages )
1180 {
1181 GDIMetaFile aPageFile;
1182 PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache );
1183 if( aPageSize.aSize.Width() && aPageSize.aSize.Height() )
1184 {
1185 long nCellX = 0, nCellY = 0;
1186 switch( rMPS.nOrder )
1187 {
1188 case NupOrderType::LRTB:
1189 nCellX = (nSubPage % rMPS.nColumns);
1190 nCellY = (nSubPage / rMPS.nColumns);
1191 break;
1192 case NupOrderType::TBLR:
1193 nCellX = (nSubPage / rMPS.nRows);
1194 nCellY = (nSubPage % rMPS.nRows);
1195 break;
1196 case NupOrderType::RLTB:
1197 nCellX = rMPS.nColumns - 1 - (nSubPage % rMPS.nColumns);
1198 nCellY = (nSubPage / rMPS.nColumns);
1199 break;
1200 case NupOrderType::TBRL:
1201 nCellX = rMPS.nColumns - 1 - (nSubPage / rMPS.nRows);
1202 nCellY = (nSubPage % rMPS.nRows);
1203 break;
1204 }
1205 // scale the metafile down to a sub page size
1206 double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width());
1207 double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height());
1208 double fScale = std::min( fScaleX, fScaleY );
1209 aPageFile.Scale( fScale, fScale );
1210 aPageFile.WindStart();
1211
1212 // move the subpage so it is centered in its "cell"
1213 long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2;
1214 long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2;
1215 long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX;
1216 long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY;
1217 aPageFile.Move( nX, nY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1218 aPageFile.WindStart();
1219 // calculate border rectangle
1220 tools::Rectangle aSubPageRect( Point( nX, nY ),
1221 Size( long(double(aPageSize.aSize.Width())*fScale),
1222 long(double(aPageSize.aSize.Height())*fScale) ) );
1223
1224 // append subpage to page
1225 appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder );
1226 }
1227 }
1228 }
1229 o_rMtf.WindStart();
1230
1231 // subsequent getPageFile calls have changed the paper, reset it to current value
1232 mpImplData->mxPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) );
1233 mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize );
1234
1235 return PrinterController::PageSize( aPaperSize, true );
1236}
1237
1238int PrinterController::getFilteredPageCount() const
1239{
1240 int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns;
1241 if( nDiv < 1 )
1242 nDiv = 1;
1243 return (getPageCountProtected() + (nDiv-1)) / nDiv;
1244}
1245
1246DrawModeFlags PrinterController::removeTransparencies( GDIMetaFile const & i_rIn, GDIMetaFile& o_rOut )
1247{
1248 DrawModeFlags nRestoreDrawMode = mpImplData->mxPrinter->GetDrawMode();
1249 sal_Int32 nMaxBmpDPIX = mpImplData->mxPrinter->GetDPIX();
1250 sal_Int32 nMaxBmpDPIY = mpImplData->mxPrinter->GetDPIY();
1251
1252 const PrinterOptions& rPrinterOptions = mpImplData->mxPrinter->GetPrinterOptions();
1253
1254 static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300;
1255 static const sal_Int32 NORMAL_BMP_RESOLUTION = 200;
1256
1257 if( rPrinterOptions.IsReduceBitmaps() )
1258 {
1259 // calculate maximum resolution for bitmap graphics
1260 if( PrinterBitmapMode::Optimal == rPrinterOptions.GetReducedBitmapMode() )
1261 {
1262 nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1263 nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1264 }
1265 else if( PrinterBitmapMode::Normal == rPrinterOptions.GetReducedBitmapMode() )
1266 {
1267 nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1268 nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1269 }
1270 else
1271 {
1272 nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX );
1273 nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY );
1274 }
1275 }
1276
1277 // convert to greyscales
1278 if( rPrinterOptions.IsConvertToGreyscales() )
1279 {
1280 mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() |
1281 ( DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText |
1282 DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient ) );
1283 }
1284
1285 // disable transparency output
1286 if( rPrinterOptions.IsReduceTransparency() && ( PrinterTransparencyMode::NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
1287 {
1288 mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() | DrawModeFlags::NoTransparency );
1289 }
1290
1291 Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic
1292 if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 )
1293 {
1294 // in N-Up printing we have no "page" background operation
1295 // we also have no way to determine the paper color
1296 // so let's go for white, which will kill 99.9% of the real cases
1297 aBg = COL_WHITE;
1298 }
1299 mpImplData->mxPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY,
1300 rPrinterOptions.IsReduceTransparency(),
1301 rPrinterOptions.GetReducedTransparencyMode() == PrinterTransparencyMode::Auto,
1302 rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(),
1303 aBg
1304 );
1305 return nRestoreDrawMode;
1306}
1307
1308void PrinterController::printFilteredPage( int i_nPage )
1309{
1310 if( mpImplData->meJobState != css::view::PrintableState_JOB_STARTED )
1311 return; // rhbz#657394: check that we are still printing...
1312
1313 GDIMetaFile aPageFile;
1314 PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile );
1315
1316 if( mpImplData->mxProgress )
1317 {
1318 // do nothing if printing is canceled
1319 if( mpImplData->mxProgress->isCanceled() )
1320 {
1321 setJobState( css::view::PrintableState_JOB_ABORTED );
1322 return;
1323 }
1324 }
1325
1326 // in N-Up printing set the correct page size
1327 mpImplData->mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
1328 // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile()
1329 mpImplData->mxPrinter->SetPaperSizeUser( aPageSize.aSize );
1330 if( mpImplData->mnFixedPaperBin != -1 &&
1331 mpImplData->mxPrinter->GetPaperBin() != mpImplData->mnFixedPaperBin )
1332 {
1333 mpImplData->mxPrinter->SetPaperBin( mpImplData->mnFixedPaperBin );
1334 }
1335
1336 // if full paper is meant to be used, move the output to accommodate for pageoffset
1337 if( aPageSize.bFullPaper )
1338 {
1339 Point aPageOffset( mpImplData->mxPrinter->GetPageOffset() );
1340 aPageFile.WindStart();
1341 aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y(), mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1342 }
1343
1344 GDIMetaFile aCleanedFile;
1345 DrawModeFlags nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile );
1346
1347 mpImplData->mxPrinter->EnableOutput();
1348
1349 // actually print the page
1350 mpImplData->mxPrinter->ImplStartPage();
1351
1352 mpImplData->mxPrinter->Push();
1353 aCleanedFile.WindStart();
1354 aCleanedFile.Play( mpImplData->mxPrinter.get() );
1355 mpImplData->mxPrinter->Pop();
1356
1357 mpImplData->mxPrinter->ImplEndPage();
1358
1359 mpImplData->mxPrinter->SetDrawMode( nRestoreDrawMode );
1360}
1361
1362void PrinterController::jobStarted()
1363{
1364}
1365
1366void PrinterController::jobFinished( css::view::PrintableState )
1367{
1368}
1369
1370void PrinterController::abortJob()
1371{
1372 setJobState( css::view::PrintableState_JOB_ABORTED );
1373 // applications (well, sw) depend on a page request with "IsLastPage" = true
1374 // to free resources, else they (well, sw) will crash eventually
1375 setLastPage( true );
1376
1377 if (mpImplData->mxProgress)
1378 {
1379 mpImplData->mxProgress->response(RET_CANCEL);
1380 mpImplData->mxProgress.reset();
1381 }
1382
1383 GDIMetaFile aMtf;
1384 getPageFile( 0, aMtf );
1385}
1386
1387void PrinterController::setLastPage( bool i_bLastPage )
1388{
1389 mpImplData->mbLastPage = i_bLastPage;
1390}
1391
1392void PrinterController::setReversePrint( bool i_bReverse )
1393{
1394 mpImplData->mbReversePageOrder = i_bReverse;
1395}
1396
1397void PrinterController::setPapersizeFromSetup( bool i_bPapersizeFromSetup )
1398{
1399 mpImplData->mbPapersizeFromSetup = i_bPapersizeFromSetup;
1400 mpImplData->mxPrinter->SetPrinterSettingsPreferred( i_bPapersizeFromSetup );
1401 if ( i_bPapersizeFromSetup )
1402 mpImplData->mbPapersizeFromUser = !i_bPapersizeFromSetup;
1403}
1404
1405bool PrinterController::getPapersizeFromSetup() const
1406{
1407 return mpImplData->mbPapersizeFromSetup;
1408}
1409
1410Size& PrinterController::getPaperSizeSetup() const
1411{
1412 return mpImplData->maDefaultPageSize;
1413}
1414
1415void PrinterController::setPaperSizeFromUser( Size i_aUserSize )
1416{
1417 mpImplData->mbPapersizeFromUser = true;
1418 mpImplData->mbPapersizeFromSetup = false;
1419 mpImplData->mxPrinter->SetPrinterSettingsPreferred( false );
1420
1421 mpImplData->maUserPageSize = i_aUserSize;
1422}
1423
1424Size& PrinterController::getPaperSizeFromUser() const
1425{
1426 return mpImplData->maUserPageSize;
1427}
1428
1429bool PrinterController::isPaperSizeFromUser() const
1430{
1431 return mpImplData->mbPapersizeFromUser;
1432}
1433
1434void PrinterController::setPrinterModified( bool i_bPrinterModified )
1435{
1436 mpImplData->mbPrinterModified = i_bPrinterModified;
1437}
1438
1439bool PrinterController::getPrinterModified() const
1440{
1441 return mpImplData->mbPrinterModified;
1442}
1443
1444css::uno::Sequence< css::beans::PropertyValue > PrinterController::getJobProperties( const css::uno::Sequence< css::beans::PropertyValue >& i_rMergeList ) const
1445{
1446 std::unordered_set< OUString > aMergeSet;
1447 size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3;
1448 for( const auto& rPropVal : i_rMergeList )
1449 aMergeSet.insert( rPropVal.Name );
1450
1451 css::uno::Sequence< css::beans::PropertyValue > aResult( nResultLen );
1452 std::copy(i_rMergeList.begin(), i_rMergeList.end(), aResult.begin());
1453 int nCur = i_rMergeList.getLength();
1454 for(const css::beans::PropertyValue & rPropVal : mpImplData->maUIProperties)
1455 {
1456 if( aMergeSet.find( rPropVal.Name ) == aMergeSet.end() )
1457 aResult[nCur++] = rPropVal;
1458 }
1459 // append IsFirstPage
1460 if( aMergeSet.find( "IsFirstPage" ) == aMergeSet.end() )
1461 {
1462 css::beans::PropertyValue aVal;
1463 aVal.Name = "IsFirstPage";
1464 aVal.Value <<= mpImplData->mbFirstPage;
1465 aResult[nCur++] = aVal;
1466 }
1467 // append IsLastPage
1468 if( aMergeSet.find( "IsLastPage" ) == aMergeSet.end() )
1469 {
1470 css::beans::PropertyValue aVal;
1471 aVal.Name = "IsLastPage";
1472 aVal.Value <<= mpImplData->mbLastPage;
1473 aResult[nCur++] = aVal;
1474 }
1475 // append IsPrinter
1476 if( aMergeSet.find( "IsPrinter" ) == aMergeSet.end() )
1477 {
1478 css::beans::PropertyValue aVal;
1479 aVal.Name = "IsPrinter";
1480 aVal.Value <<= true;
1481 aResult[nCur++] = aVal;
1482 }
1483 aResult.realloc( nCur );
1484 return aResult;
1485}
1486
1487const css::uno::Sequence< css::beans::PropertyValue >& PrinterController::getUIOptions() const
1488{
1489 return mpImplData->maUIOptions;
1490}
1491
1492css::beans::PropertyValue* PrinterController::getValue( const OUString& i_rProperty )
1493{
1494 std::unordered_map< OUString, size_t >::const_iterator it =
1495 mpImplData->maPropertyToIndex.find( i_rProperty );
1496 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : nullptr;
1497}
1498
1499const css::beans::PropertyValue* PrinterController::getValue( const OUString& i_rProperty ) const
1500{
1501 std::unordered_map< OUString, size_t >::const_iterator it =
1502 mpImplData->maPropertyToIndex.find( i_rProperty );
1503 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : nullptr;
1504}
1505
1506void PrinterController::setValue( const OUString& i_rPropertyName, const css::uno::Any& i_rValue )
1507{
1508 css::beans::PropertyValue aVal;
1509 aVal.Name = i_rPropertyName;
1510 aVal.Value = i_rValue;
1511
1512 setValue( aVal );
1513}
1514
1515void PrinterController::setValue( const css::beans::PropertyValue& i_rPropertyValue )
1516{
1517 std::unordered_map< OUString, size_t >::const_iterator it =
1518 mpImplData->maPropertyToIndex.find( i_rPropertyValue.Name );
1519 if( it != mpImplData->maPropertyToIndex.end() )
1520 mpImplData->maUIProperties[ it->second ] = i_rPropertyValue;
1521 else
1522 {
1523 // insert correct index into property map
1524 mpImplData->maPropertyToIndex[ i_rPropertyValue.Name ] = mpImplData->maUIProperties.size();
1525 mpImplData->maUIProperties.push_back( i_rPropertyValue );
1526 mpImplData->maUIPropertyEnabled.push_back( true );
1527 }
1528}
1529
1530void PrinterController::setUIOptions( const css::uno::Sequence< css::beans::PropertyValue >& i_rOptions )
1531{
1532 SAL_WARN_IF( mpImplData->maUIOptions.hasElements(), "vcl.gdi", "setUIOptions called twice !" )do { if (true && (mpImplData->maUIOptions.hasElements
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "setUIOptions called twice !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1532" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "setUIOptions called twice !"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "setUIOptions called twice !"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1532" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "setUIOptions called twice !") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1532" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "setUIOptions called twice !"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "setUIOptions called twice !"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1532" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1533
1534 mpImplData->maUIOptions = i_rOptions;
1535
1536 for( const auto& rOpt : i_rOptions )
1537 {
1538 css::uno::Sequence< css::beans::PropertyValue > aOptProp;
1539 rOpt.Value >>= aOptProp;
1540 bool bIsEnabled = true;
1541 bool bHaveProperty = false;
1542 OUString aPropName;
1543 vcl::ImplPrinterControllerData::ControlDependency aDep;
1544 css::uno::Sequence< sal_Bool > aChoicesDisabled;
1545 for( const css::beans::PropertyValue& rEntry : std::as_const(aOptProp) )
1546 {
1547 if ( rEntry.Name == "Property" )
1548 {
1549 css::beans::PropertyValue aVal;
1550 rEntry.Value >>= aVal;
1551 DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name )do { if (true && (!(mpImplData->maPropertyToIndex.
find( aVal.Name ) == mpImplData->maPropertyToIndex.end()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1552" ": "), "%s", "duplicate property entry"); } } while
(false)
1552 == mpImplData->maPropertyToIndex.end(), "duplicate property entry" )do { if (true && (!(mpImplData->maPropertyToIndex.
find( aVal.Name ) == mpImplData->maPropertyToIndex.end()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1552" ": "), "%s", "duplicate property entry"); } } while
(false)
;
1553 setValue( aVal );
1554 aPropName = aVal.Name;
1555 bHaveProperty = true;
1556 }
1557 else if ( rEntry.Name == "Enabled" )
1558 {
1559 bool bValue = true;
1560 rEntry.Value >>= bValue;
1561 bIsEnabled = bValue;
1562 }
1563 else if ( rEntry.Name == "DependsOnName" )
1564 {
1565 rEntry.Value >>= aDep.maDependsOnName;
1566 }
1567 else if ( rEntry.Name == "DependsOnEntry" )
1568 {
1569 rEntry.Value >>= aDep.mnDependsOnEntry;
1570 }
1571 else if ( rEntry.Name == "ChoicesDisabled" )
1572 {
1573 rEntry.Value >>= aChoicesDisabled;
1574 }
1575 }
1576 if( bHaveProperty )
1577 {
1578 vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it =
1579 mpImplData->maPropertyToIndex.find( aPropName );
1580 // sanity check
1581 if( it != mpImplData->maPropertyToIndex.end() )
1582 {
1583 mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled;
1584 }
1585 if( !aDep.maDependsOnName.isEmpty() )
1586 mpImplData->maControlDependencies[ aPropName ] = aDep;
1587 if( aChoicesDisabled.hasElements() )
1588 mpImplData->maChoiceDisableMap[ aPropName ] = aChoicesDisabled;
1589 }
1590 }
1591}
1592
1593bool PrinterController::isUIOptionEnabled( const OUString& i_rProperty ) const
1594{
1595 bool bEnabled = false;
1596 std::unordered_map< OUString, size_t >::const_iterator prop_it =
1597 mpImplData->maPropertyToIndex.find( i_rProperty );
1598 if( prop_it != mpImplData->maPropertyToIndex.end() )
1599 {
1600 bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second];
1601
1602 if( bEnabled )
1603 {
1604 // check control dependencies
1605 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1606 mpImplData->maControlDependencies.find( i_rProperty );
1607 if( it != mpImplData->maControlDependencies.end() )
1608 {
1609 // check if the dependency is enabled
1610 // if the dependency is disabled, we are too
1611 bEnabled = isUIOptionEnabled( it->second.maDependsOnName );
1612
1613 if( bEnabled )
1614 {
1615 // does the dependency have the correct value ?
1616 const css::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName );
1617 OSL_ENSURE( pVal, "unknown property in dependency" )do { if (true && (!(pVal))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1617" ": "), "%s", "unknown property in dependency"); }
} while (false)
;
1618 if( pVal )
1619 {
1620 sal_Int32 nDepVal = 0;
1621 bool bDepVal = false;
1622 if( pVal->Value >>= nDepVal )
1623 {
1624 bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1);
1625 }
1626 else if( pVal->Value >>= bDepVal )
1627 {
1628 // could be a dependency on a checked boolean
1629 // in this case the dependency is on a non zero for checked value
1630 bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) ||
1631 ( ! bDepVal && it->second.mnDependsOnEntry == 0);
1632 }
1633 else
1634 {
1635 // if the type does not match something is awry
1636 OSL_FAIL( "strange type in control dependency" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1636" ": "), "%s", "strange type in control dependency"
); } } while (false)
;
1637 bEnabled = false;
1638 }
1639 }
1640 }
1641 }
1642 }
1643 }
1644 return bEnabled;
1645}
1646
1647bool PrinterController::isUIChoiceEnabled( const OUString& i_rProperty, sal_Int32 i_nValue ) const
1648{
1649 bool bEnabled = true;
1650 ImplPrinterControllerData::ChoiceDisableMap::const_iterator it =
1651 mpImplData->maChoiceDisableMap.find( i_rProperty );
1652 if(it != mpImplData->maChoiceDisableMap.end() )
1653 {
1654 const css::uno::Sequence< sal_Bool >& rDisabled( it->second );
1655 if( i_nValue >= 0 && i_nValue < rDisabled.getLength() )
1656 bEnabled = ! rDisabled[i_nValue];
1657 }
1658 return bEnabled;
1659}
1660
1661OUString PrinterController::makeEnabled( const OUString& i_rProperty )
1662{
1663 OUString aDependency;
1664
1665 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1666 mpImplData->maControlDependencies.find( i_rProperty );
1667 if( it != mpImplData->maControlDependencies.end() )
1668 {
1669 if( isUIOptionEnabled( it->second.maDependsOnName ) )
1670 {
1671 aDependency = it->second.maDependsOnName;
1672 const css::beans::PropertyValue* pVal = getValue( aDependency );
1673 OSL_ENSURE( pVal, "unknown property in dependency" )do { if (true && (!(pVal))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1673" ": "), "%s", "unknown property in dependency"); }
} while (false)
;
1674 if( pVal )
1675 {
1676 sal_Int32 nDepVal = 0;
1677 bool bDepVal = false;
1678 if( pVal->Value >>= nDepVal )
1679 {
1680 if( it->second.mnDependsOnEntry != -1 )
1681 {
1682 setValue( aDependency, css::uno::makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) );
1683 }
1684 }
1685 else if( pVal->Value >>= bDepVal )
1686 {
1687 setValue( aDependency, css::uno::makeAny( it->second.mnDependsOnEntry != 0 ) );
1688 }
1689 else
1690 {
1691 // if the type does not match something is awry
1692 OSL_FAIL( "strange type in control dependency" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1692" ": "), "%s", "strange type in control dependency"
); } } while (false)
;
1693 }
1694 }
1695 }
1696 }
1697
1698 return aDependency;
1699}
1700
1701void PrinterController::createProgressDialog()
1702{
1703 if (!mpImplData->mxProgress)
1704 {
1705 bool bShow = true;
1706 css::beans::PropertyValue* pMonitor = getValue( "MonitorVisible" );
1707 if( pMonitor )
1708 pMonitor->Value >>= bShow;
1709 else
1710 {
1711 const css::beans::PropertyValue* pVal = getValue( "IsApi" );
1712 if( pVal )
1713 {
1714 bool bApi = false;
1715 pVal->Value >>= bApi;
1716 bShow = ! bApi;
1717 }
1718 }
1719
1720 if( bShow && ! Application::IsHeadlessModeEnabled() )
1721 {
1722 mpImplData->mxProgress = std::make_shared<PrintProgressDialog>(getWindow(), getPageCountProtected());
1723 weld::DialogController::runAsync(mpImplData->mxProgress, [](sal_Int32 /*nResult*/){});
1724 }
1725 }
1726 else
1727 {
1728 mpImplData->mxProgress->response(RET_CANCEL);
1729 mpImplData->mxProgress.reset();
1730 }
1731}
1732
1733bool PrinterController::isProgressCanceled() const
1734{
1735 return mpImplData->mxProgress && mpImplData->mxProgress->isCanceled();
1736}
1737
1738void PrinterController::setMultipage( const MultiPageSetup& i_rMPS )
1739{
1740 mpImplData->maMultiPage = i_rMPS;
1741}
1742
1743const PrinterController::MultiPageSetup& PrinterController::getMultipage() const
1744{
1745 return mpImplData->maMultiPage;
1746}
1747
1748void PrinterController::resetPaperToLastConfigured()
1749{
1750 mpImplData->resetPaperToLastConfigured();
1751}
1752
1753void PrinterController::pushPropertiesToPrinter()
1754{
1755 sal_Int32 nCopyCount = 1;
1756 // set copycount and collate
1757 const css::beans::PropertyValue* pVal = getValue( "CopyCount" );
1758 if( pVal )
1759 pVal->Value >>= nCopyCount;
1760 bool bCollate = false;
1761 pVal = getValue( "Collate" );
1762 if( pVal )
1763 pVal->Value >>= bCollate;
1764 mpImplData->mxPrinter->SetCopyCount( static_cast<sal_uInt16>(nCopyCount), bCollate );
1765
1766 // duplex mode
1767 pVal = getValue( "DuplexMode" );
1768 if( pVal )
1769 {
1770 sal_Int16 nDuplex = css::view::DuplexMode::UNKNOWN;
1771 pVal->Value >>= nDuplex;
1772 switch( nDuplex )
1773 {
1774 case css::view::DuplexMode::OFF: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::Off ); break;
1775 case css::view::DuplexMode::LONGEDGE: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::LongEdge ); break;
1776 case css::view::DuplexMode::SHORTEDGE: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::ShortEdge ); break;
1777 }
1778 }
1779}
1780
1781bool PrinterController::isShowDialogs() const
1782{
1783 bool bApi = getBoolProperty( "IsApi", false );
1784 return ! bApi && ! Application::IsHeadlessModeEnabled();
1785}
1786
1787bool PrinterController::isDirectPrint() const
1788{
1789 bool bDirect = getBoolProperty( "IsDirect", false );
1790 return bDirect;
1791}
1792
1793bool PrinterController::getBoolProperty( const OUString& i_rProperty, bool i_bFallback ) const
1794{
1795 bool bRet = i_bFallback;
1796 const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1797 if( pVal )
1798 pVal->Value >>= bRet;
1799 return bRet;
1800}
1801
1802sal_Int32 PrinterController::getIntProperty( const OUString& i_rProperty, sal_Int32 i_nFallback ) const
1803{
1804 sal_Int32 nRet = i_nFallback;
1805 const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1806 if( pVal )
1807 pVal->Value >>= nRet;
1808 return nRet;
1809}
1810
1811/*
1812 * PrinterOptionsHelper
1813**/
1814css::uno::Any PrinterOptionsHelper::getValue( const OUString& i_rPropertyName ) const
1815{
1816 css::uno::Any aRet;
1817 std::unordered_map< OUString, css::uno::Any >::const_iterator it =
1818 m_aPropertyMap.find( i_rPropertyName );
1819 if( it != m_aPropertyMap.end() )
1820 aRet = it->second;
1821 return aRet;
1822}
1823
1824bool PrinterOptionsHelper::getBoolValue( const OUString& i_rPropertyName, bool i_bDefault ) const
1825{
1826 bool bRet = false;
1827 css::uno::Any aVal( getValue( i_rPropertyName ) );
1828 return (aVal >>= bRet) ? bRet : i_bDefault;
1829}
1830
1831sal_Int64 PrinterOptionsHelper::getIntValue( const OUString& i_rPropertyName, sal_Int64 i_nDefault ) const
1832{
1833 sal_Int64 nRet = 0;
1834 css::uno::Any aVal( getValue( i_rPropertyName ) );
1835 return (aVal >>= nRet) ? nRet : i_nDefault;
1836}
1837
1838OUString PrinterOptionsHelper::getStringValue( const OUString& i_rPropertyName ) const
1839{
1840 OUString aRet;
1841 css::uno::Any aVal( getValue( i_rPropertyName ) );
1842 return (aVal >>= aRet) ? aRet : OUString();
1843}
1844
1845bool PrinterOptionsHelper::processProperties( const css::uno::Sequence< css::beans::PropertyValue >& i_rNewProp )
1846{
1847 bool bChanged = false;
1848
1849 for( const auto& rVal : i_rNewProp )
1850 {
1851 std::unordered_map< OUString, css::uno::Any >::iterator it =
1852 m_aPropertyMap.find( rVal.Name );
1853
1854 bool bElementChanged = (it == m_aPropertyMap.end()) || (it->second != rVal.Value);
1855 if( bElementChanged )
1856 {
1857 m_aPropertyMap[ rVal.Name ] = rVal.Value;
1858 bChanged = true;
1859 }
1860 }
1861 return bChanged;
1862}
1863
1864void PrinterOptionsHelper::appendPrintUIOptions( css::uno::Sequence< css::beans::PropertyValue >& io_rProps ) const
1865{
1866 if( !m_aUIProperties.empty() )
1867 {
1868 sal_Int32 nIndex = io_rProps.getLength();
1869 io_rProps.realloc( nIndex+1 );
1870 css::beans::PropertyValue aVal;
1871 aVal.Name = "ExtraPrintUIOptions";
1872 aVal.Value <<= comphelper::containerToSequence(m_aUIProperties);
1873 io_rProps[ nIndex ] = aVal;
1874 }
1875}
1876
1877css::uno::Any PrinterOptionsHelper::setUIControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
1878 const OUString& i_rTitle,
1879 const css::uno::Sequence< OUString >& i_rHelpIds,
1880 const OUString& i_rType,
1881 const css::beans::PropertyValue* i_pVal,
1882 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1883{
1884 sal_Int32 nElements =
1885 2 // ControlType + ID
1886 + (i_rTitle.isEmpty() ? 0 : 1) // Text
1887 + (i_rHelpIds.hasElements() ? 1 : 0) // HelpId
1888 + (i_pVal ? 1 : 0) // Property
1889 + i_rControlOptions.maAddProps.size() // additional props
1890 + (i_rControlOptions.maGroupHint.isEmpty() ? 0 : 1) // grouping
1891 + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint
1892 + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled
1893 ;
1894 if( !i_rControlOptions.maDependsOnName.isEmpty() )
1895 {
1896 nElements += 1;
1897 if( i_rControlOptions.mnDependsOnEntry != -1 )
1898 nElements += 1;
1899 if( i_rControlOptions.mbAttachToDependency )
1900 nElements += 1;
1901 }
1902
1903 css::uno::Sequence< css::beans::PropertyValue > aCtrl( nElements );
1904 sal_Int32 nUsed = 0;
1905 if( !i_rTitle.isEmpty() )
1906 {
1907 aCtrl[nUsed ].Name = "Text";
1908 aCtrl[nUsed++].Value <<= i_rTitle;
1909 }
1910 if( i_rHelpIds.hasElements() )
1911 {
1912 aCtrl[nUsed ].Name = "HelpId";
1913 aCtrl[nUsed++].Value <<= i_rHelpIds;
1914 }
1915 aCtrl[nUsed ].Name = "ControlType";
1916 aCtrl[nUsed++].Value <<= i_rType;
1917 aCtrl[nUsed ].Name = "ID";
1918 aCtrl[nUsed++].Value <<= i_rIDs;
1919 if( i_pVal )
1920 {
1921 aCtrl[nUsed ].Name = "Property";
1922 aCtrl[nUsed++].Value <<= *i_pVal;
1923 }
1924 if( !i_rControlOptions.maDependsOnName.isEmpty() )
1925 {
1926 aCtrl[nUsed ].Name = "DependsOnName";
1927 aCtrl[nUsed++].Value <<= i_rControlOptions.maDependsOnName;
1928 if( i_rControlOptions.mnDependsOnEntry != -1 )
1929 {
1930 aCtrl[nUsed ].Name = "DependsOnEntry";
1931 aCtrl[nUsed++].Value <<= i_rControlOptions.mnDependsOnEntry;
1932 }
1933 if( i_rControlOptions.mbAttachToDependency )
1934 {
1935 aCtrl[nUsed ].Name = "AttachToDependency";
1936 aCtrl[nUsed++].Value <<= i_rControlOptions.mbAttachToDependency;
1937 }
1938 }
1939 if( !i_rControlOptions.maGroupHint.isEmpty() )
1940 {
1941 aCtrl[nUsed ].Name = "GroupingHint";
1942 aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint;
1943 }
1944 if( i_rControlOptions.mbInternalOnly )
1945 {
1946 aCtrl[nUsed ].Name = "InternalUIOnly";
1947 aCtrl[nUsed++].Value <<= true;
1948 }
1949 if( ! i_rControlOptions.mbEnabled )
1950 {
1951 aCtrl[nUsed ].Name = "Enabled";
1952 aCtrl[nUsed++].Value <<= false;
1953 }
1954
1955 sal_Int32 nAddProps = i_rControlOptions.maAddProps.size();
1956 for( sal_Int32 i = 0; i < nAddProps; i++ )
1957 aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i];
1958
1959 SAL_WARN_IF( nUsed != nElements, "vcl.gdi", "nUsed != nElements, probable heap corruption" )do { if (true && (nUsed != nElements)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "nUsed != nElements, probable heap corruption"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1959" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "nUsed != nElements, probable heap corruption"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "nUsed != nElements, probable heap corruption"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1959" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "nUsed != nElements, probable heap corruption") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1959" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "nUsed != nElements, probable heap corruption"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "nUsed != nElements, probable heap corruption"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print3.cxx"
":" "1959" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1960
1961 return css::uno::makeAny( aCtrl );
1962}
1963
1964css::uno::Any PrinterOptionsHelper::setGroupControlOpt(const OUString& i_rID,
1965 const OUString& i_rTitle,
1966 const OUString& i_rHelpId)
1967{
1968 css::uno::Sequence< OUString > aHelpId;
1969 if( !i_rHelpId.isEmpty() )
1970 {
1971 aHelpId.realloc( 1 );
1972 *aHelpId.getArray() = i_rHelpId;
1973 }
1974 css::uno::Sequence< OUString > aIds { i_rID };
1975 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Group");
1976}
1977
1978css::uno::Any PrinterOptionsHelper::setSubgroupControlOpt(const OUString& i_rID,
1979 const OUString& i_rTitle,
1980 const OUString& i_rHelpId,
1981 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1982{
1983 css::uno::Sequence< OUString > aHelpId;
1984 if( !i_rHelpId.isEmpty() )
1985 {
1986 aHelpId.realloc( 1 );
1987 *aHelpId.getArray() = i_rHelpId;
1988 }
1989 css::uno::Sequence< OUString > aIds { i_rID };
1990 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Subgroup", nullptr, i_rControlOptions);
1991}
1992
1993css::uno::Any PrinterOptionsHelper::setBoolControlOpt(const OUString& i_rID,
1994 const OUString& i_rTitle,
1995 const OUString& i_rHelpId,
1996 const OUString& i_rProperty,
1997 bool i_bValue,
1998 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1999{
2000 css::uno::Sequence< OUString > aHelpId;
2001 if( !i_rHelpId.isEmpty() )
2002 {
2003 aHelpId.realloc( 1 );
2004 *aHelpId.getArray() = i_rHelpId;
2005 }
2006 css::beans::PropertyValue aVal;
2007 aVal.Name = i_rProperty;
2008 aVal.Value <<= i_bValue;
2009 css::uno::Sequence< OUString > aIds { i_rID };
2010 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Bool", &aVal, i_rControlOptions);
2011}
2012
2013css::uno::Any PrinterOptionsHelper::setChoiceRadiosControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
2014 const OUString& i_rTitle,
2015 const css::uno::Sequence< OUString >& i_rHelpId,
2016 const OUString& i_rProperty,
2017 const css::uno::Sequence< OUString >& i_rChoices,
2018 sal_Int32 i_nValue,
2019 const css::uno::Sequence< sal_Bool >& i_rDisabledChoices,
2020 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2021{
2022 UIControlOptions aOpt( i_rControlOptions );
2023 sal_Int32 nUsed = aOpt.maAddProps.size();
2024 aOpt.maAddProps.resize( nUsed + 1 + (i_rDisabledChoices.hasElements() ? 1 : 0) );
2025 aOpt.maAddProps[nUsed].Name = "Choices";
2026 aOpt.maAddProps[nUsed].Value <<= i_rChoices;
2027 if( i_rDisabledChoices.hasElements() )
2028 {
2029 aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
2030 aOpt.maAddProps[nUsed+1].Value <<= i_rDisabledChoices;
2031 }
2032
2033 css::beans::PropertyValue aVal;
2034 aVal.Name = i_rProperty;
2035 aVal.Value <<= i_nValue;
2036 return setUIControlOpt(i_rIDs, i_rTitle, i_rHelpId, "Radio", &aVal, aOpt);
2037}
2038
2039css::uno::Any PrinterOptionsHelper::setChoiceListControlOpt(const OUString& i_rID,
2040 const OUString& i_rTitle,
2041 const css::uno::Sequence< OUString >& i_rHelpId,
2042 const OUString& i_rProperty,
2043 const css::uno::Sequence< OUString >& i_rChoices,
2044 sal_Int32 i_nValue,
2045 const css::uno::Sequence< sal_Bool >& i_rDisabledChoices,
2046 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2047{
2048 UIControlOptions aOpt( i_rControlOptions );
2049 sal_Int32 nUsed = aOpt.maAddProps.size();
2050 aOpt.maAddProps.resize( nUsed + 1 + (i_rDisabledChoices.hasElements() ? 1 : 0) );
2051 aOpt.maAddProps[nUsed].Name = "Choices";
2052 aOpt.maAddProps[nUsed].Value <<= i_rChoices;
2053 if( i_rDisabledChoices.hasElements() )
2054 {
2055 aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
2056 aOpt.maAddProps[nUsed+1].Value <<= i_rDisabledChoices;
2057 }
2058
2059 css::beans::PropertyValue aVal;
2060 aVal.Name = i_rProperty;
2061 aVal.Value <<= i_nValue;
2062 css::uno::Sequence< OUString > aIds { i_rID };
2063 return setUIControlOpt(aIds, i_rTitle, i_rHelpId, "List", &aVal, aOpt);
2064}
2065
2066css::uno::Any PrinterOptionsHelper::setRangeControlOpt(const OUString& i_rID,
2067 const OUString& i_rTitle,
2068 const OUString& i_rHelpId,
2069 const OUString& i_rProperty,
2070 sal_Int32 i_nValue,
2071 sal_Int32 i_nMinValue,
2072 sal_Int32 i_nMaxValue,
2073 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2074{
2075 UIControlOptions aOpt( i_rControlOptions );
2076 if( i_nMaxValue >= i_nMinValue )
2077 {
2078 sal_Int32 nUsed = aOpt.maAddProps.size();
2079 aOpt.maAddProps.resize( nUsed + 2 );
2080 aOpt.maAddProps[nUsed ].Name = "MinValue";
2081 aOpt.maAddProps[nUsed++].Value <<= i_nMinValue;
2082 aOpt.maAddProps[nUsed ].Name = "MaxValue";
2083 aOpt.maAddProps[nUsed++].Value <<= i_nMaxValue;
2084 }
2085
2086 css::uno::Sequence< OUString > aHelpId;
2087 if( !i_rHelpId.isEmpty() )
2088 {
2089 aHelpId.realloc( 1 );
2090 *aHelpId.getArray() = i_rHelpId;
2091 }
2092 css::beans::PropertyValue aVal;
2093 aVal.Name = i_rProperty;
2094 aVal.Value <<= i_nValue;
2095 css::uno::Sequence< OUString > aIds { i_rID };
2096 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Range", &aVal, aOpt);
2097}
2098
2099css::uno::Any PrinterOptionsHelper::setEditControlOpt(const OUString& i_rID,
2100 const OUString& i_rTitle,
2101 const OUString& i_rHelpId,
2102 const OUString& i_rProperty,
2103 const OUString& i_rValue,
2104 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2105{
2106 css::uno::Sequence< OUString > aHelpId;
2107 if( !i_rHelpId.isEmpty() )
2108 {
2109 aHelpId.realloc( 1 );
2110 *aHelpId.getArray() = i_rHelpId;
2111 }
2112 css::beans::PropertyValue aVal;
2113 aVal.Name = i_rProperty;
2114 aVal.Value <<= i_rValue;
2115 css::uno::Sequence< OUString > aIds { i_rID };
2116 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Edit", &aVal, i_rControlOptions);
2117}
2118
2119/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
3
Assuming field 'm_pBody' is non-null
4
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody
15.1
'pBody' is non-null
15.1
'pBody' is non-null
15.1
'pBody' is non-null
15.1
'pBody' is non-null
)
16
Taking true branch
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld
16.1
'pOld' is non-null
16.1
'pOld' is non-null
16.1
'pOld' is non-null
16.1
'pOld' is non-null
)
17
Taking true branch
127 pOld->release();
18
Calling 'VclReferenceBase::release'
22
Returning; memory was released
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
15
Calling 'Reference::set'
23
Returning; memory was released via 1st parameter
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
28
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
19
Assuming the condition is true
20
Taking true branch
40 delete this;
21
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
27
Calling 'Reference::get'
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */