File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 192, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
49 | using namespace vcl; | |||
50 | ||||
51 | namespace { | |||
52 | ||||
53 | class 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 | ||||
77 | public: | |||
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 | ||||
130 | class vcl::ImplPrinterControllerData | |||
131 | { | |||
132 | public: | |||
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 | ||||
226 | PrinterController::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 | ||||
233 | static 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 | ||||
277 | namespace { | |||
278 | ||||
279 | struct 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 | ||||
294 | IMPL_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 | ||||
302 | void 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 | ||||
319 | bool 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 | ||||
525 | bool 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 | ||||
535 | void Printer::FinishPrintJob(const std::shared_ptr<PrinterController>& xController) | |||
536 | { | |||
537 | xController->resetPaperToLastConfigured(); | |||
538 | xController->jobFinished( xController->getJobState() ); | |||
539 | } | |||
540 | ||||
541 | void 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 | ||||
551 | bool 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 | ||||
764 | PrinterController::~PrinterController() | |||
765 | { | |||
766 | } | |||
767 | ||||
768 | css::view::PrintableState PrinterController::getJobState() const | |||
769 | { | |||
770 | return mpImplData->meJobState; | |||
771 | } | |||
772 | ||||
773 | void PrinterController::setJobState( css::view::PrintableState i_eState ) | |||
774 | { | |||
775 | mpImplData->meJobState = i_eState; | |||
776 | } | |||
777 | ||||
778 | const VclPtr<Printer>& PrinterController::getPrinter() const | |||
779 | { | |||
780 | return mpImplData->mxPrinter; | |||
781 | } | |||
782 | ||||
783 | weld::Window* PrinterController::getWindow() const | |||
784 | { | |||
785 | return mpImplData->mpWindow; | |||
786 | } | |||
787 | ||||
788 | void 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 | ||||
823 | void PrinterController::resetPrinterOptions( bool i_bFileOutput ) | |||
824 | { | |||
825 | PrinterOptions aOpt; | |||
826 | aOpt.ReadFromConfig( i_bFileOutput ); | |||
827 | mpImplData->mxPrinter->SetPrinterOptions( aOpt ); | |||
828 | } | |||
829 | ||||
830 | void 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; | |||
| ||||
836 | ||||
837 | if( !xPrinter ) | |||
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()) | |||
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) | |||
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; | |||
862 | ||||
863 | Size aNewPaperSize(xPrinter->GetPaperSize()); | |||
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 | ||||
900 | PrinterController::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 | |||
970 | void 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 | ||||
980 | int 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 | ||||
991 | css::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 | ||||
1002 | PrinterController::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 | ||||
1059 | static 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 | ||||
1095 | PrinterController::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 | ||||
1238 | int 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 | ||||
1246 | DrawModeFlags 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 | ||||
1308 | void 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 | ||||
1362 | void PrinterController::jobStarted() | |||
1363 | { | |||
1364 | } | |||
1365 | ||||
1366 | void PrinterController::jobFinished( css::view::PrintableState ) | |||
1367 | { | |||
1368 | } | |||
1369 | ||||
1370 | void 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 | ||||
1387 | void PrinterController::setLastPage( bool i_bLastPage ) | |||
1388 | { | |||
1389 | mpImplData->mbLastPage = i_bLastPage; | |||
1390 | } | |||
1391 | ||||
1392 | void PrinterController::setReversePrint( bool i_bReverse ) | |||
1393 | { | |||
1394 | mpImplData->mbReversePageOrder = i_bReverse; | |||
1395 | } | |||
1396 | ||||
1397 | void 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 | ||||
1405 | bool PrinterController::getPapersizeFromSetup() const | |||
1406 | { | |||
1407 | return mpImplData->mbPapersizeFromSetup; | |||
1408 | } | |||
1409 | ||||
1410 | Size& PrinterController::getPaperSizeSetup() const | |||
1411 | { | |||
1412 | return mpImplData->maDefaultPageSize; | |||
1413 | } | |||
1414 | ||||
1415 | void 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 | ||||
1424 | Size& PrinterController::getPaperSizeFromUser() const | |||
1425 | { | |||
1426 | return mpImplData->maUserPageSize; | |||
1427 | } | |||
1428 | ||||
1429 | bool PrinterController::isPaperSizeFromUser() const | |||
1430 | { | |||
1431 | return mpImplData->mbPapersizeFromUser; | |||
1432 | } | |||
1433 | ||||
1434 | void PrinterController::setPrinterModified( bool i_bPrinterModified ) | |||
1435 | { | |||
1436 | mpImplData->mbPrinterModified = i_bPrinterModified; | |||
1437 | } | |||
1438 | ||||
1439 | bool PrinterController::getPrinterModified() const | |||
1440 | { | |||
1441 | return mpImplData->mbPrinterModified; | |||
1442 | } | |||
1443 | ||||
1444 | css::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 | ||||
1487 | const css::uno::Sequence< css::beans::PropertyValue >& PrinterController::getUIOptions() const | |||
1488 | { | |||
1489 | return mpImplData->maUIOptions; | |||
1490 | } | |||
1491 | ||||
1492 | css::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 | ||||
1499 | const 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 | ||||
1506 | void 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 | ||||
1515 | void 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 | ||||
1530 | void 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 | ||||
1593 | bool 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 | ||||
1647 | bool 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 | ||||
1661 | OUString 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 | ||||
1701 | void 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 | ||||
1733 | bool PrinterController::isProgressCanceled() const | |||
1734 | { | |||
1735 | return mpImplData->mxProgress && mpImplData->mxProgress->isCanceled(); | |||
1736 | } | |||
1737 | ||||
1738 | void PrinterController::setMultipage( const MultiPageSetup& i_rMPS ) | |||
1739 | { | |||
1740 | mpImplData->maMultiPage = i_rMPS; | |||
1741 | } | |||
1742 | ||||
1743 | const PrinterController::MultiPageSetup& PrinterController::getMultipage() const | |||
1744 | { | |||
1745 | return mpImplData->maMultiPage; | |||
1746 | } | |||
1747 | ||||
1748 | void PrinterController::resetPaperToLastConfigured() | |||
1749 | { | |||
1750 | mpImplData->resetPaperToLastConfigured(); | |||
1751 | } | |||
1752 | ||||
1753 | void 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 | ||||
1781 | bool PrinterController::isShowDialogs() const | |||
1782 | { | |||
1783 | bool bApi = getBoolProperty( "IsApi", false ); | |||
1784 | return ! bApi && ! Application::IsHeadlessModeEnabled(); | |||
1785 | } | |||
1786 | ||||
1787 | bool PrinterController::isDirectPrint() const | |||
1788 | { | |||
1789 | bool bDirect = getBoolProperty( "IsDirect", false ); | |||
1790 | return bDirect; | |||
1791 | } | |||
1792 | ||||
1793 | bool 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 | ||||
1802 | sal_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 | **/ | |||
1814 | css::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 | ||||
1824 | bool 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 | ||||
1831 | sal_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 | ||||
1838 | OUString 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 | ||||
1845 | bool 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 | ||||
1864 | void 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 | ||||
1877 | css::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 | ||||
1964 | css::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 | ||||
1978 | css::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 | ||||
1993 | css::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 | ||||
2013 | css::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 | ||||
2039 | css::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 | ||||
2066 | css::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 | ||||
2099 | css::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: */ |
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 | |||||||||
34 | namespace rtl | ||||||||
35 | { | ||||||||
36 | |||||||||
37 | /** Template reference class for reference type. | ||||||||
38 | */ | ||||||||
39 | template <class reference_type> | ||||||||
40 | class Reference | ||||||||
41 | { | ||||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||||
43 | */ | ||||||||
44 | reference_type * m_pBody; | ||||||||
45 | |||||||||
46 | |||||||||
47 | public: | ||||||||
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) | ||||||||
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
| ||||||||
123 | pBody->acquire(); | ||||||||
124 | reference_type * const pOld = m_pBody; | ||||||||
125 | m_pBody = pBody; | ||||||||
126 | if (pOld
| ||||||||
127 | pOld->release(); | ||||||||
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 ); | ||||||||
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; | ||||||||
| |||||||||
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 | ||||||||
277 | namespace 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 | */ | ||||||||
286 | template<typename T> | ||||||||
287 | struct 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: */ |
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 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
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) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |
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 | |
36 | class VclReferenceBase; |
37 | |
38 | namespace vcl::detail { |
39 | |
40 | template<typename> |
41 | constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; } |
42 | |
43 | template<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 | */ |
56 | template <class reference_type> |
57 | class 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 | |
66 | public: |
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(); |
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 | |
218 | template<typename T1, typename T2> |
219 | inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
220 | return p1.get() == p2.get(); |
221 | } |
222 | |
223 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2) |
224 | { |
225 | return p1.get() == p2; |
226 | } |
227 | |
228 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) { |
229 | return p1.get() == p2; |
230 | } |
231 | |
232 | template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2) |
233 | { |
234 | return p1 == p2.get(); |
235 | } |
236 | |
237 | template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) { |
238 | return p1 == p2.get(); |
239 | } |
240 | |
241 | template<typename T1, typename T2> |
242 | inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
243 | return !(p1 == p2); |
244 | } |
245 | |
246 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2) |
247 | { |
248 | return !(p1 == p2); |
249 | } |
250 | |
251 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) { |
252 | return !(p1 == p2); |
253 | } |
254 | |
255 | template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2) |
256 | { |
257 | return !(p1 == p2); |
258 | } |
259 | |
260 | template<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 | */ |
274 | template <class reference_type> |
275 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type> |
276 | { |
277 | public: |
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 | |
290 | template <class reference_type> |
291 | class ScopedVclPtr : public VclPtr<reference_type> |
292 | { |
293 | public: |
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 | |
378 | private: |
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 | |
387 | protected: |
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 |
406 | template <class reference_type> |
407 | class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type> |
408 | { |
409 | public: |
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 | |
421 | private: |
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: */ |