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