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