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