| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include "tools/resary.hxx" |
| |
| #include "vcl/print.hxx" |
| #include "vcl/image.hxx" |
| #include "vcl/virdev.hxx" |
| #include "vcl/svapp.hxx" |
| #include "vcl/unohelp.hxx" |
| |
| #include "aqua/aquaprintview.h" |
| #include "aqua/salinst.h" |
| |
| #include "svdata.hxx" |
| #include "svids.hrc" |
| |
| #include "com/sun/star/i18n/XBreakIterator.hpp" |
| #include "com/sun/star/i18n/WordType.hpp" |
| |
| #include <map> |
| |
| using namespace vcl; |
| using namespace com::sun::star; |
| using namespace com::sun::star::beans; |
| using namespace com::sun::star::uno; |
| |
| /* Note: the accesory view as implemented here is already deprecated in Leopard. Unfortunately |
| as long as our baseline is Tiger we cannot gain the advantages over multiple accessory views |
| as well havs having accessory views AND a preview (as long as you are linked vs. 10.4 libraries |
| the preview insists on not being present. This is unfortunate. |
| */ |
| |
| class ControllerProperties; |
| |
| @interface ControlTarget : NSObject |
| { |
| ControllerProperties* mpController; |
| } |
| -(id)initWithControllerMap: (ControllerProperties*)pController; |
| -(void)triggered:(id)pSender; |
| -(void)triggeredNumeric:(id)pSender; |
| -(void)triggeredPreview:(id)pSender; |
| -(void)dealloc; |
| @end |
| |
| |
| class ControllerProperties |
| { |
| vcl::PrinterController* mpController; |
| std::map< int, rtl::OUString > maTagToPropertyName; |
| std::map< int, sal_Int32 > maTagToValueInt; |
| std::map< NSView*, NSView* > maViewPairMap; |
| std::vector< NSObject* > maViews; |
| int mnNextTag; |
| sal_Int32 mnLastPageCount; |
| PrintAccessoryViewState* mpState; |
| NSPrintOperation* mpOp; |
| NSView* mpAccessoryView; |
| NSTabView* mpTabView; |
| NSBox* mpPreviewBox; |
| NSImageView* mpPreview; |
| NSTextField* mpPageEdit; |
| NSStepper* mpStepper; |
| NSTextView* mpPagesLabel; |
| ResStringArray maLocalizedStrings; |
| |
| public: |
| ControllerProperties( vcl::PrinterController* i_pController, |
| NSPrintOperation* i_pOp, |
| NSView* i_pAccessoryView, |
| NSTabView* i_pTabView, |
| PrintAccessoryViewState* i_pState ) |
| : mpController( i_pController ), |
| mnNextTag( 0 ), |
| mnLastPageCount( i_pController->getFilteredPageCount() ), |
| mpState( i_pState ), |
| mpOp( i_pOp ), |
| mpAccessoryView( i_pAccessoryView ), |
| mpTabView( i_pTabView ), |
| mpPreviewBox( nil ), |
| mpPreview( nil ), |
| mpPageEdit( nil ), |
| mpStepper( nil ), |
| mpPagesLabel( nil ), |
| maLocalizedStrings( VclResId( SV_PRINT_NATIVE_STRINGS ) ) |
| { |
| mpState->bNeedRestart = false; |
| DBG_ASSERT( maLocalizedStrings.Count() >= 5, "resources not found !" ); |
| } |
| |
| rtl::OUString getMoreString() |
| { |
| return maLocalizedStrings.Count() >= 4 |
| ? rtl::OUString( maLocalizedStrings.GetString( 3 ) ) |
| : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "More" ) ); |
| } |
| |
| rtl::OUString getPrintSelectionString() |
| { |
| return maLocalizedStrings.Count() >= 5 |
| ? rtl::OUString( maLocalizedStrings.GetString( 4 ) ) |
| : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Print selection only" ) ); |
| } |
| |
| void updatePrintJob() |
| { |
| // TODO: refresh page count etc from mpController |
| |
| // page range may have changed depending on options |
| sal_Int32 nPages = mpController->getFilteredPageCount(); |
| #if OSL_DEBUG_LEVEL > 1 |
| if( nPages != mnLastPageCount ) |
| fprintf( stderr, "trouble: number of pages changed from %ld to %ld !\n", mnLastPageCount, nPages ); |
| #endif |
| mpState->bNeedRestart = (nPages != mnLastPageCount); |
| NSTabViewItem* pItem = [mpTabView selectedTabViewItem]; |
| if( pItem ) |
| mpState->nLastPage = [mpTabView indexOfTabViewItem: pItem]; |
| else |
| mpState->nLastPage = 0; |
| mnLastPageCount = nPages; |
| if( mpState->bNeedRestart ) |
| { |
| // Warning: bad hack ahead |
| // Apple does not give us a chance of changing the page count, |
| // and they don't let us cancel the dialog either |
| // hack: send a cancel message to the window displaying our views. |
| // this is ugly. |
| NSWindow* pNSWindow = [NSApp modalWindow]; |
| if( pNSWindow ) |
| [pNSWindow cancelOperation: nil]; |
| [[mpOp printInfo] setJobDisposition: NSPrintCancelJob]; |
| } |
| else |
| { |
| sal_Int32 nPage = [mpStepper intValue]; |
| updatePreviewImage( nPage-1 ); |
| } |
| } |
| |
| int addNameTag( const rtl::OUString& i_rPropertyName ) |
| { |
| int nNewTag = mnNextTag++; |
| maTagToPropertyName[ nNewTag ] = i_rPropertyName; |
| return nNewTag; |
| } |
| |
| int addNameAndValueTag( const rtl::OUString& i_rPropertyName, sal_Int32 i_nValue ) |
| { |
| int nNewTag = mnNextTag++; |
| maTagToPropertyName[ nNewTag ] = i_rPropertyName; |
| maTagToValueInt[ nNewTag ] = i_nValue; |
| return nNewTag; |
| } |
| |
| void addObservedControl( NSObject* i_pView ) |
| { |
| maViews.push_back( i_pView ); |
| } |
| |
| void addViewPair( NSView* i_pLeft, NSView* i_pRight ) |
| { |
| maViewPairMap[ i_pLeft ] = i_pRight; |
| maViewPairMap[ i_pRight ] = i_pLeft; |
| } |
| |
| NSView* getPair( NSView* i_pLeft ) const |
| { |
| NSView* pRight = nil; |
| std::map< NSView*, NSView* >::const_iterator it = maViewPairMap.find( i_pLeft ); |
| if( it != maViewPairMap.end() ) |
| pRight = it->second; |
| return pRight; |
| } |
| |
| void changePropertyWithIntValue( int i_nTag ) |
| { |
| std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); |
| std::map< int, sal_Int32 >::const_iterator value_it = maTagToValueInt.find( i_nTag ); |
| if( name_it != maTagToPropertyName.end() && value_it != maTagToValueInt.end() ) |
| { |
| PropertyValue* pVal = mpController->getValue( name_it->second ); |
| if( pVal ) |
| { |
| pVal->Value <<= value_it->second; |
| updatePrintJob(); |
| } |
| } |
| } |
| |
| void changePropertyWithIntValue( int i_nTag, sal_Int64 i_nValue ) |
| { |
| std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); |
| if( name_it != maTagToPropertyName.end() ) |
| { |
| PropertyValue* pVal = mpController->getValue( name_it->second ); |
| if( pVal ) |
| { |
| pVal->Value <<= i_nValue; |
| updatePrintJob(); |
| } |
| } |
| } |
| |
| void changePropertyWithBoolValue( int i_nTag, sal_Bool i_bValue ) |
| { |
| std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); |
| if( name_it != maTagToPropertyName.end() ) |
| { |
| PropertyValue* pVal = mpController->getValue( name_it->second ); |
| if( pVal ) |
| { |
| // ugly |
| if( name_it->second.equalsAscii( "PrintContent" ) ) |
| pVal->Value <<= i_bValue ? sal_Int32(2) : sal_Int32(0); |
| else |
| pVal->Value <<= i_bValue; |
| updatePrintJob(); |
| } |
| } |
| } |
| |
| void changePropertyWithStringValue( int i_nTag, const rtl::OUString& i_rValue ) |
| { |
| std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); |
| if( name_it != maTagToPropertyName.end() ) |
| { |
| PropertyValue* pVal = mpController->getValue( name_it->second ); |
| if( pVal ) |
| { |
| pVal->Value <<= i_rValue; |
| updatePrintJob(); |
| } |
| } |
| } |
| |
| void updateEnableState() |
| { |
| for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it ) |
| { |
| NSObject* pObj = *it; |
| NSControl* pCtrl = nil; |
| NSCell* pCell = nil; |
| if( [pObj isKindOfClass: [NSControl class]] ) |
| pCtrl = (NSControl*)pObj; |
| else if( [pObj isKindOfClass: [NSCell class]] ) |
| pCell = (NSCell*)pObj; |
| |
| int nTag = pCtrl ? [pCtrl tag] : |
| pCell ? [pCell tag] : |
| -1; |
| |
| std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( nTag ); |
| if( name_it != maTagToPropertyName.end() && ! name_it->second.equalsAscii( "PrintContent" ) ) |
| { |
| BOOL bEnabled = mpController->isUIOptionEnabled( name_it->second ) ? YES : NO; |
| if( pCtrl ) |
| { |
| [pCtrl setEnabled: bEnabled]; |
| NSView* pOther = getPair( pCtrl ); |
| if( pOther && [pOther isKindOfClass: [NSControl class]] ) |
| [(NSControl*)pOther setEnabled: bEnabled]; |
| } |
| else if( pCell ) |
| [pCell setEnabled: bEnabled]; |
| |
| } |
| } |
| } |
| |
| void updatePreviewImage( sal_Int32 i_nPage ) |
| { |
| sal_Int32 nPages = mpController->getFilteredPageCount(); |
| NSRect aViewFrame = [mpPreview frame]; |
| Size aPixelSize( static_cast<long>(aViewFrame.size.width), |
| static_cast<long>(aViewFrame.size.height) ); |
| if( i_nPage >= 0 && nPages > i_nPage ) |
| { |
| GDIMetaFile aMtf; |
| PrinterController::PageSize aPageSize( mpController->getFilteredPageFile( i_nPage, aMtf, false ) ); |
| VirtualDevice aDev; |
| if( mpController->getPrinter()->GetPrinterOptions().IsConvertToGreyscales() ) |
| aDev.SetDrawMode( aDev.GetDrawMode() | ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | |
| DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); |
| // see salprn.cxx, currently we pretend to be a 720dpi device on printers |
| aDev.SetReferenceDevice( 720, 720 ); |
| aDev.EnableOutput( TRUE ); |
| Size aLogicSize( aDev.PixelToLogic( aPixelSize, MapMode( MAP_100TH_MM ) ) ); |
| double fScaleX = double(aLogicSize.Width())/double(aPageSize.aSize.Width()); |
| double fScaleY = double(aLogicSize.Height())/double(aPageSize.aSize.Height()); |
| double fScale = (fScaleX < fScaleY) ? fScaleX : fScaleY; |
| // #i104784# if we render the page too small then rounding issues result in |
| // layout artifacts looking really bad. So scale the page unto a device that is not |
| // full page size but not too small either. This also results in much better visual |
| // quality of the preview, e.g. when its height approaches the number of text lines |
| if( fScale < 0.1 ) |
| fScale = 0.1; |
| aMtf.WindStart(); |
| aMtf.Scale( fScale, fScale ); |
| aMtf.WindStart(); |
| aLogicSize.Width() = long(double(aPageSize.aSize.Width()) * fScale); |
| aLogicSize.Height() = long(double(aPageSize.aSize.Height()) * fScale); |
| aPixelSize = aDev.LogicToPixel( aLogicSize, MapMode( MAP_100TH_MM ) ); |
| aDev.SetOutputSizePixel( aPixelSize ); |
| aMtf.WindStart(); |
| aDev.SetMapMode( MapMode( MAP_100TH_MM ) ); |
| aMtf.Play( &aDev, Point( 0, 0 ), aLogicSize ); |
| aDev.EnableMapMode( FALSE ); |
| Image aImage( aDev.GetBitmap( Point( 0, 0 ), aPixelSize ) ); |
| NSImage* pImage = CreateNSImage( aImage ); |
| [mpPreview setImage: [pImage autorelease]]; |
| } |
| else |
| [mpPreview setImage: nil]; |
| } |
| |
| void setupPreview( ControlTarget* i_pCtrlTarget ) |
| { |
| if( maLocalizedStrings.Count() < 3 ) |
| return; |
| |
| // get the preview control |
| NSRect aPreviewFrame = [mpAccessoryView frame]; |
| aPreviewFrame.origin.x = 0; |
| aPreviewFrame.origin.y = 5; |
| aPreviewFrame.size.width = 190; |
| aPreviewFrame.size.height -= 7; |
| |
| // create a box to put the preview controls in |
| mpPreviewBox = [[NSBox alloc] initWithFrame: aPreviewFrame]; |
| [mpPreviewBox setTitle: [CreateNSString( maLocalizedStrings.GetString( 0 ) ) autorelease]]; |
| [mpAccessoryView addSubview: [mpPreviewBox autorelease]]; |
| |
| // now create the image view of the preview |
| NSSize aMargins = [mpPreviewBox contentViewMargins]; |
| aPreviewFrame.origin.x = 0; |
| aPreviewFrame.origin.y = 34; |
| aPreviewFrame.size.width -= 2*(aMargins.width+1); |
| aPreviewFrame.size.height -= 61; |
| mpPreview = [[NSImageView alloc] initWithFrame: aPreviewFrame]; |
| [mpPreview setImageScaling: NSScaleProportionally]; |
| [mpPreview setImageAlignment: NSImageAlignCenter]; |
| [mpPreview setImageFrameStyle: NSImageFrameNone]; |
| [mpPreviewBox addSubview: [mpPreview autorelease]]; |
| |
| // add a label |
| sal_Int32 nPages = mpController->getFilteredPageCount(); |
| rtl::OUStringBuffer aBuf( 16 ); |
| aBuf.appendAscii( "/ " ); |
| aBuf.append( rtl::OUString::valueOf( nPages ) ); |
| |
| NSString* pText = CreateNSString( aBuf.makeStringAndClear() ); |
| NSRect aTextRect = { { 100, 5 }, { 100, 22 } }; |
| mpPagesLabel = [[NSTextView alloc] initWithFrame: aTextRect]; |
| [mpPagesLabel setFont: [NSFont controlContentFontOfSize: 0]]; |
| [mpPagesLabel setEditable: NO]; |
| [mpPagesLabel setSelectable: NO]; |
| [mpPagesLabel setDrawsBackground: NO]; |
| [mpPagesLabel setString: [pText autorelease]]; |
| [mpPagesLabel setToolTip: [CreateNSString( maLocalizedStrings.GetString( 2 ) ) autorelease]]; |
| [mpPreviewBox addSubview: [mpPagesLabel autorelease]]; |
| |
| NSRect aFieldRect = { { 45, 5 }, { 35, 25 } }; |
| mpPageEdit = [[NSTextField alloc] initWithFrame: aFieldRect]; |
| [mpPageEdit setEditable: YES]; |
| [mpPageEdit setSelectable: YES]; |
| [mpPageEdit setDrawsBackground: YES]; |
| [mpPageEdit setToolTip: [CreateNSString( maLocalizedStrings.GetString( 1 ) ) autorelease]]; |
| [mpPreviewBox addSubview: [mpPageEdit autorelease]]; |
| |
| // add a stepper control |
| NSRect aStepFrame = { { 85, 5 }, { 15, 25 } }; |
| mpStepper = [[NSStepper alloc] initWithFrame: aStepFrame]; |
| [mpStepper setIncrement: 1]; |
| [mpStepper setValueWraps: NO]; |
| [mpPreviewBox addSubview: [mpStepper autorelease]]; |
| |
| // constrain the text field to decimal numbers |
| NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init]; |
| [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4]; |
| [pFormatter setMinimum: [[NSNumber numberWithInt: 1] autorelease]]; |
| [pFormatter setMaximum: [[NSNumber numberWithInt: nPages] autorelease]]; |
| [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle]; |
| [pFormatter setAllowsFloats: NO]; |
| [pFormatter setMaximumFractionDigits: 0]; |
| [mpPageEdit setFormatter: pFormatter]; |
| [mpStepper setMinValue: 1]; |
| [mpStepper setMaxValue: nPages]; |
| |
| [mpPageEdit setIntValue: 1]; |
| [mpStepper setIntValue: 1]; |
| |
| // connect target and action |
| [mpStepper setTarget: i_pCtrlTarget]; |
| [mpStepper setAction: @selector(triggeredPreview:)]; |
| [mpPageEdit setTarget: i_pCtrlTarget]; |
| [mpPageEdit setAction: @selector(triggeredPreview:)]; |
| |
| // set first preview image |
| updatePreviewImage( 0 ); |
| } |
| |
| void changePreview( NSObject* i_pSender ) |
| { |
| if( [i_pSender isMemberOfClass: [NSTextField class]] ) |
| { |
| NSTextField* pField = (NSTextField*)i_pSender; |
| if( pField == mpPageEdit ) // sanity check |
| { |
| sal_Int32 nPage = [pField intValue]; |
| [mpStepper setIntValue: nPage]; |
| updatePreviewImage( nPage-1 ); |
| } |
| } |
| else if( [i_pSender isMemberOfClass: [NSStepper class]] ) |
| { |
| NSStepper* pStepper = (NSStepper*)i_pSender; |
| if( pStepper == mpStepper ) // sanity check |
| { |
| sal_Int32 nPage = [pStepper intValue]; |
| [mpPageEdit setIntValue: nPage]; |
| updatePreviewImage( nPage-1 ); |
| } |
| } |
| } |
| }; |
| |
| static void filterAccelerator( rtl::OUString& io_rText ) |
| { |
| rtl::OUStringBuffer aBuf( io_rText.getLength() ); |
| for( sal_Int32 nIndex = 0; nIndex != -1; ) |
| aBuf.append( io_rText.getToken( 0, '~', nIndex ) ); |
| io_rText = aBuf.makeStringAndClear(); |
| } |
| |
| @implementation ControlTarget |
| -(id)initWithControllerMap: (ControllerProperties*)pController |
| { |
| if( (self = [super init]) ) |
| { |
| mpController = pController; |
| } |
| return self; |
| } |
| -(void)triggered:(id)pSender |
| { |
| if( [pSender isMemberOfClass: [NSPopUpButton class]] ) |
| { |
| NSPopUpButton* pBtn = (NSPopUpButton*)pSender; |
| NSMenuItem* pSelected = [pBtn selectedItem]; |
| if( pSelected ) |
| { |
| int nTag = [pSelected tag]; |
| mpController->changePropertyWithIntValue( nTag ); |
| } |
| } |
| else if( [pSender isMemberOfClass: [NSButton class]] ) |
| { |
| NSButton* pBtn = (NSButton*)pSender; |
| int nTag = [pBtn tag]; |
| mpController->changePropertyWithBoolValue( nTag, [pBtn state] == NSOnState ); |
| } |
| else if( [pSender isMemberOfClass: [NSMatrix class]] ) |
| { |
| NSObject* pObj = [(NSMatrix*)pSender selectedCell]; |
| if( [pObj isMemberOfClass: [NSButtonCell class]] ) |
| { |
| NSButtonCell* pCell = (NSButtonCell*)pObj; |
| int nTag = [pCell tag]; |
| mpController->changePropertyWithIntValue( nTag ); |
| } |
| } |
| else if( [pSender isMemberOfClass: [NSTextField class]] ) |
| { |
| NSTextField* pField = (NSTextField*)pSender; |
| int nTag = [pField tag]; |
| rtl::OUString aValue = GetOUString( [pSender stringValue] ); |
| mpController->changePropertyWithStringValue( nTag, aValue ); |
| } |
| else |
| { |
| DBG_ERROR( "unsupported class" ); |
| } |
| mpController->updateEnableState(); |
| } |
| -(void)triggeredNumeric:(id)pSender |
| { |
| if( [pSender isMemberOfClass: [NSTextField class]] ) |
| { |
| NSTextField* pField = (NSTextField*)pSender; |
| int nTag = [pField tag]; |
| sal_Int64 nValue = [pField intValue]; |
| |
| NSView* pOther = mpController->getPair( pField ); |
| if( pOther ) |
| [(NSControl*)pOther setIntValue: nValue]; |
| |
| mpController->changePropertyWithIntValue( nTag, nValue ); |
| } |
| else if( [pSender isMemberOfClass: [NSStepper class]] ) |
| { |
| NSStepper* pStep = (NSStepper*)pSender; |
| int nTag = [pStep tag]; |
| sal_Int64 nValue = [pStep intValue]; |
| |
| NSView* pOther = mpController->getPair( pStep ); |
| if( pOther ) |
| [(NSControl*)pOther setIntValue: nValue]; |
| |
| mpController->changePropertyWithIntValue( nTag, nValue ); |
| } |
| else |
| { |
| DBG_ERROR( "unsupported class" ); |
| } |
| mpController->updateEnableState(); |
| } |
| -(void)triggeredPreview:(id)pSender |
| { |
| mpController->changePreview( pSender ); |
| } |
| -(void)dealloc |
| { |
| delete mpController; |
| [super dealloc]; |
| } |
| @end |
| |
| struct ColumnItem |
| { |
| NSControl* pControl; |
| long nOffset; |
| NSControl* pSubControl; |
| |
| ColumnItem( NSControl* i_pControl = nil, long i_nOffset = 0, NSControl* i_pSub = nil ) |
| : pControl( i_pControl ) |
| , nOffset( i_nOffset ) |
| , pSubControl( i_pSub ) |
| {} |
| |
| long getWidth() const |
| { |
| long nWidth = 0; |
| if( pControl ) |
| { |
| NSRect aCtrlRect = [pControl frame]; |
| nWidth = aCtrlRect.size.width; |
| nWidth += nOffset; |
| if( pSubControl ) |
| { |
| NSRect aSubRect = [pSubControl frame]; |
| nWidth += aSubRect.size.width; |
| nWidth += aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width); |
| } |
| } |
| return nWidth; |
| } |
| }; |
| |
| static void adjustViewAndChildren( NSView* pNSView, NSSize& rMaxSize, |
| std::vector< ColumnItem >& rLeftColumn, |
| std::vector< ColumnItem >& rRightColumn |
| ) |
| { |
| // balance columns |
| |
| // first get overall column widths |
| long nLeftWidth = 0; |
| long nRightWidth = 0; |
| for( size_t i = 0; i < rLeftColumn.size(); i++ ) |
| { |
| long nW = rLeftColumn[i].getWidth(); |
| if( nW > nLeftWidth ) |
| nLeftWidth = nW; |
| } |
| for( size_t i = 0; i < rRightColumn.size(); i++ ) |
| { |
| long nW = rRightColumn[i].getWidth(); |
| if( nW > nRightWidth ) |
| nRightWidth = nW; |
| } |
| |
| // right align left column |
| for( size_t i = 0; i < rLeftColumn.size(); i++ ) |
| { |
| if( rLeftColumn[i].pControl ) |
| { |
| NSRect aCtrlRect = [rLeftColumn[i].pControl frame]; |
| long nX = nLeftWidth - aCtrlRect.size.width; |
| if( rLeftColumn[i].pSubControl ) |
| { |
| NSRect aSubRect = [rLeftColumn[i].pSubControl frame]; |
| nX -= aSubRect.size.width + (aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width)); |
| aSubRect.origin.x = nLeftWidth - aSubRect.size.width; |
| [rLeftColumn[i].pSubControl setFrame: aSubRect]; |
| } |
| aCtrlRect.origin.x = nX; |
| [rLeftColumn[i].pControl setFrame: aCtrlRect]; |
| } |
| } |
| |
| // left align right column |
| for( size_t i = 0; i < rRightColumn.size(); i++ ) |
| { |
| if( rRightColumn[i].pControl ) |
| { |
| NSRect aCtrlRect = [rRightColumn[i].pControl frame]; |
| long nX = nLeftWidth + 3; |
| if( rRightColumn[i].pSubControl ) |
| { |
| NSRect aSubRect = [rRightColumn[i].pSubControl frame]; |
| aSubRect.origin.x = nX + aSubRect.origin.x - aCtrlRect.origin.x; |
| [rRightColumn[i].pSubControl setFrame: aSubRect]; |
| } |
| aCtrlRect.origin.x = nX; |
| [rRightColumn[i].pControl setFrame: aCtrlRect]; |
| } |
| } |
| |
| NSArray* pSubViews = [pNSView subviews]; |
| unsigned int nViews = [pSubViews count]; |
| NSRect aUnion = NSZeroRect; |
| |
| // get the combined frame of all subviews |
| for( unsigned int n = 0; n < nViews; n++ ) |
| { |
| aUnion = NSUnionRect( aUnion, [[pSubViews objectAtIndex: n] frame] ); |
| } |
| |
| // move everything so it will fit |
| for( unsigned int n = 0; n < nViews; n++ ) |
| { |
| NSView* pCurSubView = [pSubViews objectAtIndex: n]; |
| NSRect aFrame = [pCurSubView frame]; |
| aFrame.origin.x -= aUnion.origin.x - 5; |
| aFrame.origin.y -= aUnion.origin.y - 5; |
| [pCurSubView setFrame: aFrame]; |
| } |
| |
| // resize the view itself |
| aUnion.size.height += 10; |
| aUnion.size.width += 20; |
| [pNSView setFrameSize: aUnion.size]; |
| |
| if( aUnion.size.width > rMaxSize.width ) |
| rMaxSize.width = aUnion.size.width; |
| if( aUnion.size.height > rMaxSize.height ) |
| rMaxSize.height = aUnion.size.height; |
| } |
| |
| static void adjustTabViews( NSTabView* pTabView, NSSize aTabSize ) |
| { |
| // loop over all contained tab pages |
| NSArray* pTabbedViews = [pTabView tabViewItems]; |
| int nViews = [pTabbedViews count]; |
| for( int i = 0; i < nViews; i++ ) |
| { |
| NSTabViewItem* pItem = (NSTabViewItem*)[pTabbedViews objectAtIndex: i]; |
| NSView* pNSView = [pItem view]; |
| if( pNSView ) |
| { |
| NSRect aRect = [pNSView frame]; |
| double nDiff = aTabSize.height - aRect.size.height; |
| aRect.size = aTabSize; |
| [pNSView setFrame: aRect]; |
| |
| NSArray* pSubViews = [pNSView subviews]; |
| unsigned int nSubViews = [pSubViews count]; |
| |
| // move everything up |
| for( unsigned int n = 0; n < nSubViews; n++ ) |
| { |
| NSView* pCurSubView = [pSubViews objectAtIndex: n]; |
| NSRect aFrame = [pCurSubView frame]; |
| aFrame.origin.y += nDiff; |
| // give separators the correct width |
| // separators are currently the only NSBoxes we use |
| if( [pCurSubView isMemberOfClass: [NSBox class]] ) |
| { |
| aFrame.size.width = aTabSize.width - aFrame.origin.x - 10; |
| } |
| [pCurSubView setFrame: aFrame]; |
| } |
| } |
| } |
| } |
| |
| static NSControl* createLabel( const rtl::OUString& i_rText ) |
| { |
| NSString* pText = CreateNSString( i_rText ); |
| NSRect aTextRect = { NSZeroPoint, {20, 15} }; |
| NSTextField* pTextView = [[NSTextField alloc] initWithFrame: aTextRect]; |
| [pTextView setFont: [NSFont controlContentFontOfSize: 0]]; |
| [pTextView setEditable: NO]; |
| [pTextView setSelectable: NO]; |
| [pTextView setDrawsBackground: NO]; |
| [pTextView setBordered: NO]; |
| [pTextView setStringValue: pText]; |
| [pTextView sizeToFit]; |
| [pText release]; |
| return pTextView; |
| } |
| |
| static sal_Int32 findBreak( const rtl::OUString& i_rText, sal_Int32 i_nPos ) |
| { |
| sal_Int32 nRet = i_rText.getLength(); |
| Reference< i18n::XBreakIterator > xBI( vcl::unohelper::CreateBreakIterator() ); |
| if( xBI.is() ) |
| { |
| i18n::Boundary aBoundary = xBI->getWordBoundary( i_rText, i_nPos, |
| Application::GetSettings().GetLocale(), |
| i18n::WordType::ANYWORD_IGNOREWHITESPACES, |
| sal_True ); |
| nRet = aBoundary.endPos; |
| } |
| return nRet; |
| } |
| |
| static void linebreakCell( NSCell* pBtn, const rtl::OUString& i_rText ) |
| { |
| NSString* pText = CreateNSString( i_rText ); |
| [pBtn setTitle: pText]; |
| [pText release]; |
| NSSize aSize = [pBtn cellSize]; |
| if( aSize.width > 280 ) |
| { |
| // need two lines |
| sal_Int32 nLen = i_rText.getLength(); |
| sal_Int32 nIndex = nLen / 2; |
| nIndex = findBreak( i_rText, nIndex ); |
| if( nIndex < nLen ) |
| { |
| rtl::OUStringBuffer aBuf( i_rText ); |
| aBuf.setCharAt( nIndex, '\n' ); |
| pText = CreateNSString( aBuf.makeStringAndClear() ); |
| [pBtn setTitle: pText]; |
| [pText release]; |
| } |
| } |
| } |
| |
| static void addSubgroup( NSView* pCurParent, long& rCurY, const rtl::OUString& rText ) |
| { |
| NSControl* pTextView = createLabel( rText ); |
| [pCurParent addSubview: [pTextView autorelease]]; |
| NSRect aTextRect = [pTextView frame]; |
| // move to nCurY |
| aTextRect.origin.y = rCurY - aTextRect.size.height; |
| [pTextView setFrame: aTextRect]; |
| |
| NSRect aSepRect = { { aTextRect.size.width + 1, aTextRect.origin.y }, { 100, 6 } }; |
| NSBox* pBox = [[NSBox alloc] initWithFrame: aSepRect]; |
| [pBox setBoxType: NSBoxSeparator]; |
| [pCurParent addSubview: [pBox autorelease]]; |
| |
| // update nCurY |
| rCurY = aTextRect.origin.y - 5; |
| } |
| |
| static void addBool( NSView* pCurParent, long& rCurX, long& rCurY, long nAttachOffset, |
| const rtl::OUString& rText, sal_Bool bEnabled, |
| const rtl::OUString& rProperty, sal_Bool bValue, |
| std::vector<ColumnItem >& rRightColumn, |
| ControllerProperties* pControllerProperties, |
| ControlTarget* pCtrlTarget |
| ) |
| { |
| NSRect aCheckRect = NSMakeRect( rCurX + nAttachOffset, 0, 0, 15); |
| NSButton* pBtn = [[NSButton alloc] initWithFrame: aCheckRect]; |
| [pBtn setButtonType: NSSwitchButton]; |
| [pBtn setState: bValue ? NSOnState : NSOffState]; |
| if( ! bEnabled ) |
| [pBtn setEnabled: NO]; |
| linebreakCell( [pBtn cell], rText ); |
| [pBtn sizeToFit]; |
| |
| rRightColumn.push_back( ColumnItem( pBtn ) ); |
| |
| // connect target |
| [pBtn setTarget: pCtrlTarget]; |
| [pBtn setAction: @selector(triggered:)]; |
| int nTag = pControllerProperties->addNameTag( rProperty ); |
| pControllerProperties->addObservedControl( pBtn ); |
| [pBtn setTag: nTag]; |
| |
| aCheckRect = [pBtn frame]; |
| // #i115837# add a murphy factor; it can apparently occasionally happen |
| // that sizeToFit does not a perfect job and that the button linebreaks again |
| // if - and only if - there is already a '\n' contained in the text and the width |
| // is minimally of |
| aCheckRect.size.width += 1; |
| |
| // move to rCurY |
| aCheckRect.origin.y = rCurY - aCheckRect.size.height; |
| [pBtn setFrame: aCheckRect]; |
| |
| [pCurParent addSubview: [pBtn autorelease]]; |
| |
| // update rCurY |
| rCurY = aCheckRect.origin.y - 5; |
| } |
| |
| static void addRadio( NSView* pCurParent, long& rCurX, long& rCurY, long nAttachOffset, |
| const rtl::OUString& rText, |
| const rtl::OUString& rProperty, Sequence< rtl::OUString > rChoices, sal_Int32 nSelectValue, |
| std::vector<ColumnItem >& rLeftColumn, |
| std::vector<ColumnItem >& rRightColumn, |
| ControllerProperties* pControllerProperties, |
| ControlTarget* pCtrlTarget |
| ) |
| { |
| sal_Int32 nOff = 0; |
| if( rText.getLength() ) |
| { |
| // add a label |
| NSControl* pTextView = createLabel( rText ); |
| NSRect aTextRect = [pTextView frame]; |
| aTextRect.origin.x = rCurX + nAttachOffset; |
| [pCurParent addSubview: [pTextView autorelease]]; |
| |
| rLeftColumn.push_back( ColumnItem( pTextView ) ); |
| |
| // move to nCurY |
| aTextRect.origin.y = rCurY - aTextRect.size.height; |
| [pTextView setFrame: aTextRect]; |
| |
| // update nCurY |
| rCurY = aTextRect.origin.y - 5; |
| |
| // indent the radio group relative to the text |
| // nOff = 20; |
| } |
| |
| // setup radio matrix |
| NSButtonCell* pProto = [[NSButtonCell alloc] init]; |
| |
| NSRect aRadioRect = NSMakeRect( rCurX + nOff, 0, 280 - rCurX, 5*rChoices.getLength()); |
| [pProto setTitle: @"RadioButtonGroup"]; |
| [pProto setButtonType: NSRadioButton]; |
| NSMatrix* pMatrix = [[NSMatrix alloc] initWithFrame: aRadioRect |
| mode: NSRadioModeMatrix |
| prototype: (NSCell*)pProto |
| numberOfRows: rChoices.getLength() |
| numberOfColumns: 1]; |
| // set individual titles |
| NSArray* pCells = [pMatrix cells]; |
| for( sal_Int32 m = 0; m < rChoices.getLength(); m++ ) |
| { |
| NSCell* pCell = [pCells objectAtIndex: m]; |
| filterAccelerator( rChoices[m] ); |
| linebreakCell( pCell, rChoices[m] ); |
| // connect target and action |
| [pCell setTarget: pCtrlTarget]; |
| [pCell setAction: @selector(triggered:)]; |
| int nTag = pControllerProperties->addNameAndValueTag( rProperty, m ); |
| pControllerProperties->addObservedControl( pCell ); |
| [pCell setTag: nTag]; |
| // set current selection |
| if( nSelectValue == m ) |
| [pMatrix selectCellAtRow: m column: 0]; |
| } |
| [pMatrix sizeToFit]; |
| aRadioRect = [pMatrix frame]; |
| |
| // move it down, so it comes to the correct position |
| aRadioRect.origin.y = rCurY - aRadioRect.size.height; |
| [pMatrix setFrame: aRadioRect]; |
| [pCurParent addSubview: [pMatrix autorelease]]; |
| |
| rRightColumn.push_back( ColumnItem( pMatrix ) ); |
| |
| // update nCurY |
| rCurY = aRadioRect.origin.y - 5; |
| |
| [pProto release]; |
| } |
| |
| static void addList( NSView* pCurParent, long& rCurX, long& rCurY, long /*nAttachOffset*/, |
| const rtl::OUString& rText, |
| const rtl::OUString& rProperty, const Sequence< rtl::OUString > rChoices, sal_Int32 nSelectValue, |
| std::vector<ColumnItem >& rLeftColumn, |
| std::vector<ColumnItem >& rRightColumn, |
| ControllerProperties* pControllerProperties, |
| ControlTarget* pCtrlTarget |
| ) |
| { |
| // don't indent attached lists, looks bad in the existing cases |
| NSControl* pTextView = createLabel( rText ); |
| [pCurParent addSubview: [pTextView autorelease]]; |
| rLeftColumn.push_back( ColumnItem( pTextView ) ); |
| NSRect aTextRect = [pTextView frame]; |
| aTextRect.origin.x = rCurX /* + nAttachOffset*/; |
| |
| // don't indent attached lists, looks bad in the existing cases |
| NSRect aBtnRect = NSMakeRect( rCurX /*+ nAttachOffset*/ + aTextRect.size.width, 0, 0, 15); |
| NSPopUpButton* pBtn = [[NSPopUpButton alloc] initWithFrame: aBtnRect pullsDown: NO]; |
| |
| // iterate options |
| for( sal_Int32 m = 0; m < rChoices.getLength(); m++ ) |
| { |
| NSString* pItemText = CreateNSString( rChoices[m] ); |
| [pBtn addItemWithTitle: pItemText]; |
| NSMenuItem* pItem = [pBtn itemWithTitle: pItemText]; |
| int nTag = pControllerProperties->addNameAndValueTag( rProperty, m ); |
| [pItem setTag: nTag]; |
| [pItemText release]; |
| } |
| |
| [pBtn selectItemAtIndex: nSelectValue]; |
| |
| // add the button to observed controls for enabled state changes |
| // also add a tag just for this purpose |
| pControllerProperties->addObservedControl( pBtn ); |
| [pBtn setTag: pControllerProperties->addNameTag( rProperty )]; |
| |
| [pBtn sizeToFit]; |
| [pCurParent addSubview: [pBtn autorelease]]; |
| |
| rRightColumn.push_back( ColumnItem( pBtn ) ); |
| |
| // connect target and action |
| [pBtn setTarget: pCtrlTarget]; |
| [pBtn setAction: @selector(triggered:)]; |
| |
| // move to nCurY |
| aBtnRect = [pBtn frame]; |
| aBtnRect.origin.y = rCurY - aBtnRect.size.height; |
| [pBtn setFrame: aBtnRect]; |
| |
| // align label |
| aTextRect.origin.y = aBtnRect.origin.y + (aBtnRect.size.height - aTextRect.size.height)/2; |
| [pTextView setFrame: aTextRect]; |
| |
| // update rCurY |
| rCurY = aBtnRect.origin.y - 5; |
| } |
| |
| static void addEdit( NSView* pCurParent, long& rCurX, long& rCurY, long nAttachOffset, |
| const rtl::OUString rCtrlType, |
| const rtl::OUString& rText, |
| const rtl::OUString& rProperty, const PropertyValue* pValue, |
| sal_Int64 nMinValue, sal_Int64 nMaxValue, |
| std::vector<ColumnItem >& rLeftColumn, |
| std::vector<ColumnItem >& rRightColumn, |
| ControllerProperties* pControllerProperties, |
| ControlTarget* pCtrlTarget |
| ) |
| { |
| sal_Int32 nOff = 0; |
| if( rText.getLength() ) |
| { |
| // add a label |
| NSControl* pTextView = createLabel( rText ); |
| [pCurParent addSubview: [pTextView autorelease]]; |
| |
| rLeftColumn.push_back( ColumnItem( pTextView ) ); |
| |
| // move to nCurY |
| NSRect aTextRect = [pTextView frame]; |
| aTextRect.origin.x = rCurX + nAttachOffset; |
| aTextRect.origin.y = rCurY - aTextRect.size.height; |
| [pTextView setFrame: aTextRect]; |
| |
| // update nCurY |
| rCurY = aTextRect.origin.y - 5; |
| |
| // and set the offset for the real edit field |
| nOff = aTextRect.size.width + 5; |
| } |
| |
| NSRect aFieldRect = NSMakeRect( rCurX + nOff + nAttachOffset, 0, 100, 25); |
| NSTextField* pFieldView = [[NSTextField alloc] initWithFrame: aFieldRect]; |
| [pFieldView setEditable: YES]; |
| [pFieldView setSelectable: YES]; |
| [pFieldView setDrawsBackground: YES]; |
| [pFieldView sizeToFit]; // FIXME: this does nothing |
| [pCurParent addSubview: [pFieldView autorelease]]; |
| |
| rRightColumn.push_back( ColumnItem( pFieldView ) ); |
| |
| // add the field to observed controls for enabled state changes |
| // also add a tag just for this purpose |
| pControllerProperties->addObservedControl( pFieldView ); |
| int nTag = pControllerProperties->addNameTag( rProperty ); |
| [pFieldView setTag: nTag]; |
| // pControllerProperties->addNamedView( pFieldView, aPropertyName ); |
| |
| // move to nCurY |
| aFieldRect.origin.y = rCurY - aFieldRect.size.height; |
| [pFieldView setFrame: aFieldRect]; |
| |
| if( rCtrlType.equalsAscii( "Range" ) ) |
| { |
| // add a stepper control |
| NSRect aStepFrame = NSMakeRect( |
| aFieldRect.origin.x + aFieldRect.size.width + 5, aFieldRect.origin.y, |
| 15, aFieldRect.size.height); |
| NSStepper* pStep = [[NSStepper alloc] initWithFrame: aStepFrame]; |
| [pStep setIncrement: 1]; |
| [pStep setValueWraps: NO]; |
| [pStep setTag: nTag]; |
| [pCurParent addSubview: [pStep autorelease]]; |
| |
| rRightColumn.back().pSubControl = pStep; |
| |
| pControllerProperties->addObservedControl( pStep ); |
| [pStep setTarget: pCtrlTarget]; |
| [pStep setAction: @selector(triggered:)]; |
| |
| // constrain the text field to decimal numbers |
| NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init]; |
| [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4]; |
| [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle]; |
| [pFormatter setAllowsFloats: NO]; |
| [pFormatter setMaximumFractionDigits: 0]; |
| if( nMinValue != nMaxValue ) |
| { |
| [pFormatter setMinimum: [[NSNumber numberWithInt: nMinValue] autorelease]]; |
| [pStep setMinValue: nMinValue]; |
| [pFormatter setMaximum: [[NSNumber numberWithInt: nMaxValue] autorelease]]; |
| [pStep setMaxValue: nMaxValue]; |
| } |
| [pFieldView setFormatter: pFormatter]; |
| |
| sal_Int64 nSelectVal = 0; |
| if( pValue && pValue->Value.hasValue() ) |
| pValue->Value >>= nSelectVal; |
| |
| [pFieldView setIntValue: nSelectVal]; |
| [pStep setIntValue: nSelectVal]; |
| |
| pControllerProperties->addViewPair( pFieldView, pStep ); |
| // connect target and action |
| [pFieldView setTarget: pCtrlTarget]; |
| [pFieldView setAction: @selector(triggeredNumeric:)]; |
| [pStep setTarget: pCtrlTarget]; |
| [pStep setAction: @selector(triggeredNumeric:)]; |
| } |
| else |
| { |
| // connect target and action |
| [pFieldView setTarget: pCtrlTarget]; |
| [pFieldView setAction: @selector(triggered:)]; |
| |
| if( pValue && pValue->Value.hasValue() ) |
| { |
| rtl::OUString aValue; |
| pValue->Value >>= aValue; |
| if( aValue.getLength() ) |
| { |
| NSString* pText = CreateNSString( aValue ); |
| [pFieldView setStringValue: pText]; |
| [pText release]; |
| } |
| } |
| } |
| |
| // update nCurY |
| rCurY = aFieldRect.origin.y - 5; |
| } |
| |
| @implementation AquaPrintAccessoryView |
| +(NSObject*)setupPrinterPanel: (NSPrintOperation*)pOp withController: (vcl::PrinterController*)pController withState: (PrintAccessoryViewState*)pState |
| { |
| const Sequence< PropertyValue >& rOptions( pController->getUIOptions() ); |
| if( rOptions.getLength() == 0 ) |
| return nil; |
| |
| NSView* pCurParent = 0; |
| long nCurY = 0; |
| long nCurX = 0; |
| NSRect aViewFrame = { NSZeroPoint, {600, 400 } }; |
| NSRect aTabViewFrame = { { 190, 0 }, {410, 400 } }; |
| NSSize aMaxTabSize = NSZeroSize; |
| NSView* pAccessoryView = [[NSView alloc] initWithFrame: aViewFrame]; |
| NSTabView* pTabView = [[NSTabView alloc] initWithFrame: aTabViewFrame]; |
| [pAccessoryView addSubview: [pTabView autorelease]]; |
| |
| sal_Bool bIgnoreSubgroup = sal_False; |
| |
| ControllerProperties* pControllerProperties = new ControllerProperties( pController, pOp, pAccessoryView, pTabView, pState ); |
| ControlTarget* pCtrlTarget = [[ControlTarget alloc] initWithControllerMap: pControllerProperties]; |
| |
| std::vector< ColumnItem > aLeftColumn, aRightColumn; |
| |
| // ugly: |
| // prepend a "selection" checkbox if the properties have such a selection in PrintContent |
| bool bAddSelectionCheckBox = false, bSelectionBoxEnabled = false, bSelectionBoxChecked = false; |
| for( int i = 0; i < rOptions.getLength(); i++ ) |
| { |
| Sequence< beans::PropertyValue > aOptProp; |
| rOptions[i].Value >>= aOptProp; |
| |
| rtl::OUString aCtrlType; |
| rtl::OUString aPropertyName; |
| Sequence< rtl::OUString > aChoices; |
| Sequence< sal_Bool > aChoicesDisabled; |
| sal_Int32 aSelectionChecked = 0; |
| for( int n = 0; n < aOptProp.getLength(); n++ ) |
| { |
| const beans::PropertyValue& rEntry( aOptProp[ n ] ); |
| if( rEntry.Name.equalsAscii( "ControlType" ) ) |
| { |
| rEntry.Value >>= aCtrlType; |
| } |
| else if( rEntry.Name.equalsAscii( "Choices" ) ) |
| { |
| rEntry.Value >>= aChoices; |
| } |
| else if( rEntry.Name.equalsAscii( "ChoicesDisabled" ) ) |
| { |
| rEntry.Value >>= aChoicesDisabled; |
| } |
| else if( rEntry.Name.equalsAscii( "Property" ) ) |
| { |
| PropertyValue aVal; |
| rEntry.Value >>= aVal; |
| aPropertyName = aVal.Name; |
| if( aPropertyName.equalsAscii( "PrintContent" ) ) |
| aVal.Value >>= aSelectionChecked; |
| } |
| } |
| if( aCtrlType.equalsAscii( "Radio" ) && |
| aPropertyName.equalsAscii( "PrintContent" ) && |
| aChoices.getLength() > 2 ) |
| { |
| bAddSelectionCheckBox = true; |
| bSelectionBoxEnabled = aChoicesDisabled.getLength() < 2 || ! aChoicesDisabled[2]; |
| bSelectionBoxChecked = (aSelectionChecked==2); |
| break; |
| } |
| } |
| |
| for( int i = 0; i < rOptions.getLength(); i++ ) |
| { |
| Sequence< beans::PropertyValue > aOptProp; |
| rOptions[i].Value >>= aOptProp; |
| |
| // extract ui element |
| bool bEnabled = true; |
| rtl::OUString aCtrlType; |
| rtl::OUString aText; |
| rtl::OUString aPropertyName; |
| rtl::OUString aGroupHint; |
| Sequence< rtl::OUString > aChoices; |
| sal_Int64 nMinValue = 0, nMaxValue = 0; |
| long nAttachOffset = 0; |
| sal_Bool bIgnore = sal_False; |
| |
| for( int n = 0; n < aOptProp.getLength(); n++ ) |
| { |
| const beans::PropertyValue& rEntry( aOptProp[ n ] ); |
| if( rEntry.Name.equalsAscii( "Text" ) ) |
| { |
| rEntry.Value >>= aText; |
| filterAccelerator( aText ); |
| } |
| else if( rEntry.Name.equalsAscii( "ControlType" ) ) |
| { |
| rEntry.Value >>= aCtrlType; |
| } |
| else if( rEntry.Name.equalsAscii( "Choices" ) ) |
| { |
| rEntry.Value >>= aChoices; |
| } |
| else if( rEntry.Name.equalsAscii( "Property" ) ) |
| { |
| PropertyValue aVal; |
| rEntry.Value >>= aVal; |
| aPropertyName = aVal.Name; |
| } |
| else if( rEntry.Name.equalsAscii( "Enabled" ) ) |
| { |
| sal_Bool bValue = sal_True; |
| rEntry.Value >>= bValue; |
| bEnabled = bValue; |
| } |
| else if( rEntry.Name.equalsAscii( "MinValue" ) ) |
| { |
| rEntry.Value >>= nMinValue; |
| } |
| else if( rEntry.Name.equalsAscii( "MaxValue" ) ) |
| { |
| rEntry.Value >>= nMaxValue; |
| } |
| else if( rEntry.Name.equalsAscii( "AttachToDependency" ) ) |
| { |
| nAttachOffset = 20; |
| } |
| else if( rEntry.Name.equalsAscii( "InternalUIOnly" ) ) |
| { |
| rEntry.Value >>= bIgnore; |
| } |
| else if( rEntry.Name.equalsAscii( "GroupingHint" ) ) |
| { |
| rEntry.Value >>= aGroupHint; |
| } |
| } |
| |
| if( aCtrlType.equalsAscii( "Group" ) || |
| aCtrlType.equalsAscii( "Subgroup" ) || |
| aCtrlType.equalsAscii( "Radio" ) || |
| aCtrlType.equalsAscii( "List" ) || |
| aCtrlType.equalsAscii( "Edit" ) || |
| aCtrlType.equalsAscii( "Range" ) || |
| aCtrlType.equalsAscii( "Bool" ) ) |
| { |
| // since our build target is MacOSX 10.4 we can have only one accessory view |
| // so we have a single accessory view that is tabbed for grouping |
| if( aCtrlType.equalsAscii( "Group" ) |
| || ! pCurParent |
| || ( aCtrlType.equalsAscii( "Subgroup" ) && nCurY < -250 && ! bIgnore ) |
| ) |
| { |
| rtl::OUString aGroupTitle( aText ); |
| if( aCtrlType.equalsAscii( "Subgroup" ) ) |
| aGroupTitle = pControllerProperties->getMoreString(); |
| // set size of current parent |
| if( pCurParent ) |
| adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn ); |
| |
| // new tab item |
| if( ! aText.getLength() ) |
| aText = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OOo" ) ); |
| NSString* pLabel = CreateNSString( aGroupTitle ); |
| NSTabViewItem* pItem = [[NSTabViewItem alloc] initWithIdentifier: pLabel ]; |
| [pItem setLabel: pLabel]; |
| [pTabView addTabViewItem: pItem]; |
| pCurParent = [[NSView alloc] initWithFrame: aTabViewFrame]; |
| [pItem setView: pCurParent]; |
| [pLabel release]; |
| |
| // reset indent |
| nCurX = 20; |
| // reset Y |
| nCurY = 0; |
| // clear columns |
| aLeftColumn.clear(); |
| aRightColumn.clear(); |
| |
| if( bAddSelectionCheckBox ) |
| { |
| addBool( pCurParent, nCurX, nCurY, 0, |
| pControllerProperties->getPrintSelectionString(), bSelectionBoxEnabled, |
| rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintContent" ) ), bSelectionBoxChecked, |
| aRightColumn, pControllerProperties, pCtrlTarget ); |
| bAddSelectionCheckBox = false; |
| } |
| } |
| |
| if( aCtrlType.equalsAscii( "Subgroup" ) && pCurParent ) |
| { |
| bIgnoreSubgroup = bIgnore; |
| if( bIgnore ) |
| continue; |
| |
| addSubgroup( pCurParent, nCurY, aText ); |
| } |
| else if( bIgnoreSubgroup || bIgnore ) |
| { |
| continue; |
| } |
| else if( aCtrlType.equalsAscii( "Bool" ) && pCurParent ) |
| { |
| sal_Bool bVal = sal_False; |
| PropertyValue* pVal = pController->getValue( aPropertyName ); |
| if( pVal ) |
| pVal->Value >>= bVal; |
| addBool( pCurParent, nCurX, nCurY, nAttachOffset, |
| aText, true, aPropertyName, bVal, |
| aRightColumn, pControllerProperties, pCtrlTarget ); |
| } |
| else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent ) |
| { |
| // get currently selected value |
| sal_Int32 nSelectVal = 0; |
| PropertyValue* pVal = pController->getValue( aPropertyName ); |
| if( pVal && pVal->Value.hasValue() ) |
| pVal->Value >>= nSelectVal; |
| |
| addRadio( pCurParent, nCurX, nCurY, nAttachOffset, |
| aText, aPropertyName, aChoices, nSelectVal, |
| aLeftColumn, aRightColumn, |
| pControllerProperties, pCtrlTarget ); |
| } |
| else if( aCtrlType.equalsAscii( "List" ) && pCurParent ) |
| { |
| PropertyValue* pVal = pController->getValue( aPropertyName ); |
| sal_Int32 aSelectVal = 0; |
| if( pVal && pVal->Value.hasValue() ) |
| pVal->Value >>= aSelectVal; |
| |
| addList( pCurParent, nCurX, nCurY, nAttachOffset, |
| aText, aPropertyName, aChoices, aSelectVal, |
| aLeftColumn, aRightColumn, |
| pControllerProperties, pCtrlTarget ); |
| } |
| else if( (aCtrlType.equalsAscii( "Edit" ) || aCtrlType.equalsAscii( "Range" )) && pCurParent ) |
| { |
| // current value |
| PropertyValue* pVal = pController->getValue( aPropertyName ); |
| addEdit( pCurParent, nCurX, nCurY, nAttachOffset, |
| aCtrlType, aText, aPropertyName, pVal, |
| nMinValue, nMaxValue, |
| aLeftColumn, aRightColumn, |
| pControllerProperties, pCtrlTarget ); |
| } |
| } |
| else |
| { |
| DBG_ERROR( "Unsupported UI option" ); |
| } |
| } |
| |
| pControllerProperties->updateEnableState(); |
| adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn ); |
| |
| // leave some space for the preview |
| if( aMaxTabSize.height < 200 ) |
| aMaxTabSize.height = 200; |
| |
| // now reposition everything again so it is upper bound |
| adjustTabViews( pTabView, aMaxTabSize ); |
| |
| // find the minimum needed tab size |
| NSSize aTabCtrlSize = [pTabView minimumSize]; |
| aTabCtrlSize.height += aMaxTabSize.height + 10; |
| if( aTabCtrlSize.width < aMaxTabSize.width + 10 ) |
| aTabCtrlSize.width = aMaxTabSize.width + 10; |
| [pTabView setFrameSize: aTabCtrlSize]; |
| aViewFrame.size.width = aTabCtrlSize.width + aTabViewFrame.origin.x; |
| aViewFrame.size.height = aTabCtrlSize.height + aTabViewFrame.origin.y; |
| [pAccessoryView setFrameSize: aViewFrame.size]; |
| |
| pControllerProperties->setupPreview( pCtrlTarget ); |
| |
| // set the accessory view |
| [pOp setAccessoryView: [pAccessoryView autorelease]]; |
| |
| // set the current selecte tab item |
| if( pState->nLastPage >= 0 && pState->nLastPage < [pTabView numberOfTabViewItems] ) |
| [pTabView selectTabViewItemAtIndex: pState->nLastPage]; |
| |
| return pCtrlTarget; |
| } |
| |
| @end |