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