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