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 "tools/resary.hxx" 32 33#include "vcl/print.hxx" 34#include "vcl/image.hxx" 35#include "vcl/virdev.hxx" 36#include "vcl/svapp.hxx" 37#include "vcl/unohelp.hxx" 38 39#include "aqua/aquaprintview.h" 40#include "aqua/salinst.h" 41 42#include "svdata.hxx" 43#include "svids.hrc" 44 45#include "com/sun/star/i18n/XBreakIterator.hpp" 46#include "com/sun/star/i18n/WordType.hpp" 47 48#include <map> 49 50using namespace vcl; 51using namespace com::sun::star; 52using namespace com::sun::star::beans; 53using namespace com::sun::star::uno; 54 55/* Note: the accesory view as implemented here is already deprecated in Leopard. Unfortunately 56 as long as our baseline is Tiger we cannot gain the advantages over multiple accessory views 57 as well havs having accessory views AND a preview (as long as you are linked vs. 10.4 libraries 58 the preview insists on not being present. This is unfortunate. 59*/ 60 61class ControllerProperties; 62 63@interface ControlTarget : NSObject 64{ 65 ControllerProperties* mpController; 66} 67-(id)initWithControllerMap: (ControllerProperties*)pController; 68-(void)triggered:(id)pSender; 69-(void)triggeredNumeric:(id)pSender; 70-(void)triggeredPreview:(id)pSender; 71-(void)dealloc; 72@end 73 74 75class ControllerProperties 76{ 77 vcl::PrinterController* mpController; 78 std::map< int, rtl::OUString > maTagToPropertyName; 79 std::map< int, sal_Int32 > maTagToValueInt; 80 std::map< NSView*, NSView* > maViewPairMap; 81 std::vector< NSObject* > maViews; 82 int mnNextTag; 83 sal_Int32 mnLastPageCount; 84 PrintAccessoryViewState* mpState; 85 NSPrintOperation* mpOp; 86 NSView* mpAccessoryView; 87 NSTabView* mpTabView; 88 NSBox* mpPreviewBox; 89 NSImageView* mpPreview; 90 NSTextField* mpPageEdit; 91 NSStepper* mpStepper; 92 NSTextView* mpPagesLabel; 93 ResStringArray maLocalizedStrings; 94 95 public: 96 ControllerProperties( vcl::PrinterController* i_pController, 97 NSPrintOperation* i_pOp, 98 NSView* i_pAccessoryView, 99 NSTabView* i_pTabView, 100 PrintAccessoryViewState* i_pState ) 101 : mpController( i_pController ), 102 mnNextTag( 0 ), 103 mnLastPageCount( i_pController->getFilteredPageCount() ), 104 mpState( i_pState ), 105 mpOp( i_pOp ), 106 mpAccessoryView( i_pAccessoryView ), 107 mpTabView( i_pTabView ), 108 mpPreviewBox( nil ), 109 mpPreview( nil ), 110 mpPageEdit( nil ), 111 mpStepper( nil ), 112 mpPagesLabel( nil ), 113 maLocalizedStrings( VclResId( SV_PRINT_NATIVE_STRINGS ) ) 114 { 115 mpState->bNeedRestart = false; 116 DBG_ASSERT( maLocalizedStrings.Count() >= 5, "resources not found !" ); 117 } 118 119 rtl::OUString getMoreString() 120 { 121 return maLocalizedStrings.Count() >= 4 122 ? rtl::OUString( maLocalizedStrings.GetString( 3 ) ) 123 : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "More" ) ); 124 } 125 126 rtl::OUString getPrintSelectionString() 127 { 128 return maLocalizedStrings.Count() >= 5 129 ? rtl::OUString( maLocalizedStrings.GetString( 4 ) ) 130 : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Print selection only" ) ); 131 } 132 133 void updatePrintJob() 134 { 135 // TODO: refresh page count etc from mpController 136 137 // page range may have changed depending on options 138 sal_Int32 nPages = mpController->getFilteredPageCount(); 139 #if OSL_DEBUG_LEVEL > 1 140 if( nPages != mnLastPageCount ) 141 fprintf( stderr, "trouble: number of pages changed from %ld to %ld !\n", mnLastPageCount, nPages ); 142 #endif 143 mpState->bNeedRestart = (nPages != mnLastPageCount); 144 NSTabViewItem* pItem = [mpTabView selectedTabViewItem]; 145 if( pItem ) 146 mpState->nLastPage = [mpTabView indexOfTabViewItem: pItem]; 147 else 148 mpState->nLastPage = 0; 149 mnLastPageCount = nPages; 150 if( mpState->bNeedRestart ) 151 { 152 #if 0 153 // Warning: bad hack ahead 154 // Apple does not give us a chance of changing the page count, 155 // and they don't let us cancel the dialog either 156 // hack: send a cancel message to the window displaying our views. 157 // this is ugly. 158 for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it ) 159 { 160 if( [*it isKindOfClass: [NSView class]] ) 161 { 162 NSView* pView = (NSView*)*it; 163 NSWindow* pWindow = [pView window]; 164 if( pWindow ) 165 { 166 [pWindow cancelOperation: nil]; 167 break; 168 } 169 } 170 } 171 #else 172 NSWindow* pWindow = [NSApp modalWindow]; 173 if( pWindow ) 174 [pWindow cancelOperation: nil]; 175 #endif 176 [[mpOp printInfo] setJobDisposition: NSPrintCancelJob]; 177 } 178 else 179 { 180 sal_Int32 nPage = [mpStepper intValue]; 181 updatePreviewImage( nPage-1 ); 182 } 183 } 184 185 int addNameTag( const rtl::OUString& i_rPropertyName ) 186 { 187 int nNewTag = mnNextTag++; 188 maTagToPropertyName[ nNewTag ] = i_rPropertyName; 189 return nNewTag; 190 } 191 192 int addNameAndValueTag( const rtl::OUString& i_rPropertyName, sal_Int32 i_nValue ) 193 { 194 int nNewTag = mnNextTag++; 195 maTagToPropertyName[ nNewTag ] = i_rPropertyName; 196 maTagToValueInt[ nNewTag ] = i_nValue; 197 return nNewTag; 198 } 199 200 void addObservedControl( NSObject* i_pView ) 201 { 202 maViews.push_back( i_pView ); 203 } 204 205 void addViewPair( NSView* i_pLeft, NSView* i_pRight ) 206 { 207 maViewPairMap[ i_pLeft ] = i_pRight; 208 maViewPairMap[ i_pRight ] = i_pLeft; 209 } 210 211 NSView* getPair( NSView* i_pLeft ) const 212 { 213 NSView* pRight = nil; 214 std::map< NSView*, NSView* >::const_iterator it = maViewPairMap.find( i_pLeft ); 215 if( it != maViewPairMap.end() ) 216 pRight = it->second; 217 return pRight; 218 } 219 220 void changePropertyWithIntValue( int i_nTag ) 221 { 222 std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); 223 std::map< int, sal_Int32 >::const_iterator value_it = maTagToValueInt.find( i_nTag ); 224 if( name_it != maTagToPropertyName.end() && value_it != maTagToValueInt.end() ) 225 { 226 PropertyValue* pVal = mpController->getValue( name_it->second ); 227 if( pVal ) 228 { 229 pVal->Value <<= value_it->second; 230 updatePrintJob(); 231 } 232 } 233 } 234 235 void changePropertyWithIntValue( int i_nTag, sal_Int64 i_nValue ) 236 { 237 std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); 238 if( name_it != maTagToPropertyName.end() ) 239 { 240 PropertyValue* pVal = mpController->getValue( name_it->second ); 241 if( pVal ) 242 { 243 pVal->Value <<= i_nValue; 244 updatePrintJob(); 245 } 246 } 247 } 248 249 void changePropertyWithBoolValue( int i_nTag, sal_Bool i_bValue ) 250 { 251 std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); 252 if( name_it != maTagToPropertyName.end() ) 253 { 254 PropertyValue* pVal = mpController->getValue( name_it->second ); 255 if( pVal ) 256 { 257 // ugly 258 if( name_it->second.equalsAscii( "PrintContent" ) ) 259 pVal->Value <<= i_bValue ? sal_Int32(2) : sal_Int32(0); 260 else 261 pVal->Value <<= i_bValue; 262 updatePrintJob(); 263 } 264 } 265 } 266 267 void changePropertyWithStringValue( int i_nTag, const rtl::OUString& i_rValue ) 268 { 269 std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); 270 if( name_it != maTagToPropertyName.end() ) 271 { 272 PropertyValue* pVal = mpController->getValue( name_it->second ); 273 if( pVal ) 274 { 275 pVal->Value <<= i_rValue; 276 updatePrintJob(); 277 } 278 } 279 } 280 281 void updateEnableState() 282 { 283 for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it ) 284 { 285 NSObject* pObj = *it; 286 NSControl* pCtrl = nil; 287 NSCell* pCell = nil; 288 if( [pObj isKindOfClass: [NSControl class]] ) 289 pCtrl = (NSControl*)pObj; 290 else if( [pObj isKindOfClass: [NSCell class]] ) 291 pCell = (NSCell*)pObj; 292 293 int nTag = pCtrl ? [pCtrl tag] : 294 pCell ? [pCell tag] : 295 -1; 296 297 std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( nTag ); 298 if( name_it != maTagToPropertyName.end() && ! name_it->second.equalsAscii( "PrintContent" ) ) 299 { 300 BOOL bEnabled = mpController->isUIOptionEnabled( name_it->second ) ? YES : NO; 301 if( pCtrl ) 302 { 303 [pCtrl setEnabled: bEnabled]; 304 NSView* pOther = getPair( pCtrl ); 305 if( pOther && [pOther isKindOfClass: [NSControl class]] ) 306 [(NSControl*)pOther setEnabled: bEnabled]; 307 } 308 else if( pCell ) 309 [pCell setEnabled: bEnabled]; 310 311 } 312 } 313 } 314 315 void updatePreviewImage( sal_Int32 i_nPage ) 316 { 317 sal_Int32 nPages = mpController->getFilteredPageCount(); 318 NSRect aViewFrame = [mpPreview frame]; 319 Size aPixelSize( static_cast<long>(aViewFrame.size.width), 320 static_cast<long>(aViewFrame.size.height) ); 321 if( i_nPage >= 0 && nPages > i_nPage ) 322 { 323 GDIMetaFile aMtf; 324 PrinterController::PageSize aPageSize( mpController->getFilteredPageFile( i_nPage, aMtf, false ) ); 325 VirtualDevice aDev; 326 if( mpController->getPrinter()->GetPrinterOptions().IsConvertToGreyscales() ) 327 aDev.SetDrawMode( aDev.GetDrawMode() | ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | 328 DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); 329 // see salprn.cxx, currently we pretend to be a 720dpi device on printers 330 aDev.SetReferenceDevice( 720, 720 ); 331 aDev.EnableOutput( TRUE ); 332 Size aLogicSize( aDev.PixelToLogic( aPixelSize, MapMode( MAP_100TH_MM ) ) ); 333 double fScaleX = double(aLogicSize.Width())/double(aPageSize.aSize.Width()); 334 double fScaleY = double(aLogicSize.Height())/double(aPageSize.aSize.Height()); 335 double fScale = (fScaleX < fScaleY) ? fScaleX : fScaleY; 336 // #i104784# if we render the page too small then rounding issues result in 337 // layout artifacts looking really bad. So scale the page unto a device that is not 338 // full page size but not too small either. This also results in much better visual 339 // quality of the preview, e.g. when its height approaches the number of text lines 340 if( fScale < 0.1 ) 341 fScale = 0.1; 342 aMtf.WindStart(); 343 aMtf.Scale( fScale, fScale ); 344 aMtf.WindStart(); 345 aLogicSize.Width() = long(double(aPageSize.aSize.Width()) * fScale); 346 aLogicSize.Height() = long(double(aPageSize.aSize.Height()) * fScale); 347 aPixelSize = aDev.LogicToPixel( aLogicSize, MapMode( MAP_100TH_MM ) ); 348 aDev.SetOutputSizePixel( aPixelSize ); 349 aMtf.WindStart(); 350 aDev.SetMapMode( MapMode( MAP_100TH_MM ) ); 351 aMtf.Play( &aDev, Point( 0, 0 ), aLogicSize ); 352 aDev.EnableMapMode( FALSE ); 353 Image aImage( aDev.GetBitmap( Point( 0, 0 ), aPixelSize ) ); 354 NSImage* pImage = CreateNSImage( aImage ); 355 [mpPreview setImage: [pImage autorelease]]; 356 } 357 else 358 [mpPreview setImage: nil]; 359 } 360 361 void setupPreview( ControlTarget* i_pCtrlTarget ) 362 { 363 if( maLocalizedStrings.Count() < 3 ) 364 return; 365 366 // get the preview control 367 NSRect aPreviewFrame = [mpAccessoryView frame]; 368 aPreviewFrame.origin.x = 0; 369 aPreviewFrame.origin.y = 5; 370 aPreviewFrame.size.width = 190; 371 aPreviewFrame.size.height -= 7; 372 373 // create a box to put the preview controls in 374 mpPreviewBox = [[NSBox alloc] initWithFrame: aPreviewFrame]; 375 [mpPreviewBox setTitle: [CreateNSString( maLocalizedStrings.GetString( 0 ) ) autorelease]]; 376 [mpAccessoryView addSubview: [mpPreviewBox autorelease]]; 377 378 // now create the image view of the preview 379 NSSize aMargins = [mpPreviewBox contentViewMargins]; 380 aPreviewFrame.origin.x = 0; 381 aPreviewFrame.origin.y = 34; 382 aPreviewFrame.size.width -= 2*(aMargins.width+1); 383 aPreviewFrame.size.height -= 61; 384 mpPreview = [[NSImageView alloc] initWithFrame: aPreviewFrame]; 385 [mpPreview setImageScaling: NSScaleProportionally]; 386 [mpPreview setImageAlignment: NSImageAlignCenter]; 387 [mpPreview setImageFrameStyle: NSImageFrameNone]; 388 [mpPreviewBox addSubview: [mpPreview autorelease]]; 389 390 // add a label 391 sal_Int32 nPages = mpController->getFilteredPageCount(); 392 rtl::OUStringBuffer aBuf( 16 ); 393 aBuf.appendAscii( "/ " ); 394 aBuf.append( rtl::OUString::valueOf( nPages ) ); 395 396 NSString* pText = CreateNSString( aBuf.makeStringAndClear() ); 397 NSRect aTextRect = { { 100, 5 }, { 100, 22 } }; 398 mpPagesLabel = [[NSTextView alloc] initWithFrame: aTextRect]; 399 [mpPagesLabel setFont: [NSFont controlContentFontOfSize: 0]]; 400 [mpPagesLabel setEditable: NO]; 401 [mpPagesLabel setSelectable: NO]; 402 [mpPagesLabel setDrawsBackground: NO]; 403 [mpPagesLabel setString: [pText autorelease]]; 404 [mpPagesLabel setToolTip: [CreateNSString( maLocalizedStrings.GetString( 2 ) ) autorelease]]; 405 [mpPreviewBox addSubview: [mpPagesLabel autorelease]]; 406 407 NSRect aFieldRect = { { 45, 5 }, { 35, 25 } }; 408 mpPageEdit = [[NSTextField alloc] initWithFrame: aFieldRect]; 409 [mpPageEdit setEditable: YES]; 410 [mpPageEdit setSelectable: YES]; 411 [mpPageEdit setDrawsBackground: YES]; 412 [mpPageEdit setToolTip: [CreateNSString( maLocalizedStrings.GetString( 1 ) ) autorelease]]; 413 [mpPreviewBox addSubview: [mpPageEdit autorelease]]; 414 415 // add a stepper control 416 NSRect aStepFrame = { { 85, 5 }, { 15, 25 } }; 417 mpStepper = [[NSStepper alloc] initWithFrame: aStepFrame]; 418 [mpStepper setIncrement: 1]; 419 [mpStepper setValueWraps: NO]; 420 [mpPreviewBox addSubview: [mpStepper autorelease]]; 421 422 // constrain the text field to decimal numbers 423 NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init]; 424 [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4]; 425 [pFormatter setMinimum: [[NSNumber numberWithInt: 1] autorelease]]; 426 [pFormatter setMaximum: [[NSNumber numberWithInt: nPages] autorelease]]; 427 [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle]; 428 [pFormatter setAllowsFloats: NO]; 429 [pFormatter setMaximumFractionDigits: 0]; 430 [mpPageEdit setFormatter: pFormatter]; 431 [mpStepper setMinValue: 1]; 432 [mpStepper setMaxValue: nPages]; 433 434 [mpPageEdit setIntValue: 1]; 435 [mpStepper setIntValue: 1]; 436 437 // connect target and action 438 [mpStepper setTarget: i_pCtrlTarget]; 439 [mpStepper setAction: @selector(triggeredPreview:)]; 440 [mpPageEdit setTarget: i_pCtrlTarget]; 441 [mpPageEdit setAction: @selector(triggeredPreview:)]; 442 443 // set first preview image 444 updatePreviewImage( 0 ); 445 } 446 447 void changePreview( NSObject* i_pSender ) 448 { 449 if( [i_pSender isMemberOfClass: [NSTextField class]] ) 450 { 451 NSTextField* pField = (NSTextField*)i_pSender; 452 if( pField == mpPageEdit ) // sanity check 453 { 454 sal_Int32 nPage = [pField intValue]; 455 [mpStepper setIntValue: nPage]; 456 updatePreviewImage( nPage-1 ); 457 } 458 } 459 else if( [i_pSender isMemberOfClass: [NSStepper class]] ) 460 { 461 NSStepper* pStepper = (NSStepper*)i_pSender; 462 if( pStepper == mpStepper ) // sanity check 463 { 464 sal_Int32 nPage = [pStepper intValue]; 465 [mpPageEdit setIntValue: nPage]; 466 updatePreviewImage( nPage-1 ); 467 } 468 } 469 } 470}; 471 472static void filterAccelerator( rtl::OUString& io_rText ) 473{ 474 rtl::OUStringBuffer aBuf( io_rText.getLength() ); 475 for( sal_Int32 nIndex = 0; nIndex != -1; ) 476 aBuf.append( io_rText.getToken( 0, '~', nIndex ) ); 477 io_rText = aBuf.makeStringAndClear(); 478} 479 480@implementation ControlTarget 481-(id)initWithControllerMap: (ControllerProperties*)pController 482{ 483 if( (self = [super init]) ) 484 { 485 mpController = pController; 486 } 487 return self; 488} 489-(void)triggered:(id)pSender; 490{ 491 if( [pSender isMemberOfClass: [NSPopUpButton class]] ) 492 { 493 NSPopUpButton* pBtn = (NSPopUpButton*)pSender; 494 NSMenuItem* pSelected = [pBtn selectedItem]; 495 if( pSelected ) 496 { 497 int nTag = [pSelected tag]; 498 mpController->changePropertyWithIntValue( nTag ); 499 } 500 } 501 else if( [pSender isMemberOfClass: [NSButton class]] ) 502 { 503 NSButton* pBtn = (NSButton*)pSender; 504 int nTag = [pBtn tag]; 505 mpController->changePropertyWithBoolValue( nTag, [pBtn state] == NSOnState ); 506 } 507 else if( [pSender isMemberOfClass: [NSMatrix class]] ) 508 { 509 NSObject* pObj = [(NSMatrix*)pSender selectedCell]; 510 if( [pObj isMemberOfClass: [NSButtonCell class]] ) 511 { 512 NSButtonCell* pCell = (NSButtonCell*)pObj; 513 int nTag = [pCell tag]; 514 mpController->changePropertyWithIntValue( nTag ); 515 } 516 } 517 else if( [pSender isMemberOfClass: [NSTextField class]] ) 518 { 519 NSTextField* pField = (NSTextField*)pSender; 520 int nTag = [pField tag]; 521 rtl::OUString aValue = GetOUString( [pSender stringValue] ); 522 mpController->changePropertyWithStringValue( nTag, aValue ); 523 } 524 else 525 { 526 DBG_ERROR( "unsupported class" ); 527 } 528 mpController->updateEnableState(); 529} 530-(void)triggeredNumeric:(id)pSender; 531{ 532 if( [pSender isMemberOfClass: [NSTextField class]] ) 533 { 534 NSTextField* pField = (NSTextField*)pSender; 535 int nTag = [pField tag]; 536 sal_Int64 nValue = [pField intValue]; 537 538 NSView* pOther = mpController->getPair( pField ); 539 if( pOther ) 540 [(NSControl*)pOther setIntValue: nValue]; 541 542 mpController->changePropertyWithIntValue( nTag, nValue ); 543 } 544 else if( [pSender isMemberOfClass: [NSStepper class]] ) 545 { 546 NSStepper* pStep = (NSStepper*)pSender; 547 int nTag = [pStep tag]; 548 sal_Int64 nValue = [pStep intValue]; 549 550 NSView* pOther = mpController->getPair( pStep ); 551 if( pOther ) 552 [(NSControl*)pOther setIntValue: nValue]; 553 554 mpController->changePropertyWithIntValue( nTag, nValue ); 555 } 556 else 557 { 558 DBG_ERROR( "unsupported class" ); 559 } 560 mpController->updateEnableState(); 561} 562-(void)triggeredPreview:(id)pSender 563{ 564 mpController->changePreview( pSender ); 565} 566-(void)dealloc 567{ 568 delete mpController; 569 [super dealloc]; 570} 571@end 572 573struct ColumnItem 574{ 575 NSControl* pControl; 576 long nOffset; 577 NSControl* pSubControl; 578 579 ColumnItem( NSControl* i_pControl = nil, long i_nOffset = 0, NSControl* i_pSub = nil ) 580 : pControl( i_pControl ) 581 , nOffset( i_nOffset ) 582 , pSubControl( i_pSub ) 583 {} 584 585 long getWidth() const 586 { 587 long nWidth = 0; 588 if( pControl ) 589 { 590 NSRect aCtrlRect = [pControl frame]; 591 nWidth = aCtrlRect.size.width; 592 nWidth += nOffset; 593 if( pSubControl ) 594 { 595 NSRect aSubRect = [pSubControl frame]; 596 nWidth += aSubRect.size.width; 597 nWidth += aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width); 598 } 599 } 600 return nWidth; 601 } 602}; 603 604static void adjustViewAndChildren( NSView* pView, NSSize& rMaxSize, 605 std::vector< ColumnItem >& rLeftColumn, 606 std::vector< ColumnItem >& rRightColumn 607 ) 608{ 609 // balance columns 610 611 // first get overall column widths 612 long nLeftWidth = 0; 613 long nRightWidth = 0; 614 for( size_t i = 0; i < rLeftColumn.size(); i++ ) 615 { 616 long nW = rLeftColumn[i].getWidth(); 617 if( nW > nLeftWidth ) 618 nLeftWidth = nW; 619 } 620 for( size_t i = 0; i < rRightColumn.size(); i++ ) 621 { 622 long nW = rRightColumn[i].getWidth(); 623 if( nW > nRightWidth ) 624 nRightWidth = nW; 625 } 626 627 // right align left column 628 for( size_t i = 0; i < rLeftColumn.size(); i++ ) 629 { 630 if( rLeftColumn[i].pControl ) 631 { 632 NSRect aCtrlRect = [rLeftColumn[i].pControl frame]; 633 long nX = nLeftWidth - aCtrlRect.size.width; 634 if( rLeftColumn[i].pSubControl ) 635 { 636 NSRect aSubRect = [rLeftColumn[i].pSubControl frame]; 637 nX -= aSubRect.size.width + (aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width)); 638 aSubRect.origin.x = nLeftWidth - aSubRect.size.width; 639 [rLeftColumn[i].pSubControl setFrame: aSubRect]; 640 } 641 aCtrlRect.origin.x = nX; 642 [rLeftColumn[i].pControl setFrame: aCtrlRect]; 643 } 644 } 645 646 // left align right column 647 for( size_t i = 0; i < rRightColumn.size(); i++ ) 648 { 649 if( rRightColumn[i].pControl ) 650 { 651 NSRect aCtrlRect = [rRightColumn[i].pControl frame]; 652 long nX = nLeftWidth + 3; 653 if( rRightColumn[i].pSubControl ) 654 { 655 NSRect aSubRect = [rRightColumn[i].pSubControl frame]; 656 aSubRect.origin.x = nX + aSubRect.origin.x - aCtrlRect.origin.x; 657 [rRightColumn[i].pSubControl setFrame: aSubRect]; 658 } 659 aCtrlRect.origin.x = nX; 660 [rRightColumn[i].pControl setFrame: aCtrlRect]; 661 } 662 } 663 664 NSArray* pSubViews = [pView subviews]; 665 unsigned int nViews = [pSubViews count]; 666 NSRect aUnion = { { 0, 0 }, { 0, 0 } }; 667 668 // get the combined frame of all subviews 669 for( unsigned int n = 0; n < nViews; n++ ) 670 { 671 aUnion = NSUnionRect( aUnion, [[pSubViews objectAtIndex: n] frame] ); 672 } 673 674 // move everything so it will fit 675 for( unsigned int n = 0; n < nViews; n++ ) 676 { 677 NSView* pCurSubView = [pSubViews objectAtIndex: n]; 678 NSRect aFrame = [pCurSubView frame]; 679 aFrame.origin.x -= aUnion.origin.x - 5; 680 aFrame.origin.y -= aUnion.origin.y - 5; 681 [pCurSubView setFrame: aFrame]; 682 } 683 684 // resize the view itself 685 aUnion.size.height += 10; 686 aUnion.size.width += 20; 687 [pView setFrameSize: aUnion.size]; 688 689 if( aUnion.size.width > rMaxSize.width ) 690 rMaxSize.width = aUnion.size.width; 691 if( aUnion.size.height > rMaxSize.height ) 692 rMaxSize.height = aUnion.size.height; 693} 694 695static void adjustTabViews( NSTabView* pTabView, NSSize aTabSize ) 696{ 697 // loop over all contained tab pages 698 NSArray* pTabbedViews = [pTabView tabViewItems]; 699 int nViews = [pTabbedViews count]; 700 for( int i = 0; i < nViews; i++ ) 701 { 702 NSTabViewItem* pItem = (NSTabViewItem*)[pTabbedViews objectAtIndex: i]; 703 NSView* pView = [pItem view]; 704 if( pView ) 705 { 706 NSRect aRect = [pView frame]; 707 double nDiff = aTabSize.height - aRect.size.height; 708 aRect.size = aTabSize; 709 [pView setFrame: aRect]; 710 711 NSArray* pSubViews = [pView subviews]; 712 unsigned int nSubViews = [pSubViews count]; 713 714 // move everything up 715 for( unsigned int n = 0; n < nSubViews; n++ ) 716 { 717 NSView* pCurSubView = [pSubViews objectAtIndex: n]; 718 NSRect aFrame = [pCurSubView frame]; 719 aFrame.origin.y += nDiff; 720 // give separators the correct width 721 // separators are currently the only NSBoxes we use 722 if( [pCurSubView isMemberOfClass: [NSBox class]] ) 723 { 724 aFrame.size.width = aTabSize.width - aFrame.origin.x - 10; 725 } 726 [pCurSubView setFrame: aFrame]; 727 } 728 } 729 } 730} 731 732static NSControl* createLabel( const rtl::OUString& i_rText ) 733{ 734 NSString* pText = CreateNSString( i_rText ); 735 NSRect aTextRect = { { 0, 0 }, {20, 15} }; 736 NSTextField* pTextView = [[NSTextField alloc] initWithFrame: aTextRect]; 737 [pTextView setFont: [NSFont controlContentFontOfSize: 0]]; 738 [pTextView setEditable: NO]; 739 [pTextView setSelectable: NO]; 740 [pTextView setDrawsBackground: NO]; 741 [pTextView setBordered: NO]; 742 [pTextView setStringValue: pText]; 743 [pTextView sizeToFit]; 744 [pText release]; 745 return pTextView; 746} 747 748static sal_Int32 findBreak( const rtl::OUString& i_rText, sal_Int32 i_nPos ) 749{ 750 sal_Int32 nRet = i_rText.getLength(); 751 Reference< i18n::XBreakIterator > xBI( vcl::unohelper::CreateBreakIterator() ); 752 if( xBI.is() ) 753 { 754 i18n::Boundary aBoundary = xBI->getWordBoundary( i_rText, i_nPos, 755 Application::GetSettings().GetLocale(), 756 i18n::WordType::ANYWORD_IGNOREWHITESPACES, 757 sal_True ); 758 nRet = aBoundary.endPos; 759 } 760 return nRet; 761} 762 763static void linebreakCell( NSCell* pBtn, const rtl::OUString& i_rText ) 764{ 765 NSString* pText = CreateNSString( i_rText ); 766 [pBtn setTitle: pText]; 767 [pText release]; 768 NSSize aSize = [pBtn cellSize]; 769 if( aSize.width > 280 ) 770 { 771 // need two lines 772 sal_Int32 nLen = i_rText.getLength(); 773 sal_Int32 nIndex = nLen / 2; 774 nIndex = findBreak( i_rText, nIndex ); 775 if( nIndex < nLen ) 776 { 777 rtl::OUStringBuffer aBuf( i_rText ); 778 aBuf.setCharAt( nIndex, '\n' ); 779 pText = CreateNSString( aBuf.makeStringAndClear() ); 780 [pBtn setTitle: pText]; 781 [pText release]; 782 } 783 } 784} 785 786static void addSubgroup( NSView* pCurParent, long& rCurY, const rtl::OUString& rText ) 787{ 788 NSControl* pTextView = createLabel( rText ); 789 [pCurParent addSubview: [pTextView autorelease]]; 790 NSRect aTextRect = [pTextView frame]; 791 // move to nCurY 792 aTextRect.origin.y = rCurY - aTextRect.size.height; 793 [pTextView setFrame: aTextRect]; 794 795 NSRect aSepRect = { { aTextRect.size.width + 1, aTextRect.origin.y }, { 100, 6 } }; 796 NSBox* pBox = [[NSBox alloc] initWithFrame: aSepRect]; 797 [pBox setBoxType: NSBoxSeparator]; 798 [pCurParent addSubview: [pBox autorelease]]; 799 800 // update nCurY 801 rCurY = aTextRect.origin.y - 5; 802} 803 804static void addBool( NSView* pCurParent, long& rCurX, long& rCurY, long nAttachOffset, 805 const rtl::OUString& rText, sal_Bool bEnabled, 806 const rtl::OUString& rProperty, sal_Bool bValue, 807 std::vector<ColumnItem >& rRightColumn, 808 ControllerProperties* pControllerProperties, 809 ControlTarget* pCtrlTarget 810 ) 811{ 812 NSRect aCheckRect = { { rCurX + nAttachOffset, 0 }, { 0, 15 } }; 813 NSButton* pBtn = [[NSButton alloc] initWithFrame: aCheckRect]; 814 [pBtn setButtonType: NSSwitchButton]; 815 [pBtn setState: bValue ? NSOnState : NSOffState]; 816 if( ! bEnabled ) 817 [pBtn setEnabled: NO]; 818 linebreakCell( [pBtn cell], rText ); 819 [pBtn sizeToFit]; 820 821 rRightColumn.push_back( ColumnItem( pBtn ) ); 822 823 // connect target 824 [pBtn setTarget: pCtrlTarget]; 825 [pBtn setAction: @selector(triggered:)]; 826 int nTag = pControllerProperties->addNameTag( rProperty ); 827 pControllerProperties->addObservedControl( pBtn ); 828 [pBtn setTag: nTag]; 829 830 aCheckRect = [pBtn frame]; 831 // #i115837# add a murphy factor; it can apparently occasionally happen 832 // that sizeToFit does not a perfect job and that the button linebreaks again 833 // if - and only if - there is already a '\n' contained in the text and the width 834 // is minimally of 835 aCheckRect.size.width += 1; 836 837 // move to rCurY 838 aCheckRect.origin.y = rCurY - aCheckRect.size.height; 839 [pBtn setFrame: aCheckRect]; 840 841 [pCurParent addSubview: [pBtn autorelease]]; 842 843 // update rCurY 844 rCurY = aCheckRect.origin.y - 5; 845} 846 847static void addRadio( NSView* pCurParent, long& rCurX, long& rCurY, long nAttachOffset, 848 const rtl::OUString& rText, 849 const rtl::OUString& rProperty, Sequence< rtl::OUString > rChoices, sal_Int32 nSelectValue, 850 std::vector<ColumnItem >& rLeftColumn, 851 std::vector<ColumnItem >& rRightColumn, 852 ControllerProperties* pControllerProperties, 853 ControlTarget* pCtrlTarget 854 ) 855{ 856 sal_Int32 nOff = 0; 857 if( rText.getLength() ) 858 { 859 // add a label 860 NSControl* pTextView = createLabel( rText ); 861 NSRect aTextRect = [pTextView frame]; 862 aTextRect.origin.x = rCurX + nAttachOffset; 863 [pCurParent addSubview: [pTextView autorelease]]; 864 865 rLeftColumn.push_back( ColumnItem( pTextView ) ); 866 867 // move to nCurY 868 aTextRect.origin.y = rCurY - aTextRect.size.height; 869 [pTextView setFrame: aTextRect]; 870 871 // update nCurY 872 rCurY = aTextRect.origin.y - 5; 873 874 // indent the radio group relative to the text 875 // nOff = 20; 876 } 877 878 // setup radio matrix 879 NSButtonCell* pProto = [[NSButtonCell alloc] init]; 880 881 NSRect aRadioRect = { { rCurX + nOff, 0 }, { 280 - rCurX, 5*rChoices.getLength() } }; 882 [pProto setTitle: @"RadioButtonGroup"]; 883 [pProto setButtonType: NSRadioButton]; 884 NSMatrix* pMatrix = [[NSMatrix alloc] initWithFrame: aRadioRect 885 mode: NSRadioModeMatrix 886 prototype: (NSCell*)pProto 887 numberOfRows: rChoices.getLength() 888 numberOfColumns: 1]; 889 // set individual titles 890 NSArray* pCells = [pMatrix cells]; 891 for( sal_Int32 m = 0; m < rChoices.getLength(); m++ ) 892 { 893 NSCell* pCell = [pCells objectAtIndex: m]; 894 filterAccelerator( rChoices[m] ); 895 linebreakCell( pCell, rChoices[m] ); 896 // connect target and action 897 [pCell setTarget: pCtrlTarget]; 898 [pCell setAction: @selector(triggered:)]; 899 int nTag = pControllerProperties->addNameAndValueTag( rProperty, m ); 900 pControllerProperties->addObservedControl( pCell ); 901 [pCell setTag: nTag]; 902 // set current selection 903 if( nSelectValue == m ) 904 [pMatrix selectCellAtRow: m column: 0]; 905 } 906 [pMatrix sizeToFit]; 907 aRadioRect = [pMatrix frame]; 908 909 // move it down, so it comes to the correct position 910 aRadioRect.origin.y = rCurY - aRadioRect.size.height; 911 [pMatrix setFrame: aRadioRect]; 912 [pCurParent addSubview: [pMatrix autorelease]]; 913 914 rRightColumn.push_back( ColumnItem( pMatrix ) ); 915 916 // update nCurY 917 rCurY = aRadioRect.origin.y - 5; 918 919 [pProto release]; 920} 921 922static void addList( NSView* pCurParent, long& rCurX, long& rCurY, long /*nAttachOffset*/, 923 const rtl::OUString& rText, 924 const rtl::OUString& rProperty, const Sequence< rtl::OUString > rChoices, sal_Int32 nSelectValue, 925 std::vector<ColumnItem >& rLeftColumn, 926 std::vector<ColumnItem >& rRightColumn, 927 ControllerProperties* pControllerProperties, 928 ControlTarget* pCtrlTarget 929 ) 930{ 931 // don't indent attached lists, looks bad in the existing cases 932 NSControl* pTextView = createLabel( rText ); 933 [pCurParent addSubview: [pTextView autorelease]]; 934 rLeftColumn.push_back( ColumnItem( pTextView ) ); 935 NSRect aTextRect = [pTextView frame]; 936 aTextRect.origin.x = rCurX /* + nAttachOffset*/; 937 938 // don't indent attached lists, looks bad in the existing cases 939 NSRect aBtnRect = { { rCurX /*+ nAttachOffset*/ + aTextRect.size.width, 0 }, { 0, 15 } }; 940 NSPopUpButton* pBtn = [[NSPopUpButton alloc] initWithFrame: aBtnRect pullsDown: NO]; 941 942 // iterate options 943 for( sal_Int32 m = 0; m < rChoices.getLength(); m++ ) 944 { 945 NSString* pItemText = CreateNSString( rChoices[m] ); 946 [pBtn addItemWithTitle: pItemText]; 947 NSMenuItem* pItem = [pBtn itemWithTitle: pItemText]; 948 int nTag = pControllerProperties->addNameAndValueTag( rProperty, m ); 949 [pItem setTag: nTag]; 950 [pItemText release]; 951 } 952 953 [pBtn selectItemAtIndex: nSelectValue]; 954 955 // add the button to observed controls for enabled state changes 956 // also add a tag just for this purpose 957 pControllerProperties->addObservedControl( pBtn ); 958 [pBtn setTag: pControllerProperties->addNameTag( rProperty )]; 959 960 [pBtn sizeToFit]; 961 [pCurParent addSubview: [pBtn autorelease]]; 962 963 rRightColumn.push_back( ColumnItem( pBtn ) ); 964 965 // connect target and action 966 [pBtn setTarget: pCtrlTarget]; 967 [pBtn setAction: @selector(triggered:)]; 968 969 // move to nCurY 970 aBtnRect = [pBtn frame]; 971 aBtnRect.origin.y = rCurY - aBtnRect.size.height; 972 [pBtn setFrame: aBtnRect]; 973 974 // align label 975 aTextRect.origin.y = aBtnRect.origin.y + (aBtnRect.size.height - aTextRect.size.height)/2; 976 [pTextView setFrame: aTextRect]; 977 978 // update rCurY 979 rCurY = aBtnRect.origin.y - 5; 980} 981 982static void addEdit( NSView* pCurParent, long& rCurX, long& rCurY, long nAttachOffset, 983 const rtl::OUString rCtrlType, 984 const rtl::OUString& rText, 985 const rtl::OUString& rProperty, const PropertyValue* pValue, 986 sal_Int64 nMinValue, sal_Int64 nMaxValue, 987 std::vector<ColumnItem >& rLeftColumn, 988 std::vector<ColumnItem >& rRightColumn, 989 ControllerProperties* pControllerProperties, 990 ControlTarget* pCtrlTarget 991 ) 992{ 993 sal_Int32 nOff = 0; 994 if( rText.getLength() ) 995 { 996 // add a label 997 NSControl* pTextView = createLabel( rText ); 998 [pCurParent addSubview: [pTextView autorelease]]; 999 1000 rLeftColumn.push_back( ColumnItem( pTextView ) ); 1001 1002 // move to nCurY 1003 NSRect aTextRect = [pTextView frame]; 1004 aTextRect.origin.x = rCurX + nAttachOffset; 1005 aTextRect.origin.y = rCurY - aTextRect.size.height; 1006 [pTextView setFrame: aTextRect]; 1007 1008 // update nCurY 1009 rCurY = aTextRect.origin.y - 5; 1010 1011 // and set the offset for the real edit field 1012 nOff = aTextRect.size.width + 5; 1013 } 1014 1015 NSRect aFieldRect = { { rCurX + nOff + nAttachOffset, 0 }, { 100, 25 } }; 1016 NSTextField* pFieldView = [[NSTextField alloc] initWithFrame: aFieldRect]; 1017 [pFieldView setEditable: YES]; 1018 [pFieldView setSelectable: YES]; 1019 [pFieldView setDrawsBackground: YES]; 1020 [pFieldView sizeToFit]; // FIXME: this does nothing 1021 [pCurParent addSubview: [pFieldView autorelease]]; 1022 1023 rRightColumn.push_back( ColumnItem( pFieldView ) ); 1024 1025 // add the field to observed controls for enabled state changes 1026 // also add a tag just for this purpose 1027 pControllerProperties->addObservedControl( pFieldView ); 1028 int nTag = pControllerProperties->addNameTag( rProperty ); 1029 [pFieldView setTag: nTag]; 1030 // pControllerProperties->addNamedView( pFieldView, aPropertyName ); 1031 1032 // move to nCurY 1033 aFieldRect.origin.y = rCurY - aFieldRect.size.height; 1034 [pFieldView setFrame: aFieldRect]; 1035 1036 if( rCtrlType.equalsAscii( "Range" ) ) 1037 { 1038 // add a stepper control 1039 NSRect aStepFrame = { { aFieldRect.origin.x + aFieldRect.size.width + 5, 1040 aFieldRect.origin.y }, 1041 { 15, aFieldRect.size.height } }; 1042 NSStepper* pStep = [[NSStepper alloc] initWithFrame: aStepFrame]; 1043 [pStep setIncrement: 1]; 1044 [pStep setValueWraps: NO]; 1045 [pStep setTag: nTag]; 1046 [pCurParent addSubview: [pStep autorelease]]; 1047 1048 rRightColumn.back().pSubControl = pStep; 1049 1050 pControllerProperties->addObservedControl( pStep ); 1051 [pStep setTarget: pCtrlTarget]; 1052 [pStep setAction: @selector(triggered:)]; 1053 1054 // constrain the text field to decimal numbers 1055 NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init]; 1056 [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4]; 1057 [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle]; 1058 [pFormatter setAllowsFloats: NO]; 1059 [pFormatter setMaximumFractionDigits: 0]; 1060 if( nMinValue != nMaxValue ) 1061 { 1062 [pFormatter setMinimum: [[NSNumber numberWithInt: nMinValue] autorelease]]; 1063 [pStep setMinValue: nMinValue]; 1064 [pFormatter setMaximum: [[NSNumber numberWithInt: nMaxValue] autorelease]]; 1065 [pStep setMaxValue: nMaxValue]; 1066 } 1067 [pFieldView setFormatter: pFormatter]; 1068 1069 sal_Int64 nSelectVal = 0; 1070 if( pValue && pValue->Value.hasValue() ) 1071 pValue->Value >>= nSelectVal; 1072 1073 [pFieldView setIntValue: nSelectVal]; 1074 [pStep setIntValue: nSelectVal]; 1075 1076 pControllerProperties->addViewPair( pFieldView, pStep ); 1077 // connect target and action 1078 [pFieldView setTarget: pCtrlTarget]; 1079 [pFieldView setAction: @selector(triggeredNumeric:)]; 1080 [pStep setTarget: pCtrlTarget]; 1081 [pStep setAction: @selector(triggeredNumeric:)]; 1082 } 1083 else 1084 { 1085 // connect target and action 1086 [pFieldView setTarget: pCtrlTarget]; 1087 [pFieldView setAction: @selector(triggered:)]; 1088 1089 if( pValue && pValue->Value.hasValue() ) 1090 { 1091 rtl::OUString aValue; 1092 pValue->Value >>= aValue; 1093 if( aValue.getLength() ) 1094 { 1095 NSString* pText = CreateNSString( aValue ); 1096 [pFieldView setStringValue: pText]; 1097 [pText release]; 1098 } 1099 } 1100 } 1101 1102 // update nCurY 1103 rCurY = aFieldRect.origin.y - 5; 1104} 1105 1106@implementation AquaPrintAccessoryView 1107+(NSObject*)setupPrinterPanel: (NSPrintOperation*)pOp withController: (vcl::PrinterController*)pController withState: (PrintAccessoryViewState*)pState; 1108{ 1109 const Sequence< PropertyValue >& rOptions( pController->getUIOptions() ); 1110 if( rOptions.getLength() == 0 ) 1111 return nil; 1112 1113 NSView* pCurParent = 0; 1114 long nCurY = 0; 1115 long nCurX = 0; 1116 NSRect aViewFrame = { { 0, 0 }, {600, 400 } }; 1117 NSRect aTabViewFrame = { { 190, 0 }, {410, 400 } }; 1118 NSSize aMaxTabSize = { 0, 0 }; 1119 NSView* pAccessoryView = [[NSView alloc] initWithFrame: aViewFrame]; 1120 NSTabView* pTabView = [[NSTabView alloc] initWithFrame: aTabViewFrame]; 1121 [pAccessoryView addSubview: [pTabView autorelease]]; 1122 1123 sal_Bool bIgnoreSubgroup = sal_False; 1124 1125 ControllerProperties* pControllerProperties = new ControllerProperties( pController, pOp, pAccessoryView, pTabView, pState ); 1126 ControlTarget* pCtrlTarget = [[ControlTarget alloc] initWithControllerMap: pControllerProperties]; 1127 1128 std::vector< ColumnItem > aLeftColumn, aRightColumn; 1129 1130 // ugly: 1131 // prepend a "selection" checkbox if the properties have such a selection in PrintContent 1132 bool bAddSelectionCheckBox = false, bSelectionBoxEnabled = false, bSelectionBoxChecked = false; 1133 for( int i = 0; i < rOptions.getLength(); i++ ) 1134 { 1135 Sequence< beans::PropertyValue > aOptProp; 1136 rOptions[i].Value >>= aOptProp; 1137 1138 rtl::OUString aCtrlType; 1139 rtl::OUString aPropertyName; 1140 Sequence< rtl::OUString > aChoices; 1141 Sequence< sal_Bool > aChoicesDisabled; 1142 sal_Int32 aSelectionChecked = 0; 1143 for( int n = 0; n < aOptProp.getLength(); n++ ) 1144 { 1145 const beans::PropertyValue& rEntry( aOptProp[ n ] ); 1146 if( rEntry.Name.equalsAscii( "ControlType" ) ) 1147 { 1148 rEntry.Value >>= aCtrlType; 1149 } 1150 else if( rEntry.Name.equalsAscii( "Choices" ) ) 1151 { 1152 rEntry.Value >>= aChoices; 1153 } 1154 else if( rEntry.Name.equalsAscii( "ChoicesDisabled" ) ) 1155 { 1156 rEntry.Value >>= aChoicesDisabled; 1157 } 1158 else if( rEntry.Name.equalsAscii( "Property" ) ) 1159 { 1160 PropertyValue aVal; 1161 rEntry.Value >>= aVal; 1162 aPropertyName = aVal.Name; 1163 if( aPropertyName.equalsAscii( "PrintContent" ) ) 1164 aVal.Value >>= aSelectionChecked; 1165 } 1166 } 1167 if( aCtrlType.equalsAscii( "Radio" ) && 1168 aPropertyName.equalsAscii( "PrintContent" ) && 1169 aChoices.getLength() > 2 ) 1170 { 1171 bAddSelectionCheckBox = true; 1172 bSelectionBoxEnabled = aChoicesDisabled.getLength() < 2 || ! aChoicesDisabled[2]; 1173 bSelectionBoxChecked = (aSelectionChecked==2); 1174 break; 1175 } 1176 } 1177 1178 for( int i = 0; i < rOptions.getLength(); i++ ) 1179 { 1180 Sequence< beans::PropertyValue > aOptProp; 1181 rOptions[i].Value >>= aOptProp; 1182 1183 // extract ui element 1184 bool bEnabled = true; 1185 rtl::OUString aCtrlType; 1186 rtl::OUString aText; 1187 rtl::OUString aPropertyName; 1188 rtl::OUString aGroupHint; 1189 Sequence< rtl::OUString > aChoices; 1190 sal_Int64 nMinValue = 0, nMaxValue = 0; 1191 long nAttachOffset = 0; 1192 sal_Bool bIgnore = sal_False; 1193 1194 for( int n = 0; n < aOptProp.getLength(); n++ ) 1195 { 1196 const beans::PropertyValue& rEntry( aOptProp[ n ] ); 1197 if( rEntry.Name.equalsAscii( "Text" ) ) 1198 { 1199 rEntry.Value >>= aText; 1200 filterAccelerator( aText ); 1201 } 1202 else if( rEntry.Name.equalsAscii( "ControlType" ) ) 1203 { 1204 rEntry.Value >>= aCtrlType; 1205 } 1206 else if( rEntry.Name.equalsAscii( "Choices" ) ) 1207 { 1208 rEntry.Value >>= aChoices; 1209 } 1210 else if( rEntry.Name.equalsAscii( "Property" ) ) 1211 { 1212 PropertyValue aVal; 1213 rEntry.Value >>= aVal; 1214 aPropertyName = aVal.Name; 1215 } 1216 else if( rEntry.Name.equalsAscii( "Enabled" ) ) 1217 { 1218 sal_Bool bValue = sal_True; 1219 rEntry.Value >>= bValue; 1220 bEnabled = bValue; 1221 } 1222 else if( rEntry.Name.equalsAscii( "MinValue" ) ) 1223 { 1224 rEntry.Value >>= nMinValue; 1225 } 1226 else if( rEntry.Name.equalsAscii( "MaxValue" ) ) 1227 { 1228 rEntry.Value >>= nMaxValue; 1229 } 1230 else if( rEntry.Name.equalsAscii( "AttachToDependency" ) ) 1231 { 1232 nAttachOffset = 20; 1233 } 1234 else if( rEntry.Name.equalsAscii( "InternalUIOnly" ) ) 1235 { 1236 rEntry.Value >>= bIgnore; 1237 } 1238 else if( rEntry.Name.equalsAscii( "GroupingHint" ) ) 1239 { 1240 rEntry.Value >>= aGroupHint; 1241 } 1242 } 1243 1244 if( aCtrlType.equalsAscii( "Group" ) || 1245 aCtrlType.equalsAscii( "Subgroup" ) || 1246 aCtrlType.equalsAscii( "Radio" ) || 1247 aCtrlType.equalsAscii( "List" ) || 1248 aCtrlType.equalsAscii( "Edit" ) || 1249 aCtrlType.equalsAscii( "Range" ) || 1250 aCtrlType.equalsAscii( "Bool" ) ) 1251 { 1252 // since our build target is MacOSX 10.4 we can have only one accessory view 1253 // so we have a single accessory view that is tabbed for grouping 1254 if( aCtrlType.equalsAscii( "Group" ) 1255 || ! pCurParent 1256 || ( aCtrlType.equalsAscii( "Subgroup" ) && nCurY < -250 && ! bIgnore ) 1257 ) 1258 { 1259 rtl::OUString aGroupTitle( aText ); 1260 if( aCtrlType.equalsAscii( "Subgroup" ) ) 1261 aGroupTitle = pControllerProperties->getMoreString(); 1262 // set size of current parent 1263 if( pCurParent ) 1264 adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn ); 1265 1266 // new tab item 1267 if( ! aText.getLength() ) 1268 aText = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OOo" ) ); 1269 NSString* pLabel = CreateNSString( aGroupTitle ); 1270 NSTabViewItem* pItem = [[NSTabViewItem alloc] initWithIdentifier: pLabel ]; 1271 [pItem setLabel: pLabel]; 1272 [pTabView addTabViewItem: pItem]; 1273 pCurParent = [[NSView alloc] initWithFrame: aTabViewFrame]; 1274 [pItem setView: pCurParent]; 1275 [pLabel release]; 1276 1277 // reset indent 1278 nCurX = 20; 1279 // reset Y 1280 nCurY = 0; 1281 // clear columns 1282 aLeftColumn.clear(); 1283 aRightColumn.clear(); 1284 1285 if( bAddSelectionCheckBox ) 1286 { 1287 addBool( pCurParent, nCurX, nCurY, 0, 1288 pControllerProperties->getPrintSelectionString(), bSelectionBoxEnabled, 1289 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintContent" ) ), bSelectionBoxChecked, 1290 aRightColumn, pControllerProperties, pCtrlTarget ); 1291 bAddSelectionCheckBox = false; 1292 } 1293 } 1294 1295 if( aCtrlType.equalsAscii( "Subgroup" ) && pCurParent ) 1296 { 1297 bIgnoreSubgroup = bIgnore; 1298 if( bIgnore ) 1299 continue; 1300 1301 addSubgroup( pCurParent, nCurY, aText ); 1302 } 1303 else if( bIgnoreSubgroup || bIgnore ) 1304 { 1305 continue; 1306 } 1307 else if( aCtrlType.equalsAscii( "Bool" ) && pCurParent ) 1308 { 1309 sal_Bool bVal = sal_False; 1310 PropertyValue* pVal = pController->getValue( aPropertyName ); 1311 if( pVal ) 1312 pVal->Value >>= bVal; 1313 addBool( pCurParent, nCurX, nCurY, nAttachOffset, 1314 aText, true, aPropertyName, bVal, 1315 aRightColumn, pControllerProperties, pCtrlTarget ); 1316 } 1317 else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent ) 1318 { 1319 // get currently selected value 1320 sal_Int32 nSelectVal = 0; 1321 PropertyValue* pVal = pController->getValue( aPropertyName ); 1322 if( pVal && pVal->Value.hasValue() ) 1323 pVal->Value >>= nSelectVal; 1324 1325 addRadio( pCurParent, nCurX, nCurY, nAttachOffset, 1326 aText, aPropertyName, aChoices, nSelectVal, 1327 aLeftColumn, aRightColumn, 1328 pControllerProperties, pCtrlTarget ); 1329 } 1330 else if( aCtrlType.equalsAscii( "List" ) && pCurParent ) 1331 { 1332 PropertyValue* pVal = pController->getValue( aPropertyName ); 1333 sal_Int32 aSelectVal = 0; 1334 if( pVal && pVal->Value.hasValue() ) 1335 pVal->Value >>= aSelectVal; 1336 1337 addList( pCurParent, nCurX, nCurY, nAttachOffset, 1338 aText, aPropertyName, aChoices, aSelectVal, 1339 aLeftColumn, aRightColumn, 1340 pControllerProperties, pCtrlTarget ); 1341 } 1342 else if( (aCtrlType.equalsAscii( "Edit" ) || aCtrlType.equalsAscii( "Range" )) && pCurParent ) 1343 { 1344 // current value 1345 PropertyValue* pVal = pController->getValue( aPropertyName ); 1346 addEdit( pCurParent, nCurX, nCurY, nAttachOffset, 1347 aCtrlType, aText, aPropertyName, pVal, 1348 nMinValue, nMaxValue, 1349 aLeftColumn, aRightColumn, 1350 pControllerProperties, pCtrlTarget ); 1351 } 1352 } 1353 else 1354 { 1355 DBG_ERROR( "Unsupported UI option" ); 1356 } 1357 } 1358 1359 pControllerProperties->updateEnableState(); 1360 adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn ); 1361 1362 // leave some space for the preview 1363 if( aMaxTabSize.height < 200 ) 1364 aMaxTabSize.height = 200; 1365 1366 // now reposition everything again so it is upper bound 1367 adjustTabViews( pTabView, aMaxTabSize ); 1368 1369 // find the minimum needed tab size 1370 NSSize aTabCtrlSize = [pTabView minimumSize]; 1371 aTabCtrlSize.height += aMaxTabSize.height + 10; 1372 if( aTabCtrlSize.width < aMaxTabSize.width + 10 ) 1373 aTabCtrlSize.width = aMaxTabSize.width + 10; 1374 [pTabView setFrameSize: aTabCtrlSize]; 1375 aViewFrame.size.width = aTabCtrlSize.width + aTabViewFrame.origin.x; 1376 aViewFrame.size.height = aTabCtrlSize.height + aTabViewFrame.origin.y; 1377 [pAccessoryView setFrameSize: aViewFrame.size]; 1378 1379 pControllerProperties->setupPreview( pCtrlTarget ); 1380 1381 // set the accessory view 1382 [pOp setAccessoryView: [pAccessoryView autorelease]]; 1383 1384 // set the current selecte tab item 1385 if( pState->nLastPage >= 0 && pState->nLastPage < [pTabView numberOfTabViewItems] ) 1386 [pTabView selectTabViewItemAtIndex: pState->nLastPage]; 1387 1388 return pCtrlTarget; 1389} 1390 1391@end 1392