1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <boost/bind.hpp> 32 33 #include "vcl/print.hxx" 34 #include "vcl/unohelp.hxx" 35 36 #include "aqua/salinst.h" 37 #include "aqua/salprn.h" 38 #include "aqua/aquaprintview.h" 39 #include "aqua/salgdi.h" 40 #include "aqua/saldata.hxx" 41 42 #include "jobset.h" 43 #include "salptype.hxx" 44 45 #include "com/sun/star/lang/XMultiServiceFactory.hpp" 46 #include "com/sun/star/container/XNameAccess.hpp" 47 #include "com/sun/star/beans/PropertyValue.hpp" 48 #include "com/sun/star/awt/Size.hpp" 49 50 #include <algorithm> 51 52 using namespace rtl; 53 using namespace vcl; 54 using namespace com::sun::star; 55 using namespace com::sun::star::uno; 56 using namespace com::sun::star::lang; 57 using namespace com::sun::star::beans; 58 using namespace com::sun::star::container; 59 60 // ======================================================================= 61 62 AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo& i_rQueue ) : 63 mpGraphics( 0 ), 64 mbGraphics( false ), 65 mbJob( false ), 66 mpPrinter( nil ), 67 mpPrintInfo( nil ), 68 mePageOrientation( ORIENTATION_PORTRAIT ), 69 mnStartPageOffsetX( 0 ), 70 mnStartPageOffsetY( 0 ), 71 mnCurPageRangeStart( 0 ), 72 mnCurPageRangeCount( 0 ) 73 { 74 NSString* pStr = CreateNSString( i_rQueue.maPrinterName ); 75 mpPrinter = [NSPrinter printerWithName: pStr]; 76 [pStr release]; 77 78 NSPrintInfo* pShared = [NSPrintInfo sharedPrintInfo]; 79 if( pShared ) 80 { 81 mpPrintInfo = [pShared copy]; 82 [mpPrintInfo setPrinter: mpPrinter]; 83 mePageOrientation = ([mpPrintInfo orientation] == NSLandscapeOrientation) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; 84 [mpPrintInfo setOrientation: NSPortraitOrientation]; 85 } 86 87 mpGraphics = new AquaSalGraphics(); 88 89 const int nWidth = 100, nHeight = 100; 90 maContextMemory.reset( reinterpret_cast<sal_uInt8*>( rtl_allocateMemory( nWidth * 4 * nHeight ) ), 91 boost::bind( rtl_freeMemory, _1 ) ); 92 93 if( maContextMemory ) 94 { 95 mrContext = CGBitmapContextCreate( maContextMemory.get(), nWidth, nHeight, 8, nWidth * 4, GetSalData()->mxRGBSpace, kCGImageAlphaNoneSkipFirst ); 96 if( mrContext ) 97 SetupPrinterGraphics( mrContext ); 98 } 99 } 100 101 // ----------------------------------------------------------------------- 102 103 AquaSalInfoPrinter::~AquaSalInfoPrinter() 104 { 105 delete mpGraphics; 106 if( mpPrintInfo ) 107 [mpPrintInfo release]; 108 #if 0 109 // FIXME: verify that NSPrintInfo releases the printer 110 // else we have a leak here 111 if( mpPrinter ) 112 [mpPrinter release]; 113 #endif 114 if( mrContext ) 115 CFRelease( mrContext ); 116 } 117 118 // ----------------------------------------------------------------------- 119 120 void AquaSalInfoPrinter::SetupPrinterGraphics( CGContextRef i_rContext ) const 121 { 122 if( mpGraphics ) 123 { 124 if( mpPrintInfo ) 125 { 126 // FIXME: get printer resolution 127 long nDPIX = 720, nDPIY = 720; 128 NSSize aPaperSize = [mpPrintInfo paperSize]; 129 130 NSRect aImageRect = [mpPrintInfo imageablePageBounds]; 131 if( mePageOrientation == ORIENTATION_PORTRAIT ) 132 { 133 // move mirrored CTM back into paper 134 double dX = 0, dY = aPaperSize.height; 135 // move CTM to reflect imageable area 136 dX += aImageRect.origin.x; 137 dY -= aPaperSize.height - aImageRect.size.height - aImageRect.origin.y; 138 CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetX, dY - mnStartPageOffsetY ); 139 // scale to be top/down and reflect our "virtual" DPI 140 CGContextScaleCTM( i_rContext, 72.0/double(nDPIX), -(72.0/double(nDPIY)) ); 141 } 142 else 143 { 144 // move CTM to reflect imageable area 145 double dX = aImageRect.origin.x, dY = aPaperSize.height - aImageRect.size.height - aImageRect.origin.y; 146 CGContextTranslateCTM( i_rContext, -dX, -dY ); 147 // turn by 90 degree 148 CGContextRotateCTM( i_rContext, M_PI/2 ); 149 // move turned CTM back into paper 150 dX = aPaperSize.height; 151 dY = -aPaperSize.width; 152 CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetY, dY - mnStartPageOffsetX ); 153 // scale to be top/down and reflect our "virtual" DPI 154 CGContextScaleCTM( i_rContext, -(72.0/double(nDPIY)), (72.0/double(nDPIX)) ); 155 } 156 mpGraphics->SetPrinterGraphics( i_rContext, nDPIX, nDPIY, 1.0 ); 157 } 158 else 159 DBG_ERROR( "no print info in SetupPrinterGraphics" ); 160 } 161 } 162 163 // ----------------------------------------------------------------------- 164 165 SalGraphics* AquaSalInfoPrinter::GetGraphics() 166 { 167 SalGraphics* pGraphics = mbGraphics ? NULL : mpGraphics; 168 mbGraphics = true; 169 return pGraphics; 170 } 171 172 // ----------------------------------------------------------------------- 173 174 void AquaSalInfoPrinter::ReleaseGraphics( SalGraphics* ) 175 { 176 mbGraphics = false; 177 } 178 179 // ----------------------------------------------------------------------- 180 181 sal_Bool AquaSalInfoPrinter::Setup( SalFrame*, ImplJobSetup* ) 182 { 183 return sal_False; 184 } 185 186 // ----------------------------------------------------------------------- 187 188 static struct PaperSizeEntry 189 { 190 double fWidth; 191 double fHeight; 192 Paper nPaper; 193 } aPaperSizes[] = 194 { 195 { 842, 1191, PAPER_A3 }, 196 { 595, 842, PAPER_A4 }, 197 { 420, 595, PAPER_A5 }, 198 { 612, 792, PAPER_LETTER }, 199 { 612, 1008, PAPER_LEGAL }, 200 { 728, 1032, PAPER_B4_JIS }, 201 { 516, 729, PAPER_B5_JIS }, 202 { 792, 1224, PAPER_TABLOID } 203 }; 204 205 static bool getPaperSize( double& o_fWidth, double& o_fHeight, const Paper i_ePaper ) 206 { 207 for(unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ ) 208 { 209 if( aPaperSizes[i].nPaper == i_ePaper ) 210 { 211 o_fWidth = aPaperSizes[i].fWidth; 212 o_fHeight = aPaperSizes[i].fHeight; 213 return true; 214 } 215 } 216 return false; 217 } 218 219 static Paper recognizePaper( double i_fWidth, double i_fHeight ) 220 { 221 Paper aPaper = PAPER_USER; 222 sal_uInt64 nPaperDesc = 1000000*sal_uInt64(i_fWidth) + sal_uInt64(i_fHeight); 223 switch( nPaperDesc ) 224 { 225 case 842001191: aPaper = PAPER_A3; break; 226 case 595000842: aPaper = PAPER_A4; break; 227 case 420000595: aPaper = PAPER_A5; break; 228 case 612000792: aPaper = PAPER_LETTER; break; 229 case 728001032: aPaper = PAPER_B4_JIS; break; 230 case 516000729: aPaper = PAPER_B5_JIS; break; 231 case 612001008: aPaper = PAPER_LEGAL; break; 232 case 792001224: aPaper = PAPER_TABLOID; break; 233 default: 234 aPaper = PAPER_USER; 235 break; 236 } 237 238 if( aPaper == PAPER_USER ) 239 { 240 // search with fuzz factor 241 for( unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ ) 242 { 243 double w = (i_fWidth > aPaperSizes[i].fWidth) ? i_fWidth - aPaperSizes[i].fWidth : aPaperSizes[i].fWidth - i_fWidth; 244 double h = (i_fHeight > aPaperSizes[i].fHeight) ? i_fHeight - aPaperSizes[i].fHeight : aPaperSizes[i].fHeight - i_fHeight; 245 if( w < 3 && h < 3 ) 246 { 247 aPaper = aPaperSizes[i].nPaper; 248 break; 249 } 250 } 251 } 252 253 return aPaper; 254 } 255 256 sal_Bool AquaSalInfoPrinter::SetPrinterData( ImplJobSetup* io_pSetupData ) 257 { 258 // FIXME: implement driver data 259 if( io_pSetupData && io_pSetupData->mpDriverData ) 260 return SetData( ~0, io_pSetupData ); 261 262 263 sal_Bool bSuccess = sal_True; 264 265 // set system type 266 io_pSetupData->mnSystem = JOBSETUP_SYSTEM_MAC; 267 268 // get paper format 269 if( mpPrintInfo ) 270 { 271 NSSize aPaperSize = [mpPrintInfo paperSize]; 272 double width = aPaperSize.width, height = aPaperSize.height; 273 // set paper 274 io_pSetupData->mePaperFormat = recognizePaper( width, height ); 275 if( io_pSetupData->mePaperFormat == PAPER_USER ) 276 { 277 io_pSetupData->mnPaperWidth = PtTo10Mu( width ); 278 io_pSetupData->mnPaperHeight = PtTo10Mu( height ); 279 } 280 else 281 { 282 io_pSetupData->mnPaperWidth = 0; 283 io_pSetupData->mnPaperHeight = 0; 284 } 285 286 // set orientation 287 io_pSetupData->meOrientation = mePageOrientation; 288 289 io_pSetupData->mnPaperBin = 0; 290 io_pSetupData->mpDriverData = reinterpret_cast<sal_uInt8*>(rtl_allocateMemory( 4 )); 291 io_pSetupData->mnDriverDataLen = 4; 292 } 293 else 294 bSuccess = sal_False; 295 296 297 return bSuccess; 298 } 299 300 // ----------------------------------------------------------------------- 301 302 void AquaSalInfoPrinter::setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation ) 303 { 304 305 Orientation ePaperOrientation = ORIENTATION_PORTRAIT; 306 const PaperInfo* pPaper = matchPaper( i_nWidth, i_nHeight, ePaperOrientation ); 307 308 if( pPaper ) 309 { 310 NSString* pPaperName = [CreateNSString( rtl::OStringToOUString(PaperInfo::toPSName(pPaper->getPaper()), RTL_TEXTENCODING_ASCII_US) ) autorelease]; 311 [mpPrintInfo setPaperName: pPaperName]; 312 } 313 else if( i_nWidth > 0 && i_nHeight > 0 ) 314 { 315 NSSize aPaperSize = { TenMuToPt(i_nWidth), TenMuToPt(i_nHeight) }; 316 [mpPrintInfo setPaperSize: aPaperSize]; 317 } 318 // this seems counterintuitive 319 mePageOrientation = i_eSetOrientation; 320 } 321 322 // ----------------------------------------------------------------------- 323 324 sal_Bool AquaSalInfoPrinter::SetData( sal_uLong i_nFlags, ImplJobSetup* io_pSetupData ) 325 { 326 if( ! io_pSetupData || io_pSetupData->mnSystem != JOBSETUP_SYSTEM_MAC ) 327 return sal_False; 328 329 330 if( mpPrintInfo ) 331 { 332 if( (i_nFlags & SAL_JOBSET_ORIENTATION) != 0 ) 333 mePageOrientation = io_pSetupData->meOrientation; 334 335 if( (i_nFlags & SAL_JOBSET_PAPERSIZE) != 0) 336 { 337 // set paper format 338 long width = 21000, height = 29700; 339 if( io_pSetupData->mePaperFormat == PAPER_USER ) 340 { 341 // #i101108# sanity check 342 if( io_pSetupData->mnPaperWidth && io_pSetupData->mnPaperHeight ) 343 { 344 width = io_pSetupData->mnPaperWidth; 345 height = io_pSetupData->mnPaperHeight; 346 } 347 } 348 else 349 { 350 double w = 595, h = 842; 351 getPaperSize( w, h, io_pSetupData->mePaperFormat ); 352 width = static_cast<long>(PtTo10Mu( w )); 353 height = static_cast<long>(PtTo10Mu( h )); 354 } 355 356 setPaperSize( width, height, mePageOrientation ); 357 } 358 } 359 360 return mpPrintInfo != nil; 361 } 362 363 // ----------------------------------------------------------------------- 364 365 sal_uLong AquaSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* ) 366 { 367 return 0; 368 } 369 370 // ----------------------------------------------------------------------- 371 372 XubString AquaSalInfoPrinter::GetPaperBinName( const ImplJobSetup*, sal_uLong ) 373 { 374 return XubString(); 375 } 376 377 // ----------------------------------------------------------------------- 378 379 static bool getUseNativeDialog() 380 { 381 bool bNative = true; 382 try 383 { 384 // get service provider 385 uno::Reference< XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() ); 386 // create configuration hierachical access name 387 if( xSMgr.is() ) 388 { 389 try 390 { 391 uno::Reference< XMultiServiceFactory > xConfigProvider( 392 uno::Reference< XMultiServiceFactory >( 393 xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 394 "com.sun.star.configuration.ConfigurationProvider" ))), 395 UNO_QUERY ) 396 ); 397 if( xConfigProvider.is() ) 398 { 399 Sequence< Any > aArgs(1); 400 PropertyValue aVal; 401 aVal.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ); 402 aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) ); 403 aArgs.getArray()[0] <<= aVal; 404 uno::Reference< XNameAccess > xConfigAccess( 405 uno::Reference< XNameAccess >( 406 xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 407 "com.sun.star.configuration.ConfigurationAccess" )), 408 aArgs ), 409 UNO_QUERY ) 410 ); 411 if( xConfigAccess.is() ) 412 { 413 try 414 { 415 sal_Bool bValue = sal_False; 416 Any aAny = xConfigAccess->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseSystemPrintDialog" ) ) ); 417 if( aAny >>= bValue ) 418 bNative = bValue; 419 } 420 catch( NoSuchElementException& ) 421 { 422 } 423 catch( WrappedTargetException& ) 424 { 425 } 426 } 427 } 428 } 429 catch( Exception& ) 430 { 431 } 432 } 433 } 434 catch( WrappedTargetException& ) 435 { 436 } 437 438 return bNative; 439 } 440 441 sal_uLong AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup*, sal_uInt16 i_nType ) 442 { 443 switch( i_nType ) 444 { 445 case PRINTER_CAPABILITIES_SUPPORTDIALOG: 446 return 0; 447 case PRINTER_CAPABILITIES_COPIES: 448 return 0xffff; 449 case PRINTER_CAPABILITIES_COLLATECOPIES: 450 return 0xffff; 451 case PRINTER_CAPABILITIES_SETORIENTATION: 452 return 1; 453 case PRINTER_CAPABILITIES_SETDUPLEX: 454 return 0; 455 case PRINTER_CAPABILITIES_SETPAPERBIN: 456 return 0; 457 case PRINTER_CAPABILITIES_SETPAPERSIZE: 458 return 1; 459 case PRINTER_CAPABILITIES_SETPAPER: 460 return 1; 461 case PRINTER_CAPABILITIES_EXTERNALDIALOG: 462 return getUseNativeDialog() ? 1 : 0; 463 case PRINTER_CAPABILITIES_PDF: 464 return 1; 465 case PRINTER_CAPABILITIES_USEPULLMODEL: 466 return 1; 467 default: break; 468 }; 469 return 0; 470 } 471 472 // ----------------------------------------------------------------------- 473 474 void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup*, 475 long& o_rOutWidth, long& o_rOutHeight, 476 long& o_rPageOffX, long& o_rPageOffY, 477 long& o_rPageWidth, long& o_rPageHeight ) 478 { 479 if( mpPrintInfo ) 480 { 481 long nDPIX = 72, nDPIY = 72; 482 mpGraphics->GetResolution( nDPIX, nDPIY ); 483 const double fXScaling = static_cast<double>(nDPIX)/72.0, 484 fYScaling = static_cast<double>(nDPIY)/72.0; 485 486 NSSize aPaperSize = [mpPrintInfo paperSize]; 487 o_rPageWidth = static_cast<long>( double(aPaperSize.width) * fXScaling ); 488 o_rPageHeight = static_cast<long>( double(aPaperSize.height) * fYScaling ); 489 490 NSRect aImageRect = [mpPrintInfo imageablePageBounds]; 491 o_rPageOffX = static_cast<long>( aImageRect.origin.x * fXScaling ); 492 o_rPageOffY = static_cast<long>( (aPaperSize.height - aImageRect.size.height - aImageRect.origin.y) * fYScaling ); 493 o_rOutWidth = static_cast<long>( aImageRect.size.width * fXScaling ); 494 o_rOutHeight = static_cast<long>( aImageRect.size.height * fYScaling ); 495 496 if( mePageOrientation == ORIENTATION_LANDSCAPE ) 497 { 498 std::swap( o_rOutWidth, o_rOutHeight ); 499 std::swap( o_rPageWidth, o_rPageHeight ); 500 std::swap( o_rPageOffX, o_rPageOffY ); 501 } 502 } 503 } 504 505 static Size getPageSize( vcl::PrinterController& i_rController, sal_Int32 i_nPage ) 506 { 507 Size aPageSize; 508 Sequence< PropertyValue > aPageParms( i_rController.getPageParameters( i_nPage ) ); 509 for( sal_Int32 nProperty = 0, nPropertyCount = aPageParms.getLength(); nProperty < nPropertyCount; ++nProperty ) 510 { 511 if( aPageParms[ nProperty ].Name.equalsAscii( "PageSize" ) ) 512 { 513 awt::Size aSize; 514 aPageParms[ nProperty].Value >>= aSize; 515 aPageSize.Width() = aSize.Width; 516 aPageSize.Height() = aSize.Height; 517 break; 518 } 519 } 520 return aPageSize; 521 } 522 523 sal_Bool AquaSalInfoPrinter::StartJob( const String* i_pFileName, 524 const String& i_rJobName, 525 const String& /*i_rAppName*/, 526 ImplJobSetup* i_pSetupData, 527 vcl::PrinterController& i_rController 528 ) 529 { 530 if( mbJob ) 531 return sal_False; 532 533 sal_Bool bSuccess = sal_False; 534 bool bWasAborted = false; 535 AquaSalInstance* pInst = GetSalData()->mpFirstInstance; 536 PrintAccessoryViewState aAccViewState; 537 sal_Int32 nAllPages = 0; 538 539 // reset IsLastPage 540 i_rController.setLastPage( sal_False ); 541 542 // update job data 543 if( i_pSetupData ) 544 SetData( ~0, i_pSetupData ); 545 546 // do we want a progress panel ? 547 sal_Bool bShowProgressPanel = sal_True; 548 beans::PropertyValue* pMonitor = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) ); 549 if( pMonitor ) 550 pMonitor->Value >>= bShowProgressPanel; 551 if( ! i_rController.isShowDialogs() ) 552 bShowProgressPanel = sal_False; 553 554 // possibly create one job for collated output 555 sal_Bool bSinglePrintJobs = sal_False; 556 beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) ); 557 if( pSingleValue ) 558 { 559 pSingleValue->Value >>= bSinglePrintJobs; 560 } 561 562 // FIXME: jobStarted() should be done after the print dialog has ended (if there is one) 563 // how do I know when that might be ? 564 i_rController.jobStarted(); 565 566 567 int nCopies = i_rController.getPrinter()->GetCopyCount(); 568 int nJobs = 1; 569 if( bSinglePrintJobs ) 570 { 571 nJobs = nCopies; 572 nCopies = 1; 573 } 574 575 for( int nCurJob = 0; nCurJob < nJobs; nCurJob++ ) 576 { 577 aAccViewState.bNeedRestart = true; 578 do 579 { 580 if( aAccViewState.bNeedRestart ) 581 { 582 mnCurPageRangeStart = 0; 583 mnCurPageRangeCount = 0; 584 nAllPages = i_rController.getFilteredPageCount(); 585 } 586 587 aAccViewState.bNeedRestart = false; 588 589 Size aCurSize( 21000, 29700 ); 590 if( nAllPages > 0 ) 591 { 592 mnCurPageRangeCount = 1; 593 aCurSize = getPageSize( i_rController, mnCurPageRangeStart ); 594 Size aNextSize( aCurSize ); 595 596 // print pages up to a different size 597 while( mnCurPageRangeCount + mnCurPageRangeStart < nAllPages ) 598 { 599 aNextSize = getPageSize( i_rController, mnCurPageRangeStart + mnCurPageRangeCount ); 600 if( aCurSize == aNextSize // same page size 601 || 602 (aCurSize.Width() == aNextSize.Height() && aCurSize.Height() == aNextSize.Width()) // same size, but different orientation 603 ) 604 { 605 mnCurPageRangeCount++; 606 } 607 else 608 break; 609 } 610 } 611 else 612 mnCurPageRangeCount = 0; 613 614 // now for the current run 615 mnStartPageOffsetX = mnStartPageOffsetY = 0; 616 // setup the paper size and orientation 617 // do this on our associated Printer object, since that is 618 // out interface to the applications which occasionally rely on the paper 619 // information (e.g. brochure printing scales to the found paper size) 620 // also SetPaperSizeUser has the advantage that we can share a 621 // platform independent paper matching algorithm 622 boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() ); 623 pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); 624 pPrinter->SetPaperSizeUser( aCurSize, true ); 625 626 // create view 627 NSView* pPrintView = [[AquaPrintView alloc] initWithController: &i_rController withInfoPrinter: this]; 628 629 NSMutableDictionary* pPrintDict = [mpPrintInfo dictionary]; 630 631 // set filename 632 if( i_pFileName ) 633 { 634 [mpPrintInfo setJobDisposition: NSPrintSaveJob]; 635 NSString* pPath = CreateNSString( *i_pFileName ); 636 [pPrintDict setObject: pPath forKey: NSPrintSavePath]; 637 [pPath release]; 638 } 639 640 [pPrintDict setObject: [[NSNumber numberWithInt: nCopies] autorelease] forKey: NSPrintCopies]; 641 if( nCopies > 1 ) 642 [pPrintDict setObject: [[NSNumber numberWithBool: pPrinter->IsCollateCopy()] autorelease] forKey: NSPrintMustCollate]; 643 [pPrintDict setObject: [[NSNumber numberWithBool: YES] autorelease] forKey: NSPrintDetailedErrorReporting]; 644 [pPrintDict setObject: [[NSNumber numberWithInt: 1] autorelease] forKey: NSPrintFirstPage]; 645 // #i103253# weird: for some reason, autoreleasing the value below like the others above 646 // leads do a double free malloc error. Why this value should behave differently from all the others 647 // is a mystery. 648 [pPrintDict setObject: [NSNumber numberWithInt: mnCurPageRangeCount] forKey: NSPrintLastPage]; 649 650 651 // create print operation 652 NSPrintOperation* pPrintOperation = [NSPrintOperation printOperationWithView: pPrintView printInfo: mpPrintInfo]; 653 654 if( pPrintOperation ) 655 { 656 NSObject* pReleaseAfterUse = nil; 657 bool bShowPanel = (! i_rController.isDirectPrint() && getUseNativeDialog() && i_rController.isShowDialogs() ); 658 [pPrintOperation setShowsPrintPanel: bShowPanel ? YES : NO ]; 659 [pPrintOperation setShowsProgressPanel: bShowProgressPanel ? YES : NO]; 660 661 // set job title (since MacOSX 10.5) 662 if( [pPrintOperation respondsToSelector: @selector(setJobTitle:)] ) 663 [pPrintOperation performSelector: @selector(setJobTitle:) withObject: [CreateNSString( i_rJobName ) autorelease]]; 664 665 if( bShowPanel && mnCurPageRangeStart == 0 && nCurJob == 0) // only the first range of pages (in the first job) gets the accesory view 666 pReleaseAfterUse = [AquaPrintAccessoryView setupPrinterPanel: pPrintOperation withController: &i_rController withState: &aAccViewState]; 667 668 bSuccess = sal_True; 669 mbJob = true; 670 pInst->startedPrintJob(); 671 [pPrintOperation runOperation]; 672 pInst->endedPrintJob(); 673 bWasAborted = [[[pPrintOperation printInfo] jobDisposition] compare: NSPrintCancelJob] == NSOrderedSame; 674 mbJob = false; 675 if( pReleaseAfterUse ) 676 [pReleaseAfterUse release]; 677 } 678 679 mnCurPageRangeStart += mnCurPageRangeCount; 680 mnCurPageRangeCount = 1; 681 } while( aAccViewState.bNeedRestart || mnCurPageRangeStart + mnCurPageRangeCount < nAllPages ); 682 } 683 684 // inform application that it can release its data 685 // this is awkward, but the XRenderable interface has no method for this, 686 // so we need to call XRenderadble::render one last time with IsLastPage = sal_True 687 i_rController.setLastPage( sal_True ); 688 GDIMetaFile aPageFile; 689 if( mrContext ) 690 SetupPrinterGraphics( mrContext ); 691 i_rController.getFilteredPageFile( 0, aPageFile ); 692 693 i_rController.setJobState( bWasAborted 694 ? view::PrintableState_JOB_ABORTED 695 : view::PrintableState_JOB_SPOOLED ); 696 697 mnCurPageRangeStart = mnCurPageRangeCount = 0; 698 699 return bSuccess; 700 } 701 702 // ----------------------------------------------------------------------- 703 704 sal_Bool AquaSalInfoPrinter::EndJob() 705 { 706 mnStartPageOffsetX = mnStartPageOffsetY = 0; 707 mbJob = false; 708 return sal_True; 709 } 710 711 // ----------------------------------------------------------------------- 712 713 sal_Bool AquaSalInfoPrinter::AbortJob() 714 { 715 mbJob = false; 716 717 // FIXME: implementation 718 return sal_False; 719 } 720 721 // ----------------------------------------------------------------------- 722 723 SalGraphics* AquaSalInfoPrinter::StartPage( ImplJobSetup* i_pSetupData, sal_Bool i_bNewJobData ) 724 { 725 if( i_bNewJobData && i_pSetupData ) 726 SetPrinterData( i_pSetupData ); 727 728 CGContextRef rContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); 729 730 SetupPrinterGraphics( rContext ); 731 732 return mpGraphics; 733 } 734 735 // ----------------------------------------------------------------------- 736 737 sal_Bool AquaSalInfoPrinter::EndPage() 738 { 739 mpGraphics->InvalidateContext(); 740 return sal_True; 741 } 742 743 // ----------------------------------------------------------------------- 744 745 sal_uLong AquaSalInfoPrinter::GetErrorCode() const 746 { 747 return 0; 748 } 749 750 // ======================================================================= 751 752 AquaSalPrinter::AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter ) : 753 mpInfoPrinter( i_pInfoPrinter ) 754 { 755 } 756 757 // ----------------------------------------------------------------------- 758 759 AquaSalPrinter::~AquaSalPrinter() 760 { 761 } 762 763 // ----------------------------------------------------------------------- 764 765 sal_Bool AquaSalPrinter::StartJob( const String* i_pFileName, 766 const String& i_rJobName, 767 const String& i_rAppName, 768 ImplJobSetup* i_pSetupData, 769 vcl::PrinterController& i_rController ) 770 { 771 return mpInfoPrinter->StartJob( i_pFileName, i_rJobName, i_rAppName, i_pSetupData, i_rController ); 772 } 773 774 // ----------------------------------------------------------------------- 775 776 sal_Bool AquaSalPrinter::StartJob( const XubString* /*i_pFileName*/, 777 const XubString& /*i_rJobName*/, 778 const XubString& /*i_rAppName*/, 779 sal_uLong /*i_nCopies*/, 780 bool /*i_bCollate*/, 781 bool /*i_bDirect*/, 782 ImplJobSetup* ) 783 { 784 DBG_ERROR( "should never be called" ); 785 return sal_False; 786 } 787 788 // ----------------------------------------------------------------------- 789 790 sal_Bool AquaSalPrinter::EndJob() 791 { 792 return mpInfoPrinter->EndJob(); 793 } 794 795 // ----------------------------------------------------------------------- 796 797 sal_Bool AquaSalPrinter::AbortJob() 798 { 799 return mpInfoPrinter->AbortJob(); 800 } 801 802 // ----------------------------------------------------------------------- 803 804 SalGraphics* AquaSalPrinter::StartPage( ImplJobSetup* i_pSetupData, sal_Bool i_bNewJobData ) 805 { 806 return mpInfoPrinter->StartPage( i_pSetupData, i_bNewJobData ); 807 } 808 809 // ----------------------------------------------------------------------- 810 811 sal_Bool AquaSalPrinter::EndPage() 812 { 813 return mpInfoPrinter->EndPage(); 814 } 815 816 // ----------------------------------------------------------------------- 817 818 sal_uLong AquaSalPrinter::GetErrorCode() 819 { 820 return mpInfoPrinter->GetErrorCode(); 821 } 822 823 void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) 824 { 825 m_aPaperFormats.clear(); 826 m_bPapersInit = true; 827 828 if( mpPrinter ) 829 { 830 if( [mpPrinter statusForTable: @"PPD"] == NSPrinterTableOK ) 831 { 832 NSArray* pPaperNames = [mpPrinter stringListForKey: @"PageSize" inTable: @"PPD"]; 833 if( pPaperNames ) 834 { 835 unsigned int nPapers = [pPaperNames count]; 836 for( unsigned int i = 0; i < nPapers; i++ ) 837 { 838 NSString* pPaper = [pPaperNames objectAtIndex: i]; 839 // first try to match the name 840 rtl::OString aPaperName( [pPaper UTF8String] ); 841 Paper ePaper = PaperInfo::fromPSName( aPaperName ); 842 if( ePaper != PAPER_USER ) 843 { 844 m_aPaperFormats.push_back( PaperInfo( ePaper ) ); 845 } 846 else 847 { 848 NSSize aPaperSize = [mpPrinter pageSizeForPaper: pPaper]; 849 if( aPaperSize.width > 0 && aPaperSize.height > 0 ) 850 { 851 PaperInfo aInfo( PtTo10Mu( aPaperSize.width ), 852 PtTo10Mu( aPaperSize.height ) ); 853 if( aInfo.getPaper() == PAPER_USER ) 854 aInfo.doSloppyFit(); 855 m_aPaperFormats.push_back( aInfo ); 856 } 857 } 858 } 859 } 860 } 861 } 862 } 863 864 const PaperInfo* AquaSalInfoPrinter::matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const 865 { 866 if( ! m_bPapersInit ) 867 const_cast<AquaSalInfoPrinter*>(this)->InitPaperFormats( NULL ); 868 869 const PaperInfo* pMatch = NULL; 870 o_rOrientation = ORIENTATION_PORTRAIT; 871 for( int n = 0; n < 2 ; n++ ) 872 { 873 for( size_t i = 0; i < m_aPaperFormats.size(); i++ ) 874 { 875 if( abs( m_aPaperFormats[i].getWidth() - i_nWidth ) < 50 && 876 abs( m_aPaperFormats[i].getHeight() - i_nHeight ) < 50 ) 877 { 878 pMatch = &m_aPaperFormats[i]; 879 return pMatch; 880 } 881 } 882 o_rOrientation = ORIENTATION_LANDSCAPE; 883 std::swap( i_nWidth, i_nHeight ); 884 } 885 return pMatch; 886 } 887 888 int AquaSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* ) 889 { 890 return 900; 891 } 892 893 894