/src/libreoffice/vcl/unx/generic/print/genprnpsp.cxx
Line | Count | Source |
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 | | /** |
21 | | this file implements the sal printer interface (SalPrinter, SalInfoPrinter |
22 | | and some printer relevant methods of SalInstance and SalGraphicsData) |
23 | | |
24 | | as underlying library the printer features of psprint are used. |
25 | | |
26 | | The query methods of a SalInfoPrinter are implemented by querying psprint |
27 | | |
28 | | The job methods of a SalPrinter are implemented by calling psprint |
29 | | printer job functions. |
30 | | */ |
31 | | |
32 | | #include <sal/config.h> |
33 | | |
34 | | #include <string_view> |
35 | | |
36 | | // For spawning PDF and FAX generation |
37 | | |
38 | | #include <comphelper/fileurl.hxx> |
39 | | #include <o3tl/safeint.hxx> |
40 | | #include <o3tl/unit_conversion.hxx> |
41 | | #include <tools/mapunit.hxx> |
42 | | #include <rtl/ustrbuf.hxx> |
43 | | #include <rtl/ustring.hxx> |
44 | | #include <sal/log.hxx> |
45 | | #include <osl/diagnose.h> |
46 | | #include <osl/file.hxx> |
47 | | |
48 | | #include <utility> |
49 | | #include <vcl/gdimtf.hxx> |
50 | | #include <vcl/idle.hxx> |
51 | | #include <vcl/printer/Options.hxx> |
52 | | #include <vcl/print.hxx> |
53 | | #include <vcl/PrinterSupport.hxx> |
54 | | #include <vcl/QueueInfo.hxx> |
55 | | #include <vcl/pdfwriter.hxx> |
56 | | #include <vcl/svapp.hxx> |
57 | | #include <vcl/settings.hxx> |
58 | | #include <vcl/weld/Dialog.hxx> |
59 | | |
60 | | #include <strings.hrc> |
61 | | #include <unx/genprn.h> |
62 | | #include <unx/geninst.h> |
63 | | #include <unx/genpspgraphics.h> |
64 | | |
65 | | #include <jobset.h> |
66 | | #include <print.h> |
67 | | #include "prtsetup.hxx" |
68 | | #include <salptype.hxx> |
69 | | |
70 | | #include <com/sun/star/beans/PropertyValue.hpp> |
71 | | #include <com/sun/star/view/PrintableState.hpp> |
72 | | |
73 | | using namespace psp; |
74 | | using namespace com::sun::star; |
75 | | |
76 | | namespace |
77 | | { |
78 | | class QueryString : public weld::GenericDialogController |
79 | | { |
80 | | private: |
81 | | OUString& m_rReturnValue; |
82 | | |
83 | | std::unique_ptr<weld::Button> m_xOKButton; |
84 | | std::unique_ptr<weld::Label> m_xFixedText; |
85 | | std::unique_ptr<weld::Entry> m_xEdit; |
86 | | |
87 | | DECL_LINK( ClickBtnHdl, weld::Button&, void ); |
88 | | |
89 | | public: |
90 | | // parent window, Query text, initial value |
91 | | QueryString(weld::Window*, OUString const &, OUString &); |
92 | | }; |
93 | | |
94 | | /* |
95 | | * QueryString |
96 | | */ |
97 | | QueryString::QueryString(weld::Window* pParent, OUString const & rQuery, OUString& rRet) |
98 | 0 | : GenericDialogController(pParent, u"vcl/ui/querydialog.ui"_ustr, u"QueryDialog"_ustr) |
99 | 0 | , m_rReturnValue( rRet ) |
100 | 0 | , m_xOKButton(m_xBuilder->weld_button(u"ok"_ustr)) |
101 | 0 | , m_xFixedText(m_xBuilder->weld_label(u"label"_ustr)) |
102 | 0 | , m_xEdit(m_xBuilder->weld_entry(u"entry"_ustr)) |
103 | 0 | { |
104 | 0 | m_xOKButton->connect_clicked(LINK(this, QueryString, ClickBtnHdl)); |
105 | 0 | m_xFixedText->set_label(rQuery); |
106 | 0 | m_xEdit->set_text(m_rReturnValue); |
107 | 0 | m_xDialog->set_title(rQuery); |
108 | 0 | } |
109 | | |
110 | | IMPL_LINK(QueryString, ClickBtnHdl, weld::Button&, rButton, void) |
111 | 0 | { |
112 | 0 | if (&rButton == m_xOKButton.get()) |
113 | 0 | { |
114 | 0 | m_rReturnValue = m_xEdit->get_text(); |
115 | 0 | m_xDialog->response(RET_OK); |
116 | 0 | } |
117 | 0 | else |
118 | 0 | m_xDialog->response(RET_CANCEL); |
119 | 0 | } |
120 | | |
121 | | int QueryFaxNumber(OUString& rNumber) |
122 | 0 | { |
123 | 0 | QueryString aQuery(Application::GetDefDialogParent(), VclResId(SV_PRINT_QUERYFAXNUMBER_TXT), rNumber); |
124 | 0 | return aQuery.run(); |
125 | 0 | } |
126 | | } |
127 | | |
128 | 0 | static int PtTo10Mu( int nPoints ) { return o3tl::convert(nPoints, o3tl::Length::pt, o3tl::Length::mm100); } |
129 | | |
130 | 0 | static int TenMuToPt( int nUnits ) { return o3tl::convert(nUnits, o3tl::Length::mm100, o3tl::Length::pt); } |
131 | | |
132 | | static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) |
133 | 0 | { |
134 | 0 | pJobSetup->SetOrientation( rData.m_eOrientation == orientation::Landscape ? |
135 | 0 | Orientation::Landscape : Orientation::Portrait ); |
136 | | |
137 | | // copy page size |
138 | 0 | OUString aPaper; |
139 | 0 | int width, height; |
140 | |
|
141 | 0 | rData.m_aContext.getPageSize( aPaper, width, height ); |
142 | 0 | pJobSetup->SetPaperFormat( PaperInfo::fromPSName( |
143 | 0 | OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ))); |
144 | |
|
145 | 0 | pJobSetup->SetPaperWidth( 0 ); |
146 | 0 | pJobSetup->SetPaperHeight( 0 ); |
147 | 0 | if( pJobSetup->GetPaperFormat() == PAPER_USER ) |
148 | 0 | { |
149 | | // transform to 100dth mm |
150 | 0 | width = PtTo10Mu( width ); |
151 | 0 | height = PtTo10Mu( height ); |
152 | |
|
153 | 0 | if( rData.m_eOrientation == psp::orientation::Portrait ) |
154 | 0 | { |
155 | 0 | pJobSetup->SetPaperWidth( width ); |
156 | 0 | pJobSetup->SetPaperHeight( height ); |
157 | 0 | } |
158 | 0 | else |
159 | 0 | { |
160 | 0 | pJobSetup->SetPaperWidth( height ); |
161 | 0 | pJobSetup->SetPaperHeight( width ); |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | | // copy input slot |
166 | 0 | const PPDKey* pKey = nullptr; |
167 | 0 | const PPDValue* pValue = nullptr; |
168 | |
|
169 | 0 | pJobSetup->SetPaperBin( 0 ); |
170 | 0 | if( rData.m_pParser ) |
171 | 0 | pKey = rData.m_pParser->getKey( u"InputSlot"_ustr ); |
172 | 0 | if( pKey ) |
173 | 0 | pValue = rData.m_aContext.getValue( pKey ); |
174 | 0 | if( pKey && pValue ) |
175 | 0 | { |
176 | 0 | int nPaperBin; |
177 | 0 | for( nPaperBin = 0; |
178 | 0 | pValue != pKey->getValue( nPaperBin ) && |
179 | 0 | nPaperBin < pKey->countValues(); |
180 | 0 | nPaperBin++); |
181 | 0 | pJobSetup->SetPaperBin( |
182 | 0 | nPaperBin == pKey->countValues() ? 0 : nPaperBin); |
183 | 0 | } |
184 | | |
185 | | // copy duplex |
186 | 0 | pKey = nullptr; |
187 | 0 | pValue = nullptr; |
188 | |
|
189 | 0 | pJobSetup->SetDuplexMode( DuplexMode::Unknown ); |
190 | 0 | if( rData.m_pParser ) |
191 | 0 | pKey = rData.m_pParser->getKey( u"Duplex"_ustr ); |
192 | 0 | if( pKey ) |
193 | 0 | pValue = rData.m_aContext.getValue( pKey ); |
194 | 0 | if( pKey && pValue ) |
195 | 0 | { |
196 | 0 | if( pValue->m_aOption.equalsIgnoreAsciiCase( "None" ) || |
197 | 0 | pValue->m_aOption.startsWithIgnoreAsciiCase( "Simplex" ) |
198 | 0 | ) |
199 | 0 | { |
200 | 0 | pJobSetup->SetDuplexMode( DuplexMode::Off); |
201 | 0 | } |
202 | 0 | else if( pValue->m_aOption.equalsIgnoreAsciiCase( "DuplexNoTumble" ) ) |
203 | 0 | { |
204 | 0 | pJobSetup->SetDuplexMode( DuplexMode::LongEdge ); |
205 | 0 | } |
206 | 0 | else if( pValue->m_aOption.equalsIgnoreAsciiCase( "DuplexTumble" ) ) |
207 | 0 | { |
208 | 0 | pJobSetup->SetDuplexMode( DuplexMode::ShortEdge ); |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | // copy the whole context |
213 | |
|
214 | 0 | sal_uInt32 nBytes; |
215 | 0 | std::unique_ptr<sal_uInt8[]> pBuffer; |
216 | 0 | if( rData.getStreamBuffer( pBuffer, nBytes ) ) |
217 | 0 | { |
218 | 0 | pJobSetup->SetDriverData( std::move(pBuffer), nBytes ); |
219 | 0 | } |
220 | 0 | else |
221 | 0 | { |
222 | 0 | pJobSetup->SetDriverData( nullptr, 0 ); |
223 | 0 | } |
224 | 0 | pJobSetup->SetPapersizeFromSetup( rData.m_bPapersizeFromSetup ); |
225 | 0 | } |
226 | | |
227 | | static std::vector<OUString> getFaxNumbers() |
228 | 0 | { |
229 | 0 | std::vector<OUString> aFaxNumbers; |
230 | |
|
231 | 0 | OUString aNewNr; |
232 | 0 | if (QueryFaxNumber(aNewNr)) |
233 | 0 | { |
234 | 0 | for (sal_Int32 nIndex {0}; nIndex >= 0; ) |
235 | 0 | aFaxNumbers.push_back(aNewNr.getToken( 0, ';', nIndex )); |
236 | 0 | } |
237 | |
|
238 | 0 | return aFaxNumbers; |
239 | 0 | } |
240 | | |
241 | | /* |
242 | | * SalInstance |
243 | | */ |
244 | | |
245 | | void SalGenericInstance::configurePspInfoPrinter(PspSalInfoPrinter& rPrinter, |
246 | | const SalPrinterQueueInfo& rQueueInfo, |
247 | | ImplJobSetup& rJobSetup) |
248 | 0 | { |
249 | 0 | PrinterInfoManager& rManager( PrinterInfoManager::get() ); |
250 | 0 | PrinterInfo aInfo(rManager.getPrinterInfo(rQueueInfo.maPrinterName)); |
251 | 0 | rPrinter.m_aJobData = aInfo; |
252 | |
|
253 | 0 | if (rJobSetup.GetDriverData()) |
254 | 0 | JobData::constructFromStreamBuffer(rJobSetup.GetDriverData(), rJobSetup.GetDriverDataLen(), |
255 | 0 | aInfo); |
256 | |
|
257 | 0 | rJobSetup.SetSystem(JOBSETUP_SYSTEM_UNIX); |
258 | 0 | rJobSetup.SetPrinterName(rQueueInfo.maPrinterName); |
259 | 0 | rJobSetup.SetDriver(aInfo.m_aDriverName); |
260 | 0 | copyJobDataToJobSetup(&rJobSetup, aInfo); |
261 | 0 | } |
262 | | |
263 | | bool SalGenericInstance::getPdfDir(const PrinterInfo& rInfo, OUString& rDir) |
264 | 0 | { |
265 | 0 | sal_Int32 nIndex = 0; |
266 | 0 | while (nIndex != -1) |
267 | 0 | { |
268 | 0 | OUString aToken(rInfo.m_aFeatures.getToken(0, ',', nIndex)); |
269 | 0 | if (aToken.startsWith("pdf=")) |
270 | 0 | { |
271 | 0 | sal_Int32 nPos = 0; |
272 | 0 | rDir = aToken.getToken(1, '=', nPos); |
273 | 0 | if (rDir.isEmpty() && getenv("HOME")) |
274 | 0 | rDir |
275 | 0 | = OUString(getenv("HOME"), strlen(getenv("HOME")), osl_getThreadTextEncoding()); |
276 | 0 | return true; |
277 | 0 | } |
278 | 0 | } |
279 | 0 | return false; |
280 | 0 | } |
281 | | |
282 | | SalInfoPrinter* SalGenericInstance::CreateInfoPrinter(SalPrinterQueueInfo& rQueueInfo, |
283 | | ImplJobSetup& rJobSetup) |
284 | 0 | { |
285 | 0 | mbPrinterInit = true; |
286 | | // create and initialize SalInfoPrinter |
287 | 0 | PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter(); |
288 | 0 | configurePspInfoPrinter(*pPrinter, rQueueInfo, rJobSetup); |
289 | 0 | return pPrinter; |
290 | 0 | } |
291 | | |
292 | | std::unique_ptr<SalPrinter> SalGenericInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) |
293 | 0 | { |
294 | 0 | mbPrinterInit = true; |
295 | | // create and initialize SalPrinter |
296 | 0 | PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter ); |
297 | 0 | pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData; |
298 | |
|
299 | 0 | return std::unique_ptr<SalPrinter>(pPrinter); |
300 | 0 | } |
301 | | |
302 | | void SalGenericInstance::GetPrinterQueueInfo(ImplPrnQueueList& rList) |
303 | 0 | { |
304 | 0 | mbPrinterInit = true; |
305 | 0 | PrinterInfoManager& rManager( PrinterInfoManager::get() ); |
306 | 0 | static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" ); |
307 | 0 | if( ! pNoSyncDetection || ! *pNoSyncDetection ) |
308 | 0 | { |
309 | | // #i62663# synchronize possible asynchronouse printer detection now |
310 | 0 | rManager.checkPrintersChanged( true ); |
311 | 0 | } |
312 | |
|
313 | 0 | for (const auto& [rPrinterName, rInfo] : rManager.getPrinters()) |
314 | 0 | { |
315 | | // create new entry |
316 | 0 | std::unique_ptr<SalPrinterQueueInfo> pInfo(new SalPrinterQueueInfo); |
317 | 0 | pInfo->maPrinterName = rPrinterName; |
318 | 0 | pInfo->maDriver = rInfo.m_aDriverName; |
319 | 0 | pInfo->maLocation = rInfo.m_aLocation; |
320 | 0 | pInfo->maComment = rInfo.m_aComment; |
321 | |
|
322 | 0 | OUString sPdfDir; |
323 | 0 | if (getPdfDir(rInfo, sPdfDir)) |
324 | 0 | pInfo->maLocation = sPdfDir; |
325 | |
|
326 | 0 | rList.Add(std::move(pInfo)); |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | | OUString SalGenericInstance::GetDefaultPrinter() |
331 | 0 | { |
332 | 0 | mbPrinterInit = true; |
333 | 0 | PrinterInfoManager& rManager( PrinterInfoManager::get() ); |
334 | 0 | return rManager.getDefaultPrinter(); |
335 | 0 | } |
336 | | |
337 | | PspSalInfoPrinter::PspSalInfoPrinter() |
338 | 0 | { |
339 | 0 | } |
340 | | |
341 | | PspSalInfoPrinter::~PspSalInfoPrinter() |
342 | 0 | { |
343 | 0 | } |
344 | | |
345 | | void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) |
346 | 0 | { |
347 | 0 | m_aPaperFormats.clear(); |
348 | 0 | m_bPapersInit = true; |
349 | |
|
350 | 0 | if( !m_aJobData.m_pParser ) |
351 | 0 | return; |
352 | | |
353 | 0 | const PPDKey* pKey = m_aJobData.m_pParser->getKey( u"PageSize"_ustr ); |
354 | 0 | if( pKey ) |
355 | 0 | { |
356 | 0 | int nValues = pKey->countValues(); |
357 | 0 | for( int i = 0; i < nValues; i++ ) |
358 | 0 | { |
359 | 0 | const PPDValue* pValue = pKey->getValue( i ); |
360 | 0 | int nWidth = 0, nHeight = 0; |
361 | 0 | m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight ); |
362 | 0 | PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight )); |
363 | 0 | m_aPaperFormats.push_back( aInfo ); |
364 | 0 | } |
365 | 0 | } |
366 | 0 | } |
367 | | |
368 | | int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* ) |
369 | 0 | { |
370 | 0 | return 900; |
371 | 0 | } |
372 | | |
373 | | SalGraphics* PspSalInfoPrinter::AcquireGraphics() |
374 | 0 | { |
375 | | // return a valid pointer only once |
376 | | // the reasoning behind this is that we could have different |
377 | | // SalGraphics that can run in multiple threads |
378 | | // (future plans) |
379 | 0 | SalGraphics* pRet = nullptr; |
380 | 0 | if( ! m_pGraphics ) |
381 | 0 | { |
382 | 0 | m_pGraphics = GetGenericInstance()->CreatePrintGraphics(); |
383 | 0 | m_pGraphics->Init(&m_aJobData); |
384 | 0 | pRet = m_pGraphics.get(); |
385 | 0 | } |
386 | 0 | return pRet; |
387 | 0 | } |
388 | | |
389 | | void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics ) |
390 | 0 | { |
391 | 0 | if( m_pGraphics.get() == pGraphics ) |
392 | 0 | { |
393 | 0 | m_pGraphics.reset(); |
394 | 0 | } |
395 | 0 | } |
396 | | |
397 | | bool PspSalInfoPrinter::Setup(weld::Window& rFrame, ImplJobSetup& rJobSetup) |
398 | 0 | { |
399 | 0 | PrinterInfoManager& rManager = PrinterInfoManager::get(); |
400 | |
|
401 | 0 | PrinterInfo aInfo(rManager.getPrinterInfo(rJobSetup.GetPrinterName())); |
402 | 0 | if (rJobSetup.GetDriverData()) |
403 | 0 | { |
404 | 0 | SetData(JobSetFlags::ALL, rJobSetup); |
405 | 0 | JobData::constructFromStreamBuffer(rJobSetup.GetDriverData(), rJobSetup.GetDriverDataLen(), |
406 | 0 | aInfo); |
407 | 0 | } |
408 | 0 | aInfo.m_bPapersizeFromSetup = rJobSetup.GetPapersizeFromSetup(); |
409 | 0 | aInfo.meSetupMode = rJobSetup.GetPrinterSetupMode(); |
410 | |
|
411 | 0 | if (SetupPrinterDriver(&rFrame, aInfo)) |
412 | 0 | { |
413 | 0 | rJobSetup.SetDriverData(nullptr, 0); |
414 | |
|
415 | 0 | sal_uInt32 nBytes; |
416 | 0 | std::unique_ptr<sal_uInt8[]> pBuffer; |
417 | 0 | aInfo.getStreamBuffer( pBuffer, nBytes ); |
418 | 0 | rJobSetup.SetDriverData(std::move(pBuffer), nBytes); |
419 | | |
420 | | // copy everything to job setup |
421 | 0 | copyJobDataToJobSetup(&rJobSetup, aInfo); |
422 | 0 | JobData::constructFromStreamBuffer(rJobSetup.GetDriverData(), rJobSetup.GetDriverDataLen(), |
423 | 0 | m_aJobData); |
424 | 0 | return true; |
425 | 0 | } |
426 | 0 | return false; |
427 | 0 | } |
428 | | |
429 | | // This function gets the driver data and puts it into rJobSetup |
430 | | // If rJobSetup.GetDriverData() is NOT NULL, then the independent |
431 | | // data should be merged into the driver data |
432 | | // If rJobSetup.GetDriverData() IS NULL, then the driver defaults |
433 | | // should be merged into the independent data |
434 | | bool PspSalInfoPrinter::SetPrinterData(ImplJobSetup& rJobSetup) |
435 | 0 | { |
436 | 0 | if (rJobSetup.GetDriverData()) |
437 | 0 | return SetData(JobSetFlags::ALL, rJobSetup); |
438 | | |
439 | 0 | copyJobDataToJobSetup(&rJobSetup, m_aJobData); |
440 | |
|
441 | 0 | return true; |
442 | 0 | } |
443 | | |
444 | | bool PspSalInfoPrinter::SetData(JobSetFlags nSetDataFlags, ImplJobSetup& rJobSetup) |
445 | 0 | { |
446 | 0 | JobData aData; |
447 | 0 | JobData::constructFromStreamBuffer(rJobSetup.GetDriverData(), rJobSetup.GetDriverDataLen(), |
448 | 0 | aData); |
449 | |
|
450 | 0 | if( aData.m_pParser ) |
451 | 0 | { |
452 | 0 | const PPDKey* pKey; |
453 | 0 | const PPDValue* pValue; |
454 | | |
455 | | // merge orientation if necessary |
456 | 0 | if( nSetDataFlags & JobSetFlags::ORIENTATION ) |
457 | 0 | aData.m_eOrientation = rJobSetup.GetOrientation() == Orientation::Landscape |
458 | 0 | ? orientation::Landscape |
459 | 0 | : orientation::Portrait; |
460 | | |
461 | | // merge papersize if necessary |
462 | 0 | if( nSetDataFlags & JobSetFlags::PAPERSIZE ) |
463 | 0 | { |
464 | 0 | OUString aPaper; |
465 | |
|
466 | 0 | if (rJobSetup.GetPaperFormat() == PAPER_USER) |
467 | 0 | aPaper = aData.m_pParser->matchPaper(TenMuToPt(rJobSetup.GetPaperWidth()), |
468 | 0 | TenMuToPt(rJobSetup.GetPaperHeight()), |
469 | 0 | &aData.m_eOrientation); |
470 | 0 | else |
471 | 0 | aPaper = OStringToOUString(PaperInfo::toPSName(rJobSetup.GetPaperFormat()), |
472 | 0 | RTL_TEXTENCODING_ISO_8859_1); |
473 | |
|
474 | 0 | pKey = aData.m_pParser->getKey( u"PageSize"_ustr ); |
475 | 0 | pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : nullptr; |
476 | | |
477 | | // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5) |
478 | | // try to find the correct paper anyway using the size |
479 | 0 | if (pKey && !pValue && rJobSetup.GetPaperFormat() != PAPER_USER) |
480 | 0 | { |
481 | 0 | PaperInfo aInfo(rJobSetup.GetPaperFormat()); |
482 | 0 | aPaper = aData.m_pParser->matchPaper( |
483 | 0 | TenMuToPt( aInfo.getWidth() ), |
484 | 0 | TenMuToPt( aInfo.getHeight() ), |
485 | 0 | &aData.m_eOrientation ); |
486 | 0 | pValue = pKey->getValueCaseInsensitive( aPaper ); |
487 | 0 | } |
488 | |
|
489 | 0 | if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue ) == pValue ) ) |
490 | 0 | return false; |
491 | 0 | } |
492 | | |
493 | | // merge paperbin if necessary |
494 | 0 | if( nSetDataFlags & JobSetFlags::PAPERBIN ) |
495 | 0 | { |
496 | 0 | pKey = aData.m_pParser->getKey( u"InputSlot"_ustr ); |
497 | 0 | if( pKey ) |
498 | 0 | { |
499 | 0 | int nPaperBin = rJobSetup.GetPaperBin(); |
500 | 0 | if( nPaperBin >= pKey->countValues() ) |
501 | 0 | pValue = pKey->getDefaultValue(); |
502 | 0 | else |
503 | 0 | pValue = pKey->getValue(rJobSetup.GetPaperBin()); |
504 | | |
505 | | // may fail due to constraints; |
506 | | // real paper bin is copied back to jobsetup in that case |
507 | 0 | aData.m_aContext.setValue( pKey, pValue ); |
508 | 0 | } |
509 | | // if printer has no InputSlot key simply ignore this setting |
510 | | // (e.g. SGENPRT has no InputSlot) |
511 | 0 | } |
512 | | |
513 | | // merge duplex if necessary |
514 | 0 | if( nSetDataFlags & JobSetFlags::DUPLEXMODE ) |
515 | 0 | { |
516 | 0 | pKey = aData.m_pParser->getKey( u"Duplex"_ustr ); |
517 | 0 | if( pKey ) |
518 | 0 | { |
519 | 0 | pValue = nullptr; |
520 | 0 | switch (rJobSetup.GetDuplexMode()) |
521 | 0 | { |
522 | 0 | case DuplexMode::Off: |
523 | 0 | pValue = pKey->getValue( u"None"_ustr ); |
524 | 0 | if( pValue == nullptr ) |
525 | 0 | pValue = pKey->getValue( u"SimplexNoTumble"_ustr ); |
526 | 0 | break; |
527 | 0 | case DuplexMode::ShortEdge: |
528 | 0 | pValue = pKey->getValue( u"DuplexTumble"_ustr ); |
529 | 0 | break; |
530 | 0 | case DuplexMode::LongEdge: |
531 | 0 | pValue = pKey->getValue( u"DuplexNoTumble"_ustr ); |
532 | 0 | break; |
533 | 0 | case DuplexMode::Unknown: |
534 | 0 | default: |
535 | 0 | pValue = nullptr; |
536 | 0 | break; |
537 | 0 | } |
538 | 0 | if( ! pValue ) |
539 | 0 | pValue = pKey->getDefaultValue(); |
540 | 0 | aData.m_aContext.setValue( pKey, pValue ); |
541 | 0 | } |
542 | 0 | } |
543 | 0 | aData.m_bPapersizeFromSetup = rJobSetup.GetPapersizeFromSetup(); |
544 | |
|
545 | 0 | m_aJobData = aData; |
546 | 0 | copyJobDataToJobSetup(&rJobSetup, aData); |
547 | 0 | return true; |
548 | 0 | } |
549 | | |
550 | 0 | return false; |
551 | 0 | } |
552 | | |
553 | | void PspSalInfoPrinter::GetPageInfo( |
554 | | const ImplJobSetup* pJobSetup, |
555 | | tools::Long& rOutWidth, tools::Long& rOutHeight, |
556 | | Point& rPageOffset, |
557 | | Size& rPaperSize ) |
558 | 0 | { |
559 | 0 | if( ! pJobSetup ) |
560 | 0 | return; |
561 | | |
562 | 0 | JobData aData; |
563 | 0 | JobData::constructFromStreamBuffer( pJobSetup->GetDriverData(), pJobSetup->GetDriverDataLen(), aData ); |
564 | | |
565 | | // get the selected page size |
566 | 0 | if( !aData.m_pParser ) |
567 | 0 | return; |
568 | | |
569 | | |
570 | 0 | OUString aPaper; |
571 | 0 | int width, height; |
572 | 0 | int left = 0, top = 0, right = 0, bottom = 0; |
573 | 0 | int nDPI = aData.m_aContext.getRenderResolution(); |
574 | |
|
575 | 0 | if( aData.m_eOrientation == psp::orientation::Portrait ) |
576 | 0 | { |
577 | 0 | aData.m_aContext.getPageSize( aPaper, width, height ); |
578 | 0 | aData.m_pParser->getMargins( aPaper, left, right, top, bottom ); |
579 | 0 | } |
580 | 0 | else |
581 | 0 | { |
582 | 0 | aData.m_aContext.getPageSize( aPaper, height, width ); |
583 | 0 | aData.m_pParser->getMargins( aPaper, top, bottom, right, left ); |
584 | 0 | } |
585 | |
|
586 | 0 | rPaperSize.setWidth( width * nDPI / 72 ); |
587 | 0 | rPaperSize.setHeight( height * nDPI / 72 ); |
588 | 0 | rPageOffset.setX( left * nDPI / 72 ); |
589 | 0 | rPageOffset.setY( top * nDPI / 72 ); |
590 | 0 | rOutWidth = ( width - left - right ) * nDPI / 72; |
591 | 0 | rOutHeight = ( height - top - bottom ) * nDPI / 72; |
592 | |
|
593 | 0 | } |
594 | | |
595 | | sal_uInt16 PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup ) |
596 | 0 | { |
597 | 0 | if( ! pJobSetup ) |
598 | 0 | return 0; |
599 | | |
600 | 0 | JobData aData; |
601 | 0 | JobData::constructFromStreamBuffer( pJobSetup->GetDriverData(), pJobSetup->GetDriverDataLen(), aData ); |
602 | |
|
603 | 0 | const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( u"InputSlot"_ustr ): nullptr; |
604 | 0 | return pKey ? pKey->countValues() : 0; |
605 | 0 | } |
606 | | |
607 | | OUString PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uInt16 nPaperBin ) |
608 | 0 | { |
609 | 0 | JobData aData; |
610 | 0 | JobData::constructFromStreamBuffer( pJobSetup->GetDriverData(), pJobSetup->GetDriverDataLen(), aData ); |
611 | |
|
612 | 0 | if( aData.m_pParser ) |
613 | 0 | { |
614 | 0 | const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( u"InputSlot"_ustr ): nullptr; |
615 | 0 | if( ! pKey || nPaperBin >= o3tl::make_unsigned(pKey->countValues()) ) |
616 | 0 | return aData.m_pParser->getDefaultInputSlot(); |
617 | 0 | const PPDValue* pValue = pKey->getValue( nPaperBin ); |
618 | 0 | if( pValue ) |
619 | 0 | return aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption ); |
620 | 0 | } |
621 | | |
622 | 0 | return OUString(); |
623 | 0 | } |
624 | | |
625 | | sal_uInt16 PspSalInfoPrinter::GetPaperBinBySourceIndex( const ImplJobSetup*, sal_uInt16 ) |
626 | 0 | { |
627 | 0 | return 0xffff; |
628 | 0 | } |
629 | | |
630 | | sal_uInt16 PspSalInfoPrinter::GetSourceIndexByPaperBin(const ImplJobSetup*, sal_uInt16) |
631 | 0 | { |
632 | 0 | return 0; |
633 | 0 | } |
634 | | |
635 | | sal_uInt32 PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, PrinterCapType nType ) |
636 | 0 | { |
637 | 0 | switch( nType ) |
638 | 0 | { |
639 | 0 | case PrinterCapType::SupportDialog: |
640 | 0 | return 1; |
641 | 0 | case PrinterCapType::Copies: |
642 | 0 | return 0xffff; |
643 | 0 | case PrinterCapType::CollateCopies: |
644 | 0 | { |
645 | | // PPDs don't mention the number of possible collated copies. |
646 | | // so let's guess as many as we want ? |
647 | 0 | return 0xffff; |
648 | 0 | } |
649 | 0 | case PrinterCapType::SetOrientation: |
650 | 0 | return 1; |
651 | 0 | case PrinterCapType::SetPaperSize: |
652 | 0 | return 1; |
653 | 0 | case PrinterCapType::SetPaper: |
654 | 0 | return 0; |
655 | 0 | case PrinterCapType::Fax: |
656 | 0 | { |
657 | | // see if the PPD contains the fax4CUPS "Dial" option and that it's not set |
658 | | // to "manually" |
659 | 0 | JobData aData = PrinterInfoManager::get().getPrinterInfo(pJobSetup->GetPrinterName()); |
660 | 0 | if( pJobSetup->GetDriverData() ) |
661 | 0 | JobData::constructFromStreamBuffer( pJobSetup->GetDriverData(), pJobSetup->GetDriverDataLen(), aData ); |
662 | 0 | const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey(u"Dial"_ustr) : nullptr; |
663 | 0 | const PPDValue* pValue = pKey ? aData.m_aContext.getValue(pKey) : nullptr; |
664 | 0 | if (pValue && !pValue->m_aOption.equalsIgnoreAsciiCase("Manually")) |
665 | 0 | return 1; |
666 | 0 | return 0; |
667 | 0 | } |
668 | | |
669 | 0 | case PrinterCapType::PDF: |
670 | 0 | return 1; |
671 | 0 | case PrinterCapType::ExternalDialog: |
672 | 0 | return PrinterInfoManager::get().checkFeatureToken( pJobSetup->GetPrinterName(), "external_dialog" ) ? 1 : 0; |
673 | 0 | case PrinterCapType::UsePullModel: |
674 | 0 | return 1; |
675 | 0 | default: break; |
676 | 0 | } |
677 | 0 | return 0; |
678 | 0 | } |
679 | | |
680 | | /* |
681 | | * SalPrinter |
682 | | */ |
683 | | PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter ) |
684 | 0 | : m_pInfoPrinter( pInfoPrinter ) |
685 | 0 | { |
686 | 0 | } |
687 | | |
688 | | PspSalPrinter::~PspSalPrinter() |
689 | 0 | { |
690 | 0 | } |
691 | | |
692 | | bool PspSalPrinter::StartJob( |
693 | | const OUString* /*pFileName*/, |
694 | | const OUString& /*rJobName*/, |
695 | | const OUString& /*rAppName*/, |
696 | | sal_uInt32 /*nCopies*/, |
697 | | bool /*bCollate*/, |
698 | | bool /*bDirect*/, |
699 | | ImplJobSetup* /*pJobSetup*/ ) |
700 | 0 | { |
701 | 0 | OSL_FAIL( "should never be called" ); |
702 | 0 | return false; |
703 | 0 | } |
704 | | |
705 | | bool PspSalPrinter::EndJob() |
706 | 0 | { |
707 | 0 | return true; |
708 | 0 | } |
709 | | |
710 | | SalGraphics* PspSalPrinter::StartPage( ImplJobSetup*, bool ) |
711 | 0 | { |
712 | 0 | OSL_FAIL( "should never be called" ); |
713 | 0 | return nullptr; |
714 | 0 | } |
715 | | |
716 | | void PspSalPrinter::EndPage() |
717 | 0 | { |
718 | 0 | OSL_FAIL( "should never be called" ); |
719 | 0 | } |
720 | | |
721 | | namespace { |
722 | | |
723 | | struct PDFNewJobParameters |
724 | | { |
725 | | Size maPageSize; |
726 | | sal_uInt16 mnPaperBin; |
727 | | |
728 | | PDFNewJobParameters( const Size& i_rSize = Size(), |
729 | | sal_uInt16 i_nPaperBin = 0xffff ) |
730 | 0 | : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {} |
731 | | |
732 | | bool operator==(const PDFNewJobParameters& rComp ) const |
733 | 0 | { |
734 | 0 | const tools::Long nRotatedWidth = rComp.maPageSize.Height(); |
735 | 0 | const tools::Long nRotatedHeight = rComp.maPageSize.Width(); |
736 | 0 | Size aCompLSSize(nRotatedWidth, nRotatedHeight); |
737 | 0 | return |
738 | 0 | (maPageSize == rComp.maPageSize || maPageSize == aCompLSSize) |
739 | 0 | && mnPaperBin == rComp.mnPaperBin |
740 | 0 | ; |
741 | 0 | } |
742 | | |
743 | | bool operator!=(const PDFNewJobParameters& rComp) const |
744 | 0 | { |
745 | 0 | return ! operator==(rComp); |
746 | 0 | } |
747 | | }; |
748 | | |
749 | | struct PDFPrintFile |
750 | | { |
751 | | OUString maTmpURL; |
752 | | PDFNewJobParameters maParameters; |
753 | | |
754 | | PDFPrintFile( OUString i_URL, const PDFNewJobParameters& i_rNewParameters ) |
755 | 0 | : maTmpURL(std::move( i_URL )) |
756 | 0 | , maParameters( i_rNewParameters ) {} |
757 | | }; |
758 | | |
759 | | } |
760 | | |
761 | | bool PspSalPrinter::StartJob( const OUString* i_pFileName, const OUString& i_rJobName, const OUString& i_rAppName, |
762 | | ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController ) |
763 | 0 | { |
764 | 0 | SAL_INFO( "vcl.unx.print", "StartJob with controller: pFilename = " << (i_pFileName ? *i_pFileName : u"<nil>"_ustr) ); |
765 | | // reset IsLastPage |
766 | 0 | i_rController.setLastPage( false ); |
767 | | // is this a fax device |
768 | 0 | bool bFax = m_pInfoPrinter->GetCapabilities(i_pSetupData, PrinterCapType::Fax) == 1; |
769 | | |
770 | | // update job data |
771 | 0 | if( i_pSetupData ) |
772 | 0 | JobData::constructFromStreamBuffer( i_pSetupData->GetDriverData(), i_pSetupData->GetDriverDataLen(), m_aJobData ); |
773 | | |
774 | | // possibly create one job for collated output |
775 | 0 | int nCopies = i_rController.getPrinter()->GetCopyCount(); |
776 | 0 | bool bCollate = i_rController.getPrinter()->IsCollateCopy(); |
777 | 0 | bool bSinglePrintJobs = i_rController.getPrinter()->IsSinglePrintJobs(); |
778 | | |
779 | | // notify start of real print job |
780 | 0 | i_rController.jobStarted(); |
781 | | |
782 | | // setup PDFWriter context |
783 | 0 | vcl::pdf::PDFWriter::PDFWriterContext aContext; |
784 | 0 | aContext.Version = vcl::pdf::PDFWriter::PDFVersion::PDF_1_4; |
785 | 0 | aContext.Tagged = false; |
786 | 0 | aContext.DocumentLocale = Application::GetSettings().GetLanguageTag().getLocale(); |
787 | 0 | aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales() |
788 | 0 | ? vcl::pdf::PDFWriter::DrawGreyscale : vcl::pdf::PDFWriter::DrawColor; |
789 | | |
790 | | // prepare doc info |
791 | 0 | aContext.DocumentInfo.Title = i_rJobName; |
792 | 0 | aContext.DocumentInfo.Creator = i_rAppName; |
793 | 0 | aContext.DocumentInfo.Producer = i_rAppName; |
794 | | |
795 | | // define how we handle metafiles in PDFWriter |
796 | 0 | vcl::pdf::PDFWriter::PlayMetafileContext aMtfContext; |
797 | 0 | aMtfContext.m_bOnlyLosslessCompression = true; |
798 | |
|
799 | 0 | std::shared_ptr<vcl::pdf::PDFWriter> xWriter; |
800 | 0 | std::vector< PDFPrintFile > aPDFFiles; |
801 | 0 | VclPtr<Printer> xPrinter( i_rController.getPrinter() ); |
802 | 0 | int nAllPages = i_rController.getFilteredPageCount(); |
803 | 0 | i_rController.createProgressDialog(); |
804 | 0 | bool bAborted = false; |
805 | 0 | PDFNewJobParameters aLastParm; |
806 | |
|
807 | 0 | aContext.DPIx = xPrinter->GetDPIX(); |
808 | 0 | aContext.DPIy = xPrinter->GetDPIY(); |
809 | 0 | for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ ) |
810 | 0 | { |
811 | 0 | if( nPage == nAllPages-1 ) |
812 | 0 | i_rController.setLastPage( true ); |
813 | | |
814 | | // get the page's metafile |
815 | 0 | GDIMetaFile aPageFile; |
816 | 0 | vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile ); |
817 | 0 | if( i_rController.isProgressCanceled() ) |
818 | 0 | { |
819 | 0 | bAborted = true; |
820 | 0 | if( nPage != nAllPages-1 ) |
821 | 0 | { |
822 | 0 | i_rController.createProgressDialog(); |
823 | 0 | i_rController.setLastPage( true ); |
824 | 0 | i_rController.getFilteredPageFile( nPage, aPageFile ); |
825 | 0 | } |
826 | 0 | } |
827 | 0 | else |
828 | 0 | { |
829 | 0 | xPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) ); |
830 | 0 | xPrinter->SetPaperSizeUser( aPageSize.aSize ); |
831 | 0 | PDFNewJobParameters aNewParm(xPrinter->GetPaperSize(), xPrinter->GetPaperBin()); |
832 | | |
833 | | // create PDF writer on demand |
834 | | // either on first page |
835 | | // or on paper format change - cups does not support multiple paper formats per job (yet?) |
836 | | // so we need to start a new job to get a new paper format from the printer |
837 | | // orientation switches (that is switch of height and width) is handled transparently by CUPS |
838 | 0 | if( ! xWriter || |
839 | 0 | (aNewParm != aLastParm && ! i_pFileName ) ) |
840 | 0 | { |
841 | 0 | if( xWriter ) |
842 | 0 | { |
843 | 0 | xWriter->Emit(); |
844 | 0 | } |
845 | | // produce PDF file |
846 | 0 | OUString aPDFUrl; |
847 | 0 | if( i_pFileName ) |
848 | 0 | aPDFUrl = *i_pFileName; |
849 | 0 | else |
850 | 0 | osl_createTempFile( nullptr, nullptr, &aPDFUrl.pData ); |
851 | | // normalize to file URL |
852 | 0 | if( !comphelper::isFileUrl(aPDFUrl) ) |
853 | 0 | { |
854 | | // this is not a file URL, but it should |
855 | | // form it into an osl friendly file URL |
856 | 0 | OUString aTmp; |
857 | 0 | osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData ); |
858 | 0 | aPDFUrl = aTmp; |
859 | 0 | } |
860 | | // save current file and paper format |
861 | 0 | aLastParm = aNewParm; |
862 | 0 | aPDFFiles.emplace_back( aPDFUrl, aNewParm ); |
863 | | // update context |
864 | 0 | aContext.URL = aPDFUrl; |
865 | | |
866 | | // create and initialize PDFWriter |
867 | 0 | xWriter = std::make_shared<vcl::pdf::PDFWriter>( aContext, uno::Reference< beans::XMaterialHolder >() ); |
868 | 0 | } |
869 | |
|
870 | 0 | xWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ), |
871 | 0 | TenMuToPt( aNewParm.maPageSize.Height() ), |
872 | 0 | vcl::pdf::PDFWriter::Orientation::Portrait ); |
873 | |
|
874 | 0 | xWriter->PlayMetafile( aPageFile, aMtfContext ); |
875 | 0 | } |
876 | 0 | } |
877 | | |
878 | | // emit the last file |
879 | 0 | if( xWriter ) |
880 | 0 | xWriter->Emit(); |
881 | | |
882 | | // handle collate, copy count and multiple jobs correctly |
883 | 0 | int nOuterJobs = 1; |
884 | 0 | if( bSinglePrintJobs ) |
885 | 0 | { |
886 | 0 | nOuterJobs = nCopies; |
887 | 0 | m_aJobData.m_nCopies = 1; |
888 | 0 | } |
889 | 0 | else |
890 | 0 | { |
891 | 0 | if( bCollate ) |
892 | 0 | { |
893 | 0 | if (aPDFFiles.size() == 1 && xPrinter->HasSupport(PrinterSupport::CollateCopy)) |
894 | 0 | { |
895 | 0 | m_aJobData.setCollate( true ); |
896 | 0 | m_aJobData.m_nCopies = nCopies; |
897 | 0 | } |
898 | 0 | else |
899 | 0 | { |
900 | 0 | nOuterJobs = nCopies; |
901 | 0 | m_aJobData.m_nCopies = 1; |
902 | 0 | } |
903 | 0 | } |
904 | 0 | else |
905 | 0 | { |
906 | 0 | m_aJobData.setCollate( false ); |
907 | 0 | m_aJobData.m_nCopies = nCopies; |
908 | 0 | } |
909 | 0 | } |
910 | |
|
911 | 0 | std::vector<OUString> aFaxNumbers; |
912 | | |
913 | | // check for fax numbers |
914 | 0 | if (!bAborted && bFax) |
915 | 0 | { |
916 | 0 | aFaxNumbers = getFaxNumbers(); |
917 | 0 | bAborted = aFaxNumbers.empty(); |
918 | 0 | } |
919 | |
|
920 | 0 | bool bSuccess(true); |
921 | | // spool files |
922 | 0 | if( ! i_pFileName && ! bAborted ) |
923 | 0 | { |
924 | 0 | do |
925 | 0 | { |
926 | 0 | OUString sFaxNumber; |
927 | 0 | if (!aFaxNumbers.empty()) |
928 | 0 | { |
929 | 0 | sFaxNumber = aFaxNumbers.back(); |
930 | 0 | aFaxNumbers.pop_back(); |
931 | 0 | } |
932 | |
|
933 | 0 | bool bFirstJob = true; |
934 | 0 | for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ ) |
935 | 0 | { |
936 | 0 | for( size_t i = 0; i < aPDFFiles.size(); i++ ) |
937 | 0 | { |
938 | 0 | oslFileHandle pFile = nullptr; |
939 | 0 | osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read ); |
940 | 0 | if (pFile && (osl_setFilePos(pFile, osl_Pos_Absolut, 0) == osl_File_E_None)) |
941 | 0 | { |
942 | 0 | std::vector< char > buffer( 0x10000, 0 ); |
943 | | // update job data with current page size |
944 | 0 | Size aPageSize( aPDFFiles[i].maParameters.maPageSize ); |
945 | 0 | m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) ); |
946 | | // update job data with current paperbin |
947 | 0 | m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin ); |
948 | | |
949 | | // spool current file |
950 | 0 | FILE* fp = PrinterInfoManager::get().startSpool(xPrinter->GetName(), i_rController.isDirectPrint()); |
951 | 0 | if( fp ) |
952 | 0 | { |
953 | 0 | sal_uInt64 nBytesRead = 0; |
954 | 0 | do |
955 | 0 | { |
956 | 0 | osl_readFile( pFile, buffer.data(), buffer.size(), &nBytesRead ); |
957 | 0 | if( nBytesRead > 0 ) |
958 | 0 | { |
959 | 0 | size_t nBytesWritten = fwrite(buffer.data(), 1, nBytesRead, fp); |
960 | 0 | OSL_ENSURE(nBytesRead == nBytesWritten, "short write"); |
961 | 0 | if (nBytesRead != nBytesWritten) |
962 | 0 | break; |
963 | 0 | } |
964 | 0 | } while( nBytesRead == buffer.size() ); |
965 | 0 | OUStringBuffer aBuf( i_rJobName.getLength() + 8 ); |
966 | 0 | aBuf.append( i_rJobName ); |
967 | 0 | if( i > 0 || nCurJob > 0 ) |
968 | 0 | { |
969 | 0 | aBuf.append( ' ' ); |
970 | 0 | aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) ); |
971 | 0 | } |
972 | 0 | bSuccess &= |
973 | 0 | PrinterInfoManager::get().endSpool(xPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob, sFaxNumber); |
974 | 0 | bFirstJob = false; |
975 | 0 | } |
976 | 0 | } |
977 | 0 | osl_closeFile( pFile ); |
978 | 0 | } |
979 | 0 | } |
980 | 0 | } |
981 | 0 | while (!aFaxNumbers.empty()); |
982 | 0 | } |
983 | | |
984 | | // job has been spooled |
985 | 0 | i_rController.setJobState( bAborted |
986 | 0 | ? view::PrintableState_JOB_ABORTED |
987 | 0 | : (bSuccess ? view::PrintableState_JOB_SPOOLED |
988 | 0 | : view::PrintableState_JOB_SPOOLING_FAILED)); |
989 | | |
990 | | // clean up the temporary PDF files |
991 | 0 | if( ! i_pFileName || bAborted ) |
992 | 0 | { |
993 | 0 | for(PDFPrintFile & rPDFFile : aPDFFiles) |
994 | 0 | { |
995 | 0 | osl_removeFile( rPDFFile.maTmpURL.pData ); |
996 | 0 | SAL_INFO( "vcl.unx.print", "removed print PDF file " << rPDFFile.maTmpURL ); |
997 | 0 | } |
998 | 0 | } |
999 | | |
1000 | 0 | return true; |
1001 | 0 | } |
1002 | | |
1003 | | void SalGenericInstance::updatePrinterUpdate() |
1004 | 0 | { |
1005 | 0 | if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() ) |
1006 | 0 | return; |
1007 | | |
1008 | 0 | if (!isPrinterInit()) |
1009 | 0 | { |
1010 | | // #i45389# start background printer detection |
1011 | 0 | psp::PrinterInfoManager::get(); |
1012 | 0 | return; |
1013 | 0 | } |
1014 | | |
1015 | 0 | ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() ); |
1016 | 0 | if (rManager.checkPrintersChanged(false)) |
1017 | 0 | PostPrintersChanged(); |
1018 | 0 | } |
1019 | | |
1020 | | std::unique_ptr<GenPspGraphics> SalGenericInstance::CreatePrintGraphics() |
1021 | 0 | { |
1022 | 0 | return std::make_unique<GenPspGraphics>(); |
1023 | 0 | } |
1024 | | |
1025 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |