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