diff options
author | Kurt Zenker <kz@openoffice.org> | 2010-01-15 16:47:42 +0100 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2010-01-15 16:47:42 +0100 |
commit | 8ad567a9f81ac92a5bf7592eab0179876c1dafab (patch) | |
tree | 2504a400d1b5214a38926f8d2cdd008c88f3ef54 /vcl | |
parent | 4eeae16d41ddb88df9b4aec1fe2ea975b8ef5ec7 (diff) | |
parent | a2637545e1419956096899a82a9c79511d83fbc5 (diff) |
CWS-TOOLING: integrate CWS printerpullpages
Diffstat (limited to 'vcl')
75 files changed, 9688 insertions, 793 deletions
diff --git a/vcl/aqua/inc/aquaprintview.h b/vcl/aqua/inc/aquaprintview.h index c5ce20c17425..55a85678cd50 100755 --- a/vcl/aqua/inc/aquaprintview.h +++ b/vcl/aqua/inc/aquaprintview.h @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: aquaprintview.h,v $ - * $Revision: 1.3 $ + * $Revision: 1.3.114.1 $ * * This file is part of OpenOffice.org. * @@ -35,20 +35,36 @@ #include <Cocoa/Cocoa.h> #include "postmac.h" -class ImplQPrinter; +#include "vcl/print.hxx" + class AquaSalInfoPrinter; +struct PrintAccessoryViewState +{ + bool bNeedRestart; + sal_Int32 nLastPage; + + PrintAccessoryViewState() + : bNeedRestart( false ), nLastPage( 0 ) {} +}; + @interface AquaPrintView : NSView { - ImplQPrinter* mpQPrinter; - AquaSalInfoPrinter* mpInfoPrinter; + vcl::PrinterController* mpController; + AquaSalInfoPrinter* mpInfoPrinter; } --(id)initWithQPrinter: (ImplQPrinter*)pPrinter withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter; +-(id)initWithController: (vcl::PrinterController*)pController withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter; -(MacOSBOOL)knowsPageRange: (NSRangePointer)range; -(NSRect)rectForPage: (int)page; -(NSPoint)locationOfPrintRect: (NSRect)aRect; -(void)drawRect: (NSRect)rect; @end +@interface AquaPrintAccessoryView : NSObject +{ +} ++(NSObject*)setupPrinterPanel: (NSPrintOperation*)pOp withController: (vcl::PrinterController*)pController withState: (PrintAccessoryViewState*)pState; +@end + #endif diff --git a/vcl/aqua/inc/salgdi.h b/vcl/aqua/inc/salgdi.h index 4933dbc48586..e835ac773a50 100644 --- a/vcl/aqua/inc/salgdi.h +++ b/vcl/aqua/inc/salgdi.h @@ -175,6 +175,9 @@ public: void RefreshRect(float lX, float lY, float lWidth, float lHeight); void SetState(); + void UnsetState(); + // InvalidateContext does an UnsetState and sets mrContext to 0 + void InvalidateContext(); virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight ); virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& ); diff --git a/vcl/aqua/inc/salprn.h b/vcl/aqua/inc/salprn.h index ec08261e8321..bf9c3c25bc87 100644 --- a/vcl/aqua/inc/salprn.h +++ b/vcl/aqua/inc/salprn.h @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: salprn.h,v $ - * $Revision: 1.12 $ + * $Revision: 1.12.56.1 $ * * This file is part of OpenOffice.org. * @@ -73,8 +73,8 @@ class AquaSalInfoPrinter : public SalInfoPrinter int mnStartPageOffsetX; int mnStartPageOffsetY; - ULONG mnCurPageRangeStart; - ULONG mnCurPageRangeCount; + sal_Int32 mnCurPageRangeStart; + sal_Int32 mnCurPageRangeCount; public: AquaSalInfoPrinter( const SalPrinterQueueInfo& pInfo ); @@ -96,19 +96,17 @@ class AquaSalInfoPrinter : public SalInfoPrinter virtual String GetPaperBinName( const ImplJobSetup* i_pSetupData, ULONG i_nPaperBin ); virtual void InitPaperFormats( const ImplJobSetup* i_pSetupData ); virtual int GetLandscapeAngle( const ImplJobSetup* i_pSetupData ); - virtual DuplexMode GetDuplexMode( const ImplJobSetup* i_pSetupData ); - // the artificial separation between InfoPrinter and Printer // is not really useful for us // so let's make AquaSalPrinter just a forwarder to AquaSalInfoPrinter // and concentrate the real work in one class // implement pull model print system - BOOL StartJob( const String* pFileName, - const String& rAppName, - ImplJobSetup* pSetupData, - ImplQPrinter* pQPrinter, - bool bIsQuickJob ); + BOOL StartJob( const String* i_pFileName, + const String& rJobName, + const String& i_rAppName, + ImplJobSetup* i_pSetupData, + vcl::PrinterController& i_rController ); BOOL EndJob(); BOOL AbortJob(); SalGraphics* StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData ); @@ -117,8 +115,12 @@ class AquaSalInfoPrinter : public SalInfoPrinter NSPrintInfo* getPrintInfo() const { return mpPrintInfo; } void setStartPageOffset( int nOffsetX, int nOffsetY ) { mnStartPageOffsetX = nOffsetX; mnStartPageOffsetY = nOffsetY; } - ULONG getCurPageRangeStart() const { return mnCurPageRangeStart; } - ULONG getCurPageRangeCount() const { return mnCurPageRangeCount; } + sal_Int32 getCurPageRangeStart() const { return mnCurPageRangeStart; } + sal_Int32 getCurPageRangeCount() const { return mnCurPageRangeCount; } + + // match width/height against known paper formats, possibly switching orientation + const PaperInfo* matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const; + void setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation ); private: AquaSalInfoPrinter( const AquaSalInfoPrinter& ); @@ -139,13 +141,16 @@ class AquaSalPrinter : public SalPrinter virtual BOOL StartJob( const XubString* i_pFileName, const XubString& i_rJobName, const XubString& i_rAppName, - ULONG i_nCopies, BOOL i_bCollate, + ULONG i_nCopies, + bool i_bCollate, + bool i_bDirect, ImplJobSetup* i_pSetupData ); // implement pull model print system - virtual BOOL StartJob( const String* pFileName, - const String& rAppName, - ImplJobSetup* pSetupData, - ImplQPrinter* pQPrinter ); + virtual BOOL StartJob( const String* i_pFileName, + const String& rJobName, + const String& i_rAppName, + ImplJobSetup* i_pSetupData, + vcl::PrinterController& i_rListener ); virtual BOOL EndJob(); virtual BOOL AbortJob(); @@ -162,7 +167,7 @@ const double fPtTo100thMM = 35.27777778; inline int PtTo10Mu( double nPoints ) { return (int)(((nPoints)*fPtTo100thMM)+0.5); } -inline double TenMuToPt( double nUnits ) { return (((nUnits)/fPtTo100thMM)+0.5); } +inline double TenMuToPt( double nUnits ) { return floor(((nUnits)/fPtTo100thMM)+0.5); } diff --git a/vcl/aqua/source/gdi/aquaprintaccessoryview.mm b/vcl/aqua/source/gdi/aquaprintaccessoryview.mm new file mode 100644 index 000000000000..798fefef1b25 --- /dev/null +++ b/vcl/aqua/source/gdi/aquaprintaccessoryview.mm @@ -0,0 +1,1237 @@ +/************************************************************************ + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: aquaprintview.mm,v $ + * $Revision: 1.5.56.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "aquaprintview.h" +#include "salinst.h" +#include "vcl/print.hxx" +#include "vcl/image.hxx" +#include "vcl/virdev.hxx" +#include "vcl/svdata.hxx" +#include "vcl/svapp.hxx" +#include "vcl/unohelp.hxx" + +#include "vcl/svids.hrc" + +#include "tools/resary.hxx" + +#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() >= 4, "resources not found !" ); + } + + rtl::OUString getMoreString() + { + return maLocalizedStrings.Count() >= 4 + ? rtl::OUString( maLocalizedStrings.GetString( 3 ) ) + : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "More" ) ); + } + + 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 ) + { + #if 0 + // 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. + for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it ) + { + if( [*it isKindOfClass: [NSView class]] ) + { + NSView* pView = (NSView*)*it; + NSWindow* pWindow = [pView window]; + if( pWindow ) + { + [pWindow cancelOperation: nil]; + break; + } + } + } + #else + NSWindow* pWindow = [NSApp modalWindow]; + if( pWindow ) + [pWindow cancelOperation: nil]; + #endif + [[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 ) + { + 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() ) + { + MacOSBOOL 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; + // 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; + 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.height -= 61; + mpPreview = [[NSImageView alloc] initWithFrame: aPreviewFrame]; + [mpPreview setImageScaling: NSScaleNone]; + [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* pView, 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 = [pView subviews]; + unsigned int nViews = [pSubViews count]; + NSRect aUnion = { { 0, 0 }, { 0, 0 } }; + + // 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; + [pView 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* pView = [pItem view]; + if( pView ) + { + NSRect aRect = [pView frame]; + double nDiff = aTabSize.height - aRect.size.height; + aRect.size = aTabSize; + [pView setFrame: aRect]; + + NSArray* pSubViews = [pView 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 = { { 0, 0 }, {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]; + } + } +} + + +@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 = { { 0, 0 }, {600, 400 } }; + NSRect aTabViewFrame = { { 190, 0 }, {410, 400 } }; + NSSize aMaxTabSize = { 0, 0 }; + 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; + + 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; + 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; + } + } + + 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( aCtrlType.equalsAscii( "Subgroup" ) && pCurParent ) + { + bIgnoreSubgroup = bIgnore; + if( bIgnore ) + continue; + + NSControl* pTextView = createLabel( aText ); + [pCurParent addSubview: [pTextView autorelease]]; + NSRect aTextRect = [pTextView frame]; + // move to nCurY + aTextRect.origin.y = nCurY - 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 + nCurY = aTextRect.origin.y - 5; + } + else if( bIgnoreSubgroup || bIgnore ) + continue; + else if( aCtrlType.equalsAscii( "Bool" ) && pCurParent ) + { + NSRect aCheckRect = { { nCurX + nAttachOffset, 0 }, { 0, 15 } }; + NSButton* pBtn = [[NSButton alloc] initWithFrame: aCheckRect]; + [pBtn setButtonType: NSSwitchButton]; + sal_Bool bVal = sal_False; + PropertyValue* pVal = pController->getValue( aPropertyName ); + if( pVal ) + pVal->Value >>= bVal; + [pBtn setState: bVal ? NSOnState : NSOffState]; + linebreakCell( [pBtn cell], aText ); + [pBtn sizeToFit]; + [pCurParent addSubview: [pBtn autorelease]]; + + aRightColumn.push_back( ColumnItem( pBtn ) ); + + // connect target + [pBtn setTarget: pCtrlTarget]; + [pBtn setAction: @selector(triggered:)]; + int nTag = pControllerProperties->addNameTag( aPropertyName ); + pControllerProperties->addObservedControl( pBtn ); + [pBtn setTag: nTag]; + + aCheckRect = [pBtn frame]; + + // move to nCurY + aCheckRect.origin.y = nCurY - aCheckRect.size.height; + [pBtn setFrame: aCheckRect]; + + // update nCurY + nCurY = aCheckRect.origin.y - 5; + } + else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent ) + { + sal_Int32 nOff = 0; + if( aText.getLength() ) + { + // add a label + NSControl* pTextView = createLabel( aText ); + NSRect aTextRect = [pTextView frame]; + aTextRect.origin.x = nCurX + nAttachOffset; + [pCurParent addSubview: [pTextView autorelease]]; + + aLeftColumn.push_back( ColumnItem( pTextView ) ); + + // move to nCurY + aTextRect.origin.y = nCurY - aTextRect.size.height; + [pTextView setFrame: aTextRect]; + + // update nCurY + nCurY = aTextRect.origin.y - 5; + + // indent the radio group relative to the text + // nOff = 20; + } + + // setup radio matrix + NSButtonCell* pProto = [[NSButtonCell alloc] init]; + + NSRect aRadioRect = { { nCurX + nOff, 0 }, { 280 - nCurX, 5*aChoices.getLength() } }; + [pProto setTitle: @"RadioButtonGroup"]; + [pProto setButtonType: NSRadioButton]; + NSMatrix* pMatrix = [[NSMatrix alloc] initWithFrame: aRadioRect + mode: NSRadioModeMatrix + prototype: (NSCell*)pProto + numberOfRows: aChoices.getLength() + numberOfColumns: 1]; + // get currently selected value + sal_Int32 nSelectVal = 0; + PropertyValue* pVal = pController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nSelectVal; + // set individual titles + NSArray* pCells = [pMatrix cells]; + for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) + { + NSCell* pCell = [pCells objectAtIndex: m]; + filterAccelerator( aChoices[m] ); + linebreakCell( pCell, aChoices[m] ); + //NSString* pTitle = CreateNSString( aChoices[m] ); + //[pCell setTitle: pTitle]; + // connect target and action + [pCell setTarget: pCtrlTarget]; + [pCell setAction: @selector(triggered:)]; + int nTag = pControllerProperties->addNameAndValueTag( aPropertyName, m ); + pControllerProperties->addObservedControl( pCell ); + [pCell setTag: nTag]; + //[pTitle release]; + // set current selection + if( nSelectVal == m ) + [pMatrix selectCellAtRow: m column: 0]; + } + [pMatrix sizeToFit]; + aRadioRect = [pMatrix frame]; + + // move it down, so it comes to the correct position + aRadioRect.origin.y = nCurY - aRadioRect.size.height; + [pMatrix setFrame: aRadioRect]; + [pCurParent addSubview: [pMatrix autorelease]]; + + aRightColumn.push_back( ColumnItem( pMatrix ) ); + + // update nCurY + nCurY = aRadioRect.origin.y - 5; + + [pProto release]; + } + else if( aCtrlType.equalsAscii( "List" ) && pCurParent ) + { + // don't indent attached lists, looks bad in the existing cases + NSControl* pTextView = createLabel( aText ); + [pCurParent addSubview: [pTextView autorelease]]; + aLeftColumn.push_back( ColumnItem( pTextView ) ); + NSRect aTextRect = [pTextView frame]; + aTextRect.origin.x = nCurX /* + nAttachOffset*/; + + // don't indent attached lists, looks bad in the existing cases + NSRect aBtnRect = { { nCurX /*+ nAttachOffset*/ + aTextRect.size.width, 0 }, { 0, 15 } }; + NSPopUpButton* pBtn = [[NSPopUpButton alloc] initWithFrame: aBtnRect pullsDown: NO]; + + // iterate options + for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) + { + NSString* pItemText = CreateNSString( aChoices[m] ); + [pBtn addItemWithTitle: pItemText]; + NSMenuItem* pItem = [pBtn itemWithTitle: pItemText]; + int nTag = pControllerProperties->addNameAndValueTag( aPropertyName, m ); + [pItem setTag: nTag]; + [pItemText release]; + } + + PropertyValue* pVal = pController->getValue( aPropertyName ); + sal_Int32 aSelectVal = 0; + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= aSelectVal; + [pBtn selectItemAtIndex: aSelectVal]; + + // 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( aPropertyName )]; + + [pBtn sizeToFit]; + [pCurParent addSubview: [pBtn autorelease]]; + + aRightColumn.push_back( ColumnItem( pBtn ) ); + + // connect target and action + [pBtn setTarget: pCtrlTarget]; + [pBtn setAction: @selector(triggered:)]; + + // move to nCurY + aBtnRect = [pBtn frame]; + aBtnRect.origin.y = nCurY - 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 nCurY + nCurY = aBtnRect.origin.y - 5; + } + else if( (aCtrlType.equalsAscii( "Edit" ) || aCtrlType.equalsAscii( "Range" )) && pCurParent ) + { + sal_Int32 nOff = 0; + if( aText.getLength() ) + { + // add a label + NSControl* pTextView = createLabel( aText ); + [pCurParent addSubview: [pTextView autorelease]]; + + aLeftColumn.push_back( ColumnItem( pTextView ) ); + + // move to nCurY + NSRect aTextRect = [pTextView frame]; + aTextRect.origin.x = nCurX + nAttachOffset; + aTextRect.origin.y = nCurY - aTextRect.size.height; + [pTextView setFrame: aTextRect]; + + // update nCurY + nCurY = aTextRect.origin.y - 5; + + // and set the offset for the real edit field + nOff = aTextRect.size.width + 5; + } + + NSRect aFieldRect = { { nCurX + 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]]; + + aRightColumn.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( aPropertyName ); + [pFieldView setTag: nTag]; + // pControllerProperties->addNamedView( pFieldView, aPropertyName ); + + // move to nCurY + aFieldRect.origin.y = nCurY - aFieldRect.size.height; + [pFieldView setFrame: aFieldRect]; + + // current value + PropertyValue* pVal = pController->getValue( aPropertyName ); + if( aCtrlType.equalsAscii( "Range" ) ) + { + // add a stepper control + NSRect aStepFrame = { { 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]]; + + aRightColumn.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( pVal && pVal->Value.hasValue() ) + pVal->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( pVal && pVal->Value.hasValue() ) + { + rtl::OUString aValue; + pVal->Value >>= aValue; + if( aValue.getLength() ) + { + NSString* pText = CreateNSString( aValue ); + [pFieldView setStringValue: pText]; + [pText release]; + } + } + } + + // update nCurY + nCurY = aFieldRect.origin.y - 5; + + } + } + 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 diff --git a/vcl/aqua/source/gdi/aquaprintview.mm b/vcl/aqua/source/gdi/aquaprintview.mm index ba139da5f5a4..870b7cbab6f0 100755 --- a/vcl/aqua/source/gdi/aquaprintview.mm +++ b/vcl/aqua/source/gdi/aquaprintview.mm @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: aquaprintview.mm,v $ - * $Revision: 1.5 $ + * $Revision: 1.5.56.1 $ * * This file is part of OpenOffice.org. * @@ -33,15 +33,15 @@ #include "aquaprintview.h" #include "salprn.h" -#include "vcl/impprn.hxx" +#include "vcl/print.hxx" @implementation AquaPrintView --(id)initWithQPrinter: (ImplQPrinter*)pPrinter withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter +-(id)initWithController: (vcl::PrinterController*)pController withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter { NSRect aRect = { { 0, 0 }, [pInfoPrinter->getPrintInfo() paperSize] }; if( (self = [super initWithFrame: aRect]) != nil ) { - mpQPrinter = pPrinter; + mpController = pController; mpInfoPrinter = pInfoPrinter; } return self; @@ -79,6 +79,7 @@ int nPage = (int)(aPaperSize.width * rect.origin.y + rect.origin.x); // page count is 1 based - mpQPrinter->PrintPage( nPage-1 + mpInfoPrinter->getCurPageRangeStart() ); + if( nPage - 1 < (mpInfoPrinter->getCurPageRangeStart() + mpInfoPrinter->getCurPageRangeCount() ) ) + mpController->printFilteredPage( nPage-1 ); } @end diff --git a/vcl/aqua/source/gdi/makefile.mk b/vcl/aqua/source/gdi/makefile.mk index deb6832a5525..90b5e55b82db 100644 --- a/vcl/aqua/source/gdi/makefile.mk +++ b/vcl/aqua/source/gdi/makefile.mk @@ -62,6 +62,7 @@ SLOFILES= $(SLO)$/salmathutils.obj \ $(SLO)$/salvd.obj \ $(SLO)$/salprn.obj \ $(SLO)$/aquaprintview.obj \ + $(SLO)$/aquaprintaccessoryview.obj \ $(SLO)$/salbmp.obj .IF "$(ENABLE_CAIRO)" == "TRUE" diff --git a/vcl/aqua/source/gdi/salgdi.cxx b/vcl/aqua/source/gdi/salgdi.cxx index 263a5b6e6803..dedae3ac7cfc 100644 --- a/vcl/aqua/source/gdi/salgdi.cxx +++ b/vcl/aqua/source/gdi/salgdi.cxx @@ -604,7 +604,8 @@ void AquaSalGraphics::EndSetClipRegion() void AquaSalGraphics::SetLineColor() { maLineColor.SetAlpha( 0.0 ); // transparent - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); + if( CheckContext() ) + CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); } // ----------------------------------------------------------------------- @@ -612,7 +613,8 @@ void AquaSalGraphics::SetLineColor() void AquaSalGraphics::SetLineColor( SalColor nSalColor ) { maLineColor = RGBAColor( nSalColor ); - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); + if( CheckContext() ) + CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); } // ----------------------------------------------------------------------- @@ -620,7 +622,8 @@ void AquaSalGraphics::SetLineColor( SalColor nSalColor ) void AquaSalGraphics::SetFillColor() { maFillColor.SetAlpha( 0.0 ); // transparent - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); + if( CheckContext() ) + CGContextSetFillColor( mrContext, maFillColor.AsArray() ); } // ----------------------------------------------------------------------- @@ -628,7 +631,8 @@ void AquaSalGraphics::SetFillColor() void AquaSalGraphics::SetFillColor( SalColor nSalColor ) { maFillColor = RGBAColor( nSalColor ); - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); + if( CheckContext() ) + CGContextSetFillColor( mrContext, maFillColor.AsArray() ); } // ----------------------------------------------------------------------- diff --git a/vcl/aqua/source/gdi/salgdiutils.cxx b/vcl/aqua/source/gdi/salgdiutils.cxx index 99a1629006d2..6df50f79e9d0 100755 --- a/vcl/aqua/source/gdi/salgdiutils.cxx +++ b/vcl/aqua/source/gdi/salgdiutils.cxx @@ -68,6 +68,13 @@ void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, long nDPIX, lon mnRealDPIX = nDPIX; mnRealDPIY = nDPIY; + // a previously set clip path is now invalid + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = NULL; + } + if( mrContext ) { CGContextSetFillColorSpace( mrContext, GetSalData()->mxRGBSpace ); @@ -126,6 +133,28 @@ void AquaSalGraphics::SetVirDevGraphics( CGLayerRef xLayer, CGContextRef xContex // ---------------------------------------------------------------------- +void AquaSalGraphics::InvalidateContext() +{ + UnsetState(); + mrContext = 0; +} + +// ---------------------------------------------------------------------- + +void AquaSalGraphics::UnsetState() +{ + if( mrContext ) + { + CGContextRestoreGState( mrContext ); + mrContext = 0; + } + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = NULL; + } +} + void AquaSalGraphics::SetState() { CGContextRestoreGState( mrContext ); @@ -134,9 +163,9 @@ void AquaSalGraphics::SetState() // setup clipping if( mxClipPath ) { - CGContextBeginPath( mrContext ); // discard any existing path + CGContextBeginPath( mrContext ); // discard any existing path CGContextAddPath( mrContext, mxClipPath ); // set the current path to the clipping path - CGContextClip( mrContext ); // use it for clipping + CGContextClip( mrContext ); // use it for clipping } // set RGB colorspace and line and fill colors @@ -205,7 +234,7 @@ bool AquaSalGraphics::CheckContext() CGContextRelease( rReleaseContext ); } - DBG_ASSERT( mrContext, "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!\n" ); + DBG_ASSERT( mrContext || mbPrinter, "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!\n" ); return (mrContext != NULL); } diff --git a/vcl/aqua/source/gdi/salprn.cxx b/vcl/aqua/source/gdi/salprn.cxx index b9a1f4ef7748..47c027a033aa 100644 --- a/vcl/aqua/source/gdi/salprn.cxx +++ b/vcl/aqua/source/gdi/salprn.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: salprn.cxx,v $ - * $Revision: 1.16 $ + * $Revision: 1.16.56.2 $ * * This file is part of OpenOffice.org. * @@ -38,7 +38,6 @@ #include "saldata.hxx" #include "vcl/jobset.h" #include "vcl/salptype.hxx" -#include "vcl/impprn.hxx" #include "vcl/print.hxx" #include "vcl/unohelp.hxx" @@ -47,11 +46,13 @@ #include "com/sun/star/lang/XMultiServiceFactory.hpp" #include "com/sun/star/container/XNameAccess.hpp" #include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/awt/Size.hpp" #include <algorithm> using namespace rtl; using namespace vcl; +using namespace com::sun::star; using namespace com::sun::star::uno; using namespace com::sun::star::lang; using namespace com::sun::star::beans; @@ -67,7 +68,9 @@ AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo& i_rQueue ) : mpPrintInfo( nil ), mePageOrientation( ORIENTATION_PORTRAIT ), mnStartPageOffsetX( 0 ), - mnStartPageOffsetY( 0 ) + mnStartPageOffsetY( 0 ), + mnCurPageRangeStart( 0 ), + mnCurPageRangeCount( 0 ) { NSString* pStr = CreateNSString( i_rQueue.maPrinterName ); mpPrinter = [NSPrinter printerWithName: pStr]; @@ -87,6 +90,7 @@ AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo& i_rQueue ) : const int nWidth = 100, nHeight = 100; maContextMemory.reset( reinterpret_cast<sal_uInt8*>( rtl_allocateMemory( nWidth * 4 * nHeight ) ), boost::bind( rtl_freeMemory, _1 ) ); + if( maContextMemory ) { mrContext = CGBitmapContextCreate( maContextMemory.get(), nWidth, nHeight, 8, nWidth * 4, GetSalData()->mxRGBSpace, kCGImageAlphaNoneSkipFirst ); @@ -134,7 +138,7 @@ void AquaSalInfoPrinter::SetupPrinterGraphics( CGContextRef i_rContext ) const dY -= aPaperSize.height - aImageRect.size.height - aImageRect.origin.y; CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetX, dY - mnStartPageOffsetY ); // scale to be top/down and reflect our "virtual" DPI - CGContextScaleCTM( i_rContext, 0.1, -0.1 ); + CGContextScaleCTM( i_rContext, 72.0/double(nDPIX), -(72.0/double(nDPIY)) ); } else { @@ -148,7 +152,7 @@ void AquaSalInfoPrinter::SetupPrinterGraphics( CGContextRef i_rContext ) const dY = -aPaperSize.width; CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetY, dY - mnStartPageOffsetX ); // scale to be top/down and reflect our "virtual" DPI - CGContextScaleCTM( i_rContext, -0.1, 0.1 ); + CGContextScaleCTM( i_rContext, -(72.0/double(nDPIY)), (72.0/double(nDPIX)) ); } mpGraphics->SetPrinterGraphics( i_rContext, nDPIX, nDPIY, 1.0 ); } @@ -296,6 +300,28 @@ BOOL AquaSalInfoPrinter::SetPrinterData( ImplJobSetup* io_pSetupData ) // ----------------------------------------------------------------------- +void AquaSalInfoPrinter::setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation ) +{ + + Orientation ePaperOrientation = ORIENTATION_PORTRAIT; + const PaperInfo* pPaper = matchPaper( i_nWidth, i_nHeight, ePaperOrientation ); + + if( pPaper ) + { + NSString* pPaperName = [CreateNSString( rtl::OStringToOUString(PaperInfo::toPSName(pPaper->getPaper()), RTL_TEXTENCODING_ASCII_US) ) autorelease]; + [mpPrintInfo setPaperName: pPaperName]; + } + else if( i_nWidth > 0 && i_nHeight > 0 ) + { + NSSize aPaperSize = { TenMuToPt(i_nWidth), TenMuToPt(i_nHeight) }; + [mpPrintInfo setPaperSize: aPaperSize]; + } + // this seems counterintuitive + mePageOrientation = i_eSetOrientation; +} + +// ----------------------------------------------------------------------- + BOOL AquaSalInfoPrinter::SetData( ULONG i_nFlags, ImplJobSetup* io_pSetupData ) { if( ! io_pSetupData || io_pSetupData->mnSystem != JOBSETUP_SYSTEM_MAC ) @@ -304,31 +330,32 @@ BOOL AquaSalInfoPrinter::SetData( ULONG i_nFlags, ImplJobSetup* io_pSetupData ) if( mpPrintInfo ) { + if( (i_nFlags & SAL_JOBSET_ORIENTATION) != 0 ) + mePageOrientation = io_pSetupData->meOrientation; + if( (i_nFlags & SAL_JOBSET_PAPERSIZE) != 0) { // set paper format - double width = 0, height = 0; + long width = 21000, height = 29700; if( io_pSetupData->mePaperFormat == PAPER_USER ) { // #i101108# sanity check if( io_pSetupData->mnPaperWidth && io_pSetupData->mnPaperHeight ) { - width = TenMuToPt( io_pSetupData->mnPaperWidth ); - height = TenMuToPt( io_pSetupData->mnPaperHeight ); + width = io_pSetupData->mnPaperWidth; + height = io_pSetupData->mnPaperHeight; } } else - getPaperSize( width, height, io_pSetupData->mePaperFormat ); - - if( width > 0 && height > 0 ) { - NSSize aPaperSize = { width, height }; - [mpPrintInfo setPaperSize: aPaperSize]; + double w = 595, h = 842; + getPaperSize( w, h, io_pSetupData->mePaperFormat ); + width = static_cast<long>(PtTo10Mu( w )); + height = static_cast<long>(PtTo10Mu( h )); } - } - if( (i_nFlags & SAL_JOBSET_ORIENTATION) != 0 ) - mePageOrientation = io_pSetupData->meOrientation; + setPaperSize( width, height, mePageOrientation ); + } } return mpPrintInfo != nil; @@ -424,6 +451,8 @@ ULONG AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup* i_pSetupData, USH return 0; case PRINTER_CAPABILITIES_SETORIENTATION: return 1; + case PRINTER_CAPABILITIES_SETDUPLEX: + return 0; case PRINTER_CAPABILITIES_SETPAPERBIN: return 0; case PRINTER_CAPABILITIES_SETPAPERSIZE: @@ -432,6 +461,8 @@ ULONG AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup* i_pSetupData, USH return 1; case PRINTER_CAPABILITIES_EXTERNALDIALOG: return getUseNativeDialog() ? 1 : 0; + case PRINTER_CAPABILITIES_PDF: + return 1; default: break; }; return 0; @@ -470,58 +501,129 @@ void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup*, } } -BOOL AquaSalInfoPrinter::StartJob( const String* pFileName, - const String& rAppName, - ImplJobSetup* pSetupData, - ImplQPrinter* pQPrinter, - bool bIsQuickJob ) +static Size getPageSize( vcl::PrinterController& i_rController, sal_Int32 i_nPage ) +{ + Size aPageSize; + Sequence< PropertyValue > aPageParms( i_rController.getPageParameters( i_nPage ) ); + for( sal_Int32 nProperty = 0, nPropertyCount = aPageParms.getLength(); nProperty < nPropertyCount; ++nProperty ) + { + if( aPageParms[ nProperty ].Name.equalsAscii( "PageSize" ) ) + { + awt::Size aSize; + aPageParms[ nProperty].Value >>= aSize; + aPageSize.Width() = aSize.Width; + aPageSize.Height() = aSize.Height; + break; + } + } + return aPageSize; +} + +BOOL AquaSalInfoPrinter::StartJob( const String* i_pFileName, + const String& i_rJobName, + const String& i_rAppName, + ImplJobSetup* i_pSetupData, + vcl::PrinterController& i_rController + ) { if( mbJob ) return FALSE; BOOL bSuccess = FALSE; - std::vector<ULONG> aPaperRanges; - if( ! pQPrinter->GetPaperRanges( aPaperRanges, true ) ) - return FALSE; - - size_t nRanges = aPaperRanges.size(); + bool bWasAborted = false; AquaSalInstance* pInst = GetSalData()->mpFirstInstance; - - for( ULONG nCurRange = 0; nCurRange < nRanges-1; nCurRange++ ) + PrintAccessoryViewState aAccViewState; + sal_Int32 nAllPages = 0; + + aAccViewState.bNeedRestart = true; + + // reset IsLastPage + i_rController.setLastPage( sal_False ); + + // update job data + if( i_pSetupData ) + SetData( ~0, i_pSetupData ); + + // do we want a progress panel ? + sal_Bool bShowProgressPanel = sal_True; + beans::PropertyValue* pMonitor = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) ); + if( pMonitor ) + pMonitor->Value >>= bShowProgressPanel; + if( ! i_rController.isShowDialogs() ) + bShowProgressPanel = sal_False; + + // FIXME: jobStarted() should be done after the print dialog has ended (if there is one) + // how do I know when that might be ? + i_rController.jobStarted(); + do { - mnStartPageOffsetX = mnStartPageOffsetY = 0; + if( aAccViewState.bNeedRestart ) + { + mnCurPageRangeStart = 0; + mnCurPageRangeCount = 0; + nAllPages = i_rController.getFilteredPageCount(); + } - // update job data - ImplJobSetup* pSetup = pQPrinter->GetPageSetup( aPaperRanges[ nCurRange ] ); - if( pSetup ) - SetData( ~0, pSetup ); - DBG_ASSERT( pSetup, "no job setup for range" ); + aAccViewState.bNeedRestart = false; + + Size aCurSize( 21000, 29700 ); + if( nAllPages > 0 ) + { + mnCurPageRangeCount = 1; + aCurSize = getPageSize( i_rController, mnCurPageRangeStart ); + Size aNextSize( aCurSize ); + + // print pages up to a different size + while( mnCurPageRangeCount + mnCurPageRangeStart < nAllPages ) + { + aNextSize = getPageSize( i_rController, mnCurPageRangeStart + mnCurPageRangeCount ); + if( aCurSize == aNextSize // same page size + || + (aCurSize.Width() == aNextSize.Height() && aCurSize.Height() == aNextSize.Width()) // same size, but different orientation + ) + { + mnCurPageRangeCount++; + } + else + break; + } + } + else + mnCurPageRangeCount = 0; + + // now for the current run + mnStartPageOffsetX = mnStartPageOffsetY = 0; + // setup the paper size and orientation + // do this on our associated Printer object, since that is + // out interface to the applications which occasionally rely on the paper + // information (e.g. brochure printing scales to the found paper size) + // also SetPaperSizeUser has the advantage that we can share a + // platform independent paper matching algorithm + boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() ); + pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); + pPrinter->SetPaperSizeUser( aCurSize, true ); - mnCurPageRangeStart = aPaperRanges[nCurRange]; - mnCurPageRangeCount = aPaperRanges[nCurRange+1] - aPaperRanges[nCurRange]; // create view - NSView* pPrintView = [[AquaPrintView alloc] initWithQPrinter: pQPrinter withInfoPrinter: this]; + NSView* pPrintView = [[AquaPrintView alloc] initWithController: &i_rController withInfoPrinter: this]; NSMutableDictionary* pPrintDict = [mpPrintInfo dictionary]; // set filename - if( pFileName ) + if( i_pFileName ) { [mpPrintInfo setJobDisposition: NSPrintSaveJob]; - NSString* pPath = CreateNSString( *pFileName ); + NSString* pPath = CreateNSString( *i_pFileName ); [pPrintDict setObject: pPath forKey: NSPrintSavePath]; [pPath release]; - - // in this case we can only deliver the print job in one file - mnCurPageRangeStart = 0; - mnCurPageRangeCount = aPaperRanges.back(); - nCurRange = nRanges; } - [pPrintDict setObject: [[NSNumber numberWithInt: (int)pQPrinter->GetCopyCount()] autorelease] forKey: NSPrintCopies]; + [pPrintDict setObject: [[NSNumber numberWithInt: (int)i_rController.getPrinter()->GetCopyCount()] autorelease] forKey: NSPrintCopies]; [pPrintDict setObject: [[NSNumber numberWithBool: YES] autorelease] forKey: NSPrintDetailedErrorReporting]; [pPrintDict setObject: [[NSNumber numberWithInt: 1] autorelease] forKey: NSPrintFirstPage]; - [pPrintDict setObject: [[NSNumber numberWithInt: (int)mnCurPageRangeCount] autorelease] forKey: NSPrintLastPage]; + // #i103253# weird: for some reason, autoreleasing the value below like the others above + // leads do a double free malloc error. Why this value should behave differently from all the others + // is a mystery. + [pPrintDict setObject: [NSNumber numberWithInt: mnCurPageRangeCount] forKey: NSPrintLastPage]; // create print operation @@ -529,17 +631,47 @@ BOOL AquaSalInfoPrinter::StartJob( const String* pFileName, if( pPrintOperation ) { - bool bShowPanel = (! bIsQuickJob && getUseNativeDialog() ); + NSObject* pReleaseAfterUse = nil; + bool bShowPanel = (! i_rController.isDirectPrint() && getUseNativeDialog() && i_rController.isShowDialogs() ); [pPrintOperation setShowsPrintPanel: bShowPanel ? YES : NO ]; - // [pPrintOperation setShowsProgressPanel: NO]; + [pPrintOperation setShowsProgressPanel: bShowProgressPanel ? YES : NO]; + + // set job title (since MacOSX 10.5) + if( [pPrintOperation respondsToSelector: @selector(setJobTitle:)] ) + [pPrintOperation performSelector: @selector(setJobTitle:) withObject: [CreateNSString( i_rJobName ) autorelease]]; + + if( bShowPanel && mnCurPageRangeStart == 0 ) // only the first range of pages gets the accesory view + pReleaseAfterUse = [AquaPrintAccessoryView setupPrinterPanel: pPrintOperation withController: &i_rController withState: &aAccViewState]; + bSuccess = TRUE; mbJob = true; pInst->startedPrintJob(); [pPrintOperation runOperation]; pInst->endedPrintJob(); + bWasAborted = [[[pPrintOperation printInfo] jobDisposition] compare: NSPrintCancelJob] == NSOrderedSame; mbJob = false; + if( pReleaseAfterUse ) + [pReleaseAfterUse release]; } - } + + mnCurPageRangeStart += mnCurPageRangeCount; + mnCurPageRangeCount = 1; + } while( aAccViewState.bNeedRestart || mnCurPageRangeStart + mnCurPageRangeCount < nAllPages ); + + // inform application that it can release its data + // this is awkward, but the XRenderable interface has no method for this, + // so we need to call XRenderadble::render one last time with IsLastPage = TRUE + i_rController.setLastPage( sal_True ); + GDIMetaFile aPageFile; + if( mrContext ) + SetupPrinterGraphics( mrContext ); + i_rController.getFilteredPageFile( 0, aPageFile ); + + i_rController.setJobState( bWasAborted + ? view::PrintableState_JOB_ABORTED + : view::PrintableState_JOB_SPOOLED ); + + mnCurPageRangeStart = mnCurPageRangeCount = 0; return bSuccess; } @@ -581,6 +713,7 @@ SalGraphics* AquaSalInfoPrinter::StartPage( ImplJobSetup* i_pSetupData, BOOL i_b BOOL AquaSalInfoPrinter::EndPage() { + mpGraphics->InvalidateContext(); return TRUE; } @@ -606,31 +739,24 @@ AquaSalPrinter::~AquaSalPrinter() // ----------------------------------------------------------------------- -BOOL AquaSalPrinter::StartJob( const String* pFileName, - const String& rAppName, - ImplJobSetup* pSetupData, - ImplQPrinter* pQPrinter ) +BOOL AquaSalPrinter::StartJob( const String* i_pFileName, + const String& i_rJobName, + const String& i_rAppName, + ImplJobSetup* i_pSetupData, + vcl::PrinterController& i_rController ) { - bool bIsQuickJob = false; - std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator quick_it = - pSetupData->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ) ); - - if( quick_it != pSetupData->maValueMap.end() ) - { - if( quick_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) - bIsQuickJob = true; - } - - return mpInfoPrinter->StartJob( pFileName, rAppName, pSetupData, pQPrinter, bIsQuickJob ); + return mpInfoPrinter->StartJob( i_pFileName, i_rJobName, i_rAppName, i_pSetupData, i_rController ); } // ----------------------------------------------------------------------- BOOL AquaSalPrinter::StartJob( const XubString* i_pFileName, - const XubString& i_rJobName, - const XubString& i_rAppName, - ULONG i_nCopies, BOOL i_bCollate, - ImplJobSetup* i_pSetupData ) + const XubString& i_rJobName, + const XubString& i_rAppName, + ULONG i_nCopies, + bool i_bCollate, + bool i_bDirect, + ImplJobSetup* i_pSetupData ) { DBG_ERROR( "should never be called" ); return FALSE; @@ -671,20 +797,62 @@ ULONG AquaSalPrinter::GetErrorCode() return mpInfoPrinter->GetErrorCode(); } -//////////////////////////// -////// IMPLEMENT US ///// -//////////////////////////// - -DuplexMode AquaSalInfoPrinter::GetDuplexMode( const ImplJobSetup* i_pSetupData ) +void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* i_pSetupData ) { - return DUPLEX_UNKNOWN; + m_aPaperFormats.clear(); + m_bPapersInit = true; + + if( mpPrinter ) + { + if( [mpPrinter statusForTable: @"PPD"] == NSPrinterTableOK ) + { + NSArray* pPaperNames = [mpPrinter stringListForKey: @"PageSize" inTable: @"PPD"]; + if( pPaperNames ) + { + unsigned int nPapers = [pPaperNames count]; + for( unsigned int i = 0; i < nPapers; i++ ) + { + NSString* pPaper = [pPaperNames objectAtIndex: i]; + NSSize aPaperSize = [mpPrinter pageSizeForPaper: pPaper]; + if( aPaperSize.width > 0 && aPaperSize.height > 0 ) + { + PaperInfo aInfo( PtTo10Mu( aPaperSize.width ), + PtTo10Mu( aPaperSize.height ) ); + m_aPaperFormats.push_back( aInfo ); + } + } + } + } + } } -void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* i_pSetupData ) +const PaperInfo* AquaSalInfoPrinter::matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const { + if( ! m_bPapersInit ) + const_cast<AquaSalInfoPrinter*>(this)->InitPaperFormats( NULL ); + + const PaperInfo* pMatch = NULL; + o_rOrientation = ORIENTATION_PORTRAIT; + for( int n = 0; n < 2 ; n++ ) + { + for( size_t i = 0; i < m_aPaperFormats.size(); i++ ) + { + if( abs( m_aPaperFormats[i].getWidth() - i_nWidth ) < 50 && + abs( m_aPaperFormats[i].getHeight() - i_nHeight ) < 50 ) + { + pMatch = &m_aPaperFormats[i]; + return pMatch; + } + } + o_rOrientation = ORIENTATION_LANDSCAPE; + std::swap( i_nWidth, i_nHeight ); + } + return pMatch; } int AquaSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* i_pSetupData ) { - return 0; + return 900; } + + diff --git a/vcl/inc/vcl/arrange.hxx b/vcl/inc/vcl/arrange.hxx new file mode 100644 index 000000000000..309d0bf930ea --- /dev/null +++ b/vcl/inc/vcl/arrange.hxx @@ -0,0 +1,425 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: accel.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _VCL_ARRANGE_HXX +#define _VCL_ARRANGE_HXX + +#include "vcl/window.hxx" + +#include <vector> +#include <map> +#include <boost/shared_ptr.hpp> + +namespace vcl +{ + /* some helper classes for simple window layouting + guidelines: + - a WindowArranger is not a Window + - a WindowArranger hierarchy manages exactly one level of child windows inside a common parent + this is to keep the vcl Window hierarchy flat, as some code like accelerators depend on such behavior + - a WindowArranger never becomes owner of a Window, windows need to be destroyed separately + - a WindowArranger however always is owner of its child WindowArrangers, that is the + WindowArranger hierarchy will keep track of its objects and delete them + - a managed element of a WindowArranger can either be a Window (a leaf in the hierarchy) + or a child WindowArranger (a node in the hierarchy), but never both + */ + + class WindowArranger + { + protected: + struct Element + { + Window* m_pElement; + boost::shared_ptr<WindowArranger> m_pChild; + sal_Int32 m_nExpandPriority; + Size m_aMinSize; + bool m_bHidden; + long m_nLeftBorder; + long m_nTopBorder; + long m_nRightBorder; + long m_nBottomBorder; + + Element() + : m_pElement( NULL ) + , m_pChild() + , m_nExpandPriority( 0 ) + , m_bHidden( false ) + , m_nLeftBorder( 0 ) + , m_nTopBorder( 0 ) + , m_nRightBorder( 0 ) + , m_nBottomBorder( 0 ) + {} + + Element( Window* i_pWin, + boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(), + sal_Int32 i_nExpandPriority = 0 + ) + : m_pElement( i_pWin ) + , m_pChild( i_pChild ) + , m_nExpandPriority( i_nExpandPriority ) + , m_bHidden( false ) + , m_nLeftBorder( 0 ) + , m_nTopBorder( 0 ) + , m_nRightBorder( 0 ) + , m_nBottomBorder( 0 ) + {} + + void deleteChild() { m_pChild.reset(); } + + sal_Int32 getExpandPriority() const; + Size getOptimalSize( WindowSizeType ) const; + bool isVisible() const; + void setPosSize( const Point&, const Size& ); + }; + + Window* m_pParentWindow; + WindowArranger* m_pParentArranger; + Rectangle m_aManagedArea; + long m_nOuterBorder; + + virtual Element* getElement( size_t i_nIndex ) = 0; + const Element* getConstElement( size_t i_nIndex ) const + { return const_cast<WindowArranger*>(this)->getElement( i_nIndex ); } + + + public: + WindowArranger( WindowArranger* i_pParent = NULL ) + : m_pParentWindow( i_pParent ? i_pParent->m_pParentWindow : NULL ) + , m_pParentArranger( i_pParent ) + , m_nOuterBorder( 0 ) + {} + virtual ~WindowArranger(); + + // ask what would be the optimal size + virtual Size getOptimalSize( WindowSizeType ) const = 0; + // call Resize to trigger layouting inside the managed area + // without function while parent window is unset + virtual void resize() = 0; + // avoid this if possible, using the constructor instead + // there can be only one parent window and all managed windows MUST + // be direct children of that window + // violating that condition will result in undefined behavior + virtual void setParentWindow( Window* ); + + virtual void setParent( WindowArranger* ); + + virtual size_t countElements() const = 0; + boost::shared_ptr<WindowArranger> getChild( size_t i_nIndex ) const + { + const Element* pEle = getConstElement( i_nIndex ); + return pEle ? pEle->m_pChild : boost::shared_ptr<WindowArranger>(); + } + Window* getWindow( size_t i_nIndex ) const + { + const Element* pEle = getConstElement( i_nIndex ); + return pEle ? pEle->m_pElement : NULL; + } + + virtual bool isVisible() const; // true if any element is visible + + sal_Int32 getExpandPriority( size_t i_nIndex ) const + { + const Element* pEle = getConstElement( i_nIndex ); + return pEle ? pEle->getExpandPriority() : 0; + } + + Size getMinimumSize( size_t i_nIndex ) const + { + const Element* pEle = getConstElement( i_nIndex ); + return pEle ? pEle->m_aMinSize : Size(); + } + + bool setMinimumSize( size_t i_nIndex, const Size& i_rMinSize ) + { + Element* pEle = getElement( i_nIndex ); + if( pEle ) + pEle->m_aMinSize = i_rMinSize; + return pEle != NULL; + } + + void setBorders( size_t i_nIndex, long i_nLeft, long i_nTop, long i_nRight, long i_nBottom ) + { + Element* pEle = getElement( i_nIndex ); + if( pEle ) + { + pEle->m_nLeftBorder = i_nLeft; + pEle->m_nRightBorder = i_nRight; + pEle->m_nTopBorder = i_nTop; + pEle->m_nBottomBorder = i_nBottom; + } + } + + void show( bool i_bShow = true, bool i_bImmediateUpdate = true ); + + void setManagedArea( const Rectangle& i_rArea ) + { + m_aManagedArea = i_rArea; + resize(); + } + const Rectangle& getManagedArea() const { return m_aManagedArea; } + + void setOuterBorder( long i_nBorder ) + { + m_nOuterBorder = i_nBorder; + resize(); + } + }; + + class RowOrColumn : public WindowArranger + { + long m_nBorderWidth; + bool m_bColumn; + + std::vector< WindowArranger::Element > m_aElements; + + void distributeRowWidth( std::vector< Size >& io_rSizes, long i_nUsedWidth, long i_nExtraWidth ); + void distributeColumnHeight( std::vector< Size >& io_rSizes, long i_nUsedHeight, long i_nExtraHeight ); + protected: + virtual Element* getElement( size_t i_nIndex ) + { return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; } + + public: + RowOrColumn( WindowArranger* i_pParent = NULL, + bool bColumn = true, long i_nBorderWidth = 5 ) + : WindowArranger( i_pParent ) + , m_nBorderWidth( i_nBorderWidth ) + , m_bColumn( bColumn ) + {} + + virtual ~RowOrColumn(); + + virtual Size getOptimalSize( WindowSizeType ) const; + virtual void resize(); + virtual size_t countElements() const { return m_aElements.size(); } + + // add a managed window at the given index + // an index smaller than zero means add the window at the end + size_t addWindow( Window*, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 ); + void remove( Window* ); + + size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 ); + // convenience: use for addChild( new WindowArranger( ... ) ) constructs + size_t addChild( WindowArranger* i_pNewChild, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 ) + { return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nExpandPrio, i_nIndex ); } + void remove( boost::shared_ptr<WindowArranger> const & ); + + long getBorderWidth() const { return m_nBorderWidth; } + }; + + class LabeledElement : public WindowArranger + { + WindowArranger::Element m_aLabel; + WindowArranger::Element m_aElement; + long m_nDistance; + long m_nLabelColumnWidth; + int m_nLabelStyle; + protected: + virtual Element* getElement( size_t i_nIndex ) + { + if( i_nIndex == 0 ) + return &m_aLabel; + else if( i_nIndex == 1 ) + return &m_aElement; + return 0; + } + + public: + LabeledElement( WindowArranger* i_pParent = NULL, int i_nLabelStyle = 0, long i_nDistance = 5 ) + : WindowArranger( i_pParent ) + , m_nDistance( i_nDistance ) + , m_nLabelColumnWidth( 0 ) + , m_nLabelStyle( i_nLabelStyle ) + {} + + virtual ~LabeledElement(); + + virtual Size getOptimalSize( WindowSizeType ) const; + virtual void resize(); + virtual size_t countElements() const { return 2; } + + void setLabel( Window* ); + void setLabel( boost::shared_ptr<WindowArranger> const & ); + void setElement( Window* ); + void setElement( boost::shared_ptr<WindowArranger> const & ); + void setLabelColumnWidth( long i_nWidth ) + { m_nLabelColumnWidth = i_nWidth; } + + Size getLabelSize( WindowSizeType i_eType ) const + { return m_aLabel.getOptimalSize( i_eType ); } + Size getElementSize( WindowSizeType i_eType ) const + { return m_aElement.getOptimalSize( i_eType ); } + }; + + class LabelColumn : public RowOrColumn + { + long getLabelWidth() const; + public: + LabelColumn( WindowArranger* i_pParent = NULL, long i_nBorderWidth = 5 ) + : RowOrColumn( i_pParent, true, i_nBorderWidth ) + {} + virtual ~LabelColumn(); + + virtual Size getOptimalSize( WindowSizeType ) const; + virtual void resize(); + + // returns the index of the added label + size_t addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent = 0 ); + size_t addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent = 0 ); + }; + + class Indenter : public WindowArranger + { + long m_nIndent; + WindowArranger::Element m_aElement; + + protected: + virtual Element* getElement( size_t i_nIndex ) + { return i_nIndex == 0 ? &m_aElement : NULL; } + + public: + Indenter( WindowArranger* i_pParent = NULL, long i_nIndent = 15 ) + : WindowArranger( i_pParent ) + , m_nIndent( i_nIndent ) + {} + + virtual ~Indenter(); + + virtual Size getOptimalSize( WindowSizeType ) const; + virtual void resize(); + virtual size_t countElements() const { return (m_aElement.m_pElement != 0 || m_aElement.m_pChild != 0) ? 1 : 0; } + + void setIndent( long i_nIndent ) + { + m_nIndent = i_nIndent; + resize(); + } + + void setWindow( Window*, sal_Int32 i_nExpandPrio = 0 ); + void setChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0 ); + // convenience: use for setChild( new WindowArranger( ... ) ) constructs + void setChild( WindowArranger* i_pChild, sal_Int32 i_nExpandPrio = 0 ) + { setChild( boost::shared_ptr<WindowArranger>( i_pChild ), i_nExpandPrio ); } + }; + + class Spacer : public WindowArranger + { + WindowArranger::Element m_aElement; + Size m_aSize; + + protected: + virtual Element* getElement( size_t i_nIndex ) + { return i_nIndex == 0 ? &m_aElement : NULL; } + + public: + Spacer( WindowArranger* i_pParent = NULL, sal_Int32 i_nPrio = 20, const Size& i_rSize = Size( 0, 0 ) ) + : WindowArranger( i_pParent ) + , m_aElement( NULL, boost::shared_ptr<WindowArranger>(), i_nPrio ) + , m_aSize( i_rSize ) + {} + + virtual ~Spacer() {} + + virtual Size getOptimalSize( WindowSizeType ) const + { return m_aSize; } + virtual void resize() {} + virtual void setParentWindow( Window* ) {} + virtual size_t countElements() const { return 1; } + virtual bool isVisible() const { return true; } + }; + + class MatrixArranger : public WindowArranger + { + long m_nBorderX; + long m_nBorderY; + + struct MatrixElement : public WindowArranger::Element + { + sal_uInt32 m_nX; + sal_uInt32 m_nY; + + MatrixElement() + : WindowArranger::Element() + , m_nX( 0 ) + , m_nY( 0 ) + {} + + MatrixElement( Window* i_pWin, + sal_uInt32 i_nX, sal_uInt32 i_nY, + boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(), + sal_Int32 i_nExpandPriority = 0 + ) + : WindowArranger::Element( i_pWin, i_pChild, i_nExpandPriority ) + , m_nX( i_nX ) + , m_nY( i_nY ) + { + } + }; + + std::vector< MatrixElement > m_aElements; + std::map< sal_uInt64, size_t > m_aMatrixMap; // maps (x | (y << 32)) to index in m_aElements + + sal_uInt64 getMap( sal_uInt32 i_nX, sal_uInt32 i_nY ) + { return static_cast< sal_uInt64 >(i_nX) | (static_cast< sal_uInt64>(i_nY) << 32 ); } + + Size getOptimalSize( WindowSizeType, std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights ) const; + protected: + virtual Element* getElement( size_t i_nIndex ) + { return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; } + + public: + MatrixArranger( WindowArranger* i_pParent = NULL, + long i_nBorderX = 5, + long i_nBorderY = 5 ) + : WindowArranger( i_pParent ) + , m_nBorderX( i_nBorderX ) + , m_nBorderY( i_nBorderY ) + {} + + virtual ~MatrixArranger(); + + virtual Size getOptimalSize( WindowSizeType ) const; + virtual void resize(); + virtual size_t countElements() const { return m_aElements.size(); } + + // add a managed window at the given matrix position + size_t addWindow( Window*, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 ); + void remove( Window* ); + + size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 ); + // convenience: use for addChild( new WindowArranger( ... ) ) constructs + size_t addChild( WindowArranger* i_pNewChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 ) + { return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nX, i_nY, i_nExpandPrio ); } + void remove( boost::shared_ptr<WindowArranger> const & ); + }; + +} + +#endif + diff --git a/vcl/inc/vcl/button.hxx b/vcl/inc/vcl/button.hxx index b80edf6712cd..b5f70217e149 100644 --- a/vcl/inc/vcl/button.hxx +++ b/vcl/inc/vcl/button.hxx @@ -425,7 +425,6 @@ private: SAL_DLLPRIVATE void ImplInitCheckBoxData(); SAL_DLLPRIVATE WinBits ImplInitStyle( const Window* pPrevWindow, WinBits nStyle ); SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground ); - SAL_DLLPRIVATE void ImplDrawCheckBoxState(); SAL_DLLPRIVATE void ImplInvalidateOrDrawCheckBoxState(); SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags, const Point& rPos, const Size& rSize, @@ -450,10 +449,12 @@ protected: SAL_DLLPRIVATE virtual const Color& GetCanonicalTextColor( const StyleSettings& _rStyle ) const; + SAL_DLLPRIVATE virtual void ImplDrawCheckBoxState(); + SAL_DLLPRIVATE const Rectangle& GetStateRect() const { return maStateRect; } + SAL_DLLPRIVATE const Rectangle& GetMouseRect() const { return maMouseRect; } public: SAL_DLLPRIVATE void ImplCheck(); SAL_DLLPRIVATE void ImplSetMinimumNWFSize(); - public: CheckBox( Window* pParent, WinBits nStyle = 0 ); CheckBox( Window* pParent, const ResId& rResId ); @@ -552,4 +553,15 @@ public: ~TriStateBox(); }; +class VCL_DLLPUBLIC DisclosureButton : public CheckBox +{ +protected: + SAL_DLLPRIVATE virtual void ImplDrawCheckBoxState(); +public: + DisclosureButton( Window* pParent, WinBits nStyle = 0 ); + DisclosureButton( Window* pParent, const ResId& rResId ); + + virtual void KeyInput( const KeyEvent& rKEvt ); +}; + #endif // _SV_BUTTON_HXX diff --git a/vcl/inc/vcl/configsettings.hxx b/vcl/inc/vcl/configsettings.hxx index aee684a84ca4..211ea3f0892b 100644 --- a/vcl/inc/vcl/configsettings.hxx +++ b/vcl/inc/vcl/configsettings.hxx @@ -54,7 +54,6 @@ namespace vcl std::hash_map< rtl::OUString, SmallOUStrMap, rtl::OUStringHash > m_aSettings; virtual void Notify( const com::sun::star::uno::Sequence< rtl::OUString >& rPropertyNames ); - virtual void Commit(); void getValues(); SettingsConfigItem(); @@ -65,6 +64,8 @@ namespace vcl const rtl::OUString& getValue( const rtl::OUString& rGroup, const rtl::OUString& rKey ) const; void setValue( const rtl::OUString& rGroup, const rtl::OUString& rKey, const rtl::OUString& rValue ); + + virtual void Commit(); }; //........................................................................ diff --git a/vcl/inc/vcl/fixed.hxx b/vcl/inc/vcl/fixed.hxx index a5c834fce486..d6ffc1625afe 100644 --- a/vcl/inc/vcl/fixed.hxx +++ b/vcl/inc/vcl/fixed.hxx @@ -187,6 +187,7 @@ public: virtual void StateChanged( StateChangedType nType ); virtual void DataChanged( const DataChangedEvent& rDCEvt ); virtual void UserDraw( const UserDrawEvent& rUDEvt ); + virtual Size GetOptimalSize(WindowSizeType eType) const; void SetImage( const Image& rImage ); const Image& GetImage() const { return maImage; } diff --git a/vcl/inc/vcl/gdimtf.hxx b/vcl/inc/vcl/gdimtf.hxx index c53460d35584..e4acd55439cc 100644 --- a/vcl/inc/vcl/gdimtf.hxx +++ b/vcl/inc/vcl/gdimtf.hxx @@ -164,6 +164,7 @@ public: void Scale( double fScaleX, double fScaleY ); void Scale( const Fraction& rScaleX, const Fraction& rScaleY ); void Rotate( long nAngle10 ); + void Clip( const Rectangle& ); /* get the bound rect of the contained actions * caveats: * - clip actions will limit the contained actions, diff --git a/vcl/inc/vcl/impprn.hxx b/vcl/inc/vcl/impprn.hxx index c86090e8b49f..0cd6e9688201 100644 --- a/vcl/inc/vcl/impprn.hxx +++ b/vcl/inc/vcl/impprn.hxx @@ -28,7 +28,7 @@ * ************************************************************************/ -#ifndef _SV_IMPPRN_HXX +#if 0 #define _SV_IMPPRN_HXX #include <vcl/print.hxx> @@ -107,7 +107,6 @@ public: /** used by pull implementation to emit the next page */ - using Printer::PrintPage; void PrintPage( unsigned int nPage ); /** used by pull implementation to get the number of physical pages diff --git a/vcl/inc/vcl/jobdata.hxx b/vcl/inc/vcl/jobdata.hxx index 4451c566b5bf..d328f41f5b5b 100644 --- a/vcl/inc/vcl/jobdata.hxx +++ b/vcl/inc/vcl/jobdata.hxx @@ -74,6 +74,8 @@ struct JobData JobData( const JobData& rData ) { *this = rData; } + void setCollate( bool bCollate ); + // creates a new buffer using new // it is up to the user to delete it again bool getStreamBuffer( void*& pData, int& bytes ); diff --git a/vcl/inc/vcl/jobset.h b/vcl/inc/vcl/jobset.h index 9f3eefd507d5..fd15d0c076da 100644 --- a/vcl/inc/vcl/jobset.h +++ b/vcl/inc/vcl/jobset.h @@ -60,12 +60,13 @@ struct ImplJobSetup String maPrinterName; // Printer-Name String maDriver; // Driver-Name Orientation meOrientation; // Orientation - USHORT mnPaperBin; // Papierschacht - Paper mePaperFormat; // Papierformat - long mnPaperWidth; // Papierbreite in 100tel mm - long mnPaperHeight; // Papierhoehe in 100tel mm - ULONG mnDriverDataLen; // Laenge der systemabhaengigen Daten - BYTE* mpDriverData; // Systemabhaengige Daten die als Byte-Block rausgeschrieben werden + DuplexMode meDuplexMode; // Duplex + USHORT mnPaperBin; // paper bin / in tray + Paper mePaperFormat; // paper format + long mnPaperWidth; // paper width (100th mm) + long mnPaperHeight; // paper height (100th mm) + ULONG mnDriverDataLen; // length of system specific data + BYTE* mpDriverData; // system specific data (will be streamed a byte block) ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash > maValueMap; ImplJobSetup(); diff --git a/vcl/inc/vcl/lstbox.h b/vcl/inc/vcl/lstbox.h index 6097422b556b..9b95b9526d58 100644 --- a/vcl/inc/vcl/lstbox.h +++ b/vcl/inc/vcl/lstbox.h @@ -60,4 +60,9 @@ */ #define LISTBOX_ENTRY_FLAG_MULTILINE 0x0000002 +/** this flags lets the item be drawn disabled (e.g. in grey text) + usage only guaranteed with LISTBOX_ENTRY_FLAG_DISABLE_SELECTION +*/ +#define LISTBOX_ENTRY_FLAG_DRAW_DISABLED 0x0000004 + #endif // _SV_LSTBOX_H diff --git a/vcl/inc/vcl/oldprintadaptor.hxx b/vcl/inc/vcl/oldprintadaptor.hxx new file mode 100644 index 000000000000..d8b26433af94 --- /dev/null +++ b/vcl/inc/vcl/oldprintadaptor.hxx @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _VCL_OLDPRINTADAPTOR +#define _VCL_OLDPRINTADAPTOR + +#include "vcl/print.hxx" + +namespace vcl +{ + struct ImplOldStyleAdaptorData; + class VCL_DLLPUBLIC OldStylePrintAdaptor : public PrinterController + { + ImplOldStyleAdaptorData* mpData; + public: + OldStylePrintAdaptor( const boost::shared_ptr< Printer >& ); + virtual ~OldStylePrintAdaptor(); + + void StartPage(); + void EndPage(); + + virtual int getPageCount() const; + virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getPageParameters( int i_nPage ) const; + virtual void printPage( int i_nPage ) const; + }; +} + +#endif diff --git a/vcl/inc/vcl/outdev.hxx b/vcl/inc/vcl/outdev.hxx index 4a5b92444c21..0c03652d9300 100644 --- a/vcl/inc/vcl/outdev.hxx +++ b/vcl/inc/vcl/outdev.hxx @@ -1131,12 +1131,15 @@ public: false: output metafile is unchanged input metafile @attention this is a member method, so current state can influence the result ! + @attention the output metafile is prepared in pixel mode for the currentOutputDevice + state. It can not be moved or rotated reliably anymore. */ bool RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf, long nMaxBmpDPIX, long nMaxBmpDPIY, bool bReduceTransparency, bool bTransparencyAutoMode, - bool bDownsampleBitmaps + bool bDownsampleBitmaps, + const Color& rBackground = Color( COL_TRANSPARENT ) ); /** Retrieve downsampled and cropped bitmap diff --git a/vcl/inc/vcl/print.h b/vcl/inc/vcl/print.h index 51cbb5dee0cf..12c7439aa5b3 100644 --- a/vcl/inc/vcl/print.h +++ b/vcl/inc/vcl/print.h @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: print.h,v $ - * $Revision: 1.4 $ + * $Revision: 1.4.114.2 $ * * This file is part of OpenOffice.org. * @@ -31,27 +31,18 @@ #ifndef _SV_PRINT_H #define _SV_PRINT_H -#include <tools/list.hxx> -#include <vcl/sv.h> -#include <vcl/dllapi.h> +#include "vcl/sv.h" +#include "vcl/dllapi.h" #include <vector> #include <hash_map> struct SalPrinterQueueInfo; class QueueInfo; +class JobSetup; -// ------------------------ -// - private printer data - -// ------------------------ -struct ImplPrivatePrinterData -{ - bool mbNextJobIsQuick; - - ImplPrivatePrinterData() : - mbNextJobIsQuick( false ) - {} -}; +namespace vcl +{ class PrinterListener; } // -------------------- // - ImplPrnQueueData - @@ -87,5 +78,7 @@ public: // -------------- void ImplDeletePrnQueueList(); +void SAL_DLLPRIVATE ImplUpdateJobSetupPaper( JobSetup& rJobSetup ); + #endif // _SV_PRINT_H diff --git a/vcl/inc/vcl/print.hxx b/vcl/inc/vcl/print.hxx index b9176f4106dc..daea0c941dd0 100644 --- a/vcl/inc/vcl/print.hxx +++ b/vcl/inc/vcl/print.hxx @@ -31,14 +31,22 @@ #ifndef _SV_PRINT_HXX #define _SV_PRINT_HXX -#include <tools/errcode.hxx> -#include <vcl/sv.h> -#include <vcl/dllapi.h> -#include <vcl/outdev.hxx> -#include <vcl/prntypes.hxx> -#include <vcl/jobset.hxx> -#include <vcl/gdimtf.hxx> -#include <tools/stream.hxx> +#include "tools/errcode.hxx" +#include "vcl/sv.h" +#include "vcl/dllapi.h" +#include "vcl/outdev.hxx" +#include "vcl/prntypes.hxx" +#include "vcl/jobset.hxx" +#include "vcl/gdimtf.hxx" +#include "tools/stream.hxx" +#include "tools/multisel.hxx" + +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/view/PrintableState.hpp" + +#include <boost/shared_ptr.hpp> +#include <hash_map> +#include <set> struct SalPrinterInfoQueue; class SalInfoPrinter; @@ -46,12 +54,11 @@ struct SalPrinterQueueInfo; class SalPrinter; class VirtualDevice; class Window; -class ImplQPrinter; -struct ImplPrivatePrinterData; -namespace com { namespace sun { namespace star { namespace uno { - class Any; -} } } } +namespace vcl { + class PrinterController; + class PrintDialog; +} // ----------------- // - Printer-Types - @@ -216,16 +223,12 @@ class VCL_DLLPUBLIC Printer : public OutputDevice friend class ImplQPrinter; private: - ImplPrivatePrinterData* mpPrinterData; SalInfoPrinter* mpInfoPrinter; SalPrinter* mpPrinter; - Printer* mpJobPrinter; SalGraphics* mpJobGraphics; Printer* mpPrev; Printer* mpNext; VirtualDevice* mpDisplayDev; - ImplQPrinter* mpQPrinter; - GDIMetaFile* mpQMtf; PrinterOptions* mpPrinterOptions; XubString maPrinterName; XubString maDriver; @@ -250,9 +253,6 @@ private: BOOL mbUserSetupCompleted; BOOL mbUserSetupResult; Link maErrorHdl; - Link maStartPrintHdl; - Link maEndPrintHdl; - Link maPrintPageHdl; SAL_DLLPRIVATE void ImplInitData(); SAL_DLLPRIVATE void ImplInit( SalPrinterQueueInfo* pInfo ); @@ -261,22 +261,25 @@ private: const XubString* pDriver ); SAL_DLLPRIVATE void ImplUpdatePageData(); SAL_DLLPRIVATE void ImplUpdateFontList(); - SAL_DLLPRIVATE void ImplFindPaperFormatForUserSize( JobSetup& ); + SAL_DLLPRIVATE void ImplFindPaperFormatForUserSize( JobSetup&, bool bMatchNearest ); DECL_DLLPRIVATE_LINK( ImplDestroyPrinterAsync, void* ); -public: - SAL_DLLPRIVATE void ImplEndPrint(); - SAL_DLLPRIVATE void ImplUpdateQuickStatus(); + + SAL_DLLPRIVATE bool StartJob( const rtl::OUString& rJobName, boost::shared_ptr<vcl::PrinterController>& ); + + static SAL_DLLPRIVATE ULONG ImplSalPrinterErrorCodeToVCL( ULONG nError ); + private: + SAL_DLLPRIVATE void ImplEndPrint(); + SAL_DLLPRIVATE BOOL EndJob(); SAL_DLLPRIVATE Printer( const Printer& rPrinter ); SAL_DLLPRIVATE Printer& operator =( const Printer& rPrinter ); - -#ifdef _SPOOLPRINTER_EXT +public: + SAL_DLLPRIVATE void ImplStartPage(); + SAL_DLLPRIVATE void ImplEndPage(); public: void DrawGradientEx( OutputDevice* pOut, const Rectangle& rRect, const Gradient& rGradient ); void DrawGradientEx( OutputDevice* pOut, const PolyPolygon& rPolyPoly, const Gradient& rGradient ); -#endif // _SPOOLPRINTER_EXT - protected: void SetSelfAsQueuePrinter( BOOL bQueuePrinter ) { mbIsQueuePrinter = bQueuePrinter; } @@ -295,9 +298,6 @@ public: static XubString GetDefaultPrinterName(); virtual void Error(); - virtual void StartPrint(); - virtual void EndPrint(); - virtual void PrintPage(); const XubString& GetName() const { return maPrinterName; } const XubString& GetDriverName() const { return maDriver; } @@ -322,6 +322,7 @@ public: BOOL SetOrientation( Orientation eOrient ); Orientation GetOrientation() const; DuplexMode GetDuplexMode() const; + BOOL SetDuplexMode( DuplexMode ); // returns the angle that a landscape page will be turned counterclockwise // wrt to portrait. The return value may be only valid for // the current paper @@ -330,6 +331,7 @@ public: USHORT GetPaperBin() const; BOOL SetPaper( Paper ePaper ); BOOL SetPaperSizeUser( const Size& rSize ); + BOOL SetPaperSizeUser( const Size& rSize, bool bMatchNearest ); Paper GetPaper() const; // returns number of available paper formats @@ -348,58 +350,333 @@ public: USHORT GetCopyCount() const { return mnCopyCount; } BOOL IsCollateCopy() const { return mbCollateCopy; } - USHORT GetCurPrintPage() const { return mnCurPrintPage; } BOOL IsPrinting() const { return mbPrinting; } void SetPrintFile( const XubString& rFileName ) { maPrintFile = rFileName; } const XubString& GetPrintFile() const { return maPrintFile; } void EnablePrintFile( BOOL bEnable ) { mbPrintFile = bEnable; } BOOL IsPrintFileEnabled() const { return mbPrintFile; } - BOOL StartJob( const XubString& rJobName ); - BOOL EndJob(); BOOL AbortJob(); const XubString& GetCurJobName() const { return maJobName; } USHORT GetCurPage() const { return mnCurPage; } BOOL IsJobActive() const { return mbJobActive; } - BOOL StartPage(); - BOOL EndPage(); - - void SetPageQueueSize( USHORT nPages ) { mnPageQueueSize = nPages; } - USHORT GetPageQueueSize() const { return mnPageQueueSize; } ULONG GetError() const { return ERRCODE_TOERROR(mnError); } ULONG GetErrorCode() const { return mnError; } void SetErrorHdl( const Link& rLink ) { maErrorHdl = rLink; } const Link& GetErrorHdl() const { return maErrorHdl; } - void SetStartPrintHdl( const Link& rLink ) { maStartPrintHdl = rLink; } - const Link& GetStartPrintHdl() const { return maStartPrintHdl; } - void SetEndPrintHdl( const Link& rLink ) { maEndPrintHdl = rLink; } - const Link& GetEndPrintHdl() const { return maEndPrintHdl; } - void SetPrintPageHdl( const Link& rLink ) { maPrintPageHdl = rLink; } - const Link& GetPrintPageHdl() const { return maPrintPageHdl; } void Compat_OldPrinterMetrics( bool bSet ); - /** Notify that the next StartJob belongs to a UI less "direct print" job - * - * deprecated: the canonical way to notify a UI less job is to set the - * JobSetup value "IsQuickJob" to "true". If set at all, the "IsQuickJob" value - * on JobSetup will be preferred. However if no "IsQuickJob" value is set, - * setting SetNextJobIsQuick will cause the following StartJob to set this value - * to "true" in the current JobSetup. - * - * the paramter can be set to "false" again in case a job was not started and the - * printer is to be reused. - */ - void SetNextJobIsQuick( bool bQuick = true ); - /** checks the printer list and updates it necessary * * sends a DataChanged event of type DATACHANGED_PRINTER * if the printer list changed */ static void updatePrinters(); + + /** execute a print job + + starts a print job asynchronously (that is will return + + */ + static void PrintJob( const boost::shared_ptr<vcl::PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ); + + // implementation detail of PrintJob being asynchronous + // not exported, not usable outside vcl + static void SAL_DLLPRIVATE ImplPrintJob( const boost::shared_ptr<vcl::PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ); +}; + +namespace vcl +{ +class ImplPrinterControllerData; + +class VCL_DLLPUBLIC PrinterController +{ + ImplPrinterControllerData* mpImplData; +protected: + PrinterController( const boost::shared_ptr<Printer>& ); +public: + enum NupOrderType + { LRTB, TBLR }; + struct MultiPageSetup + { + // all metrics in 100th mm + int nRows; + int nColumns; + int nRepeat; + Size aPaperSize; + long nLeftMargin; + long nTopMargin; + long nRightMargin; + long nBottomMargin; + long nHorizontalSpacing; + long nVerticalSpacing; + bool bDrawBorder; + PrinterController::NupOrderType nOrder; + + MultiPageSetup() + : nRows( 1 ), nColumns( 1 ), nRepeat( 1 ), aPaperSize( 21000, 29700 ) + , nLeftMargin( 0 ), nTopMargin( 0 ) + , nRightMargin( 0 ), nBottomMargin( 0 ) + , nHorizontalSpacing( 0 ), nVerticalSpacing( 0 ) + , bDrawBorder( false ) + , nOrder( LRTB ) + { + } + }; + + struct PageSize + { + Size aSize; // in 100th mm + bool bFullPaper; // full paper, not only imageable area is printed + + PageSize( const Size& i_rSize = Size( 21000, 29700 ), + bool i_bFullPaper = false + ) : aSize( i_rSize ), bFullPaper( i_bFullPaper ) {} + }; + + PrinterController(); + virtual ~PrinterController(); + + const boost::shared_ptr<Printer>& getPrinter() const; + /* for implementations: get current job properties as changed by e.g. print dialog + this gets the current set of properties initially told to Printer::PrintJob + + For convenience a second sequence will be merged in to get a combined sequence. + In case of duplicate property names, the value of i_MergeList wins. + */ + com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > + getJobProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& i_rMergeList ) const; + + /* get the PropertyValue of a Property + */ + com::sun::star::beans::PropertyValue* getValue( const rtl::OUString& i_rPropertyName ); + const com::sun::star::beans::PropertyValue* getValue( const rtl::OUString& i_rPropertyName ) const; + // get a sequence of properties + com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getValues( const com::sun::star::uno::Sequence< rtl::OUString >& ) const; + /* get a bool property + in case the property is unknown or not convertible to bool, i_bFallback is returned + */ + sal_Bool getBoolProperty( const rtl::OUString& i_rPropertyName, sal_Bool i_bFallback ) const; + + /* set a property value - can also be used to add another UI property + */ + void setValue( const rtl::OUString& i_rPropertyName, const com::sun::star::uno::Any& i_rValue ); + void setValue( const com::sun::star::beans::PropertyValue& i_rValue ); + + /* return the currently active UI options. These are the same that were passed to setUIOptions. + */ + const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& getUIOptions() const; + /* set possible UI options. should only be done once before passing the PrinterListener + to Printer::PrintJob + */ + void setUIOptions( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& ); + /* enable/disable an option; this can be used to implement dialog logic. + */ + void enableUIOption( const rtl::OUString& rPropName, bool bEnable ); + bool isUIOptionEnabled( const rtl::OUString& rPropName ) const; + /* returns the property name rPropName depends on or an empty string + if no dependency exists. + */ + rtl::OUString getDependency( const rtl::OUString& rPropName ) const; + /* makeEnabled will chage the property rPropName depends on to the value + that makes rPropName enabled. If the dependency itself is also disabled, + no action will be performed. + + returns the property name rPropName depends on or an empty string + if no change was made. + */ + rtl::OUString makeEnabled( const rtl::OUString& rPropName ); + + virtual int getPageCount() const = 0; // must be overloaded by the app + /* get the page parameters, namely the jobsetup that should be active for the page + (describing among others the physical page size) and the "page size". In writer + case this would probably be the same as the JobSetup since writer sets the page size + draw/impress for example print their page on the paper set on the printer, + possibly adjusting the page size to fit. That means the page size can be different from + the paper size. + */ + // must be overloaded by the app, return page size in 1/100th mm + virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getPageParameters( int i_nPage ) const = 0; + virtual void printPage( int i_nPage ) const = 0; // must be overloaded by the app + virtual void jobStarted(); // will be called after a possible dialog has been shown and the real printjob starts + virtual void jobFinished( com::sun::star::view::PrintableState ); + + com::sun::star::view::PrintableState getJobState() const; + + void abortJob(); + + bool isShowDialogs() const; + bool isDirectPrint() const; + + // implementation details, not usable outside vcl + SAL_DLLPRIVATE int getFilteredPageCount(); + SAL_DLLPRIVATE PageSize getPageFile( int i_inUnfilteredPage, GDIMetaFile& rMtf, bool i_bMayUseCache = false ); + SAL_DLLPRIVATE PageSize getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache = false ); + SAL_DLLPRIVATE void printFilteredPage( int i_nPage ); + SAL_DLLPRIVATE void setPrinter( const boost::shared_ptr<Printer>& ); + SAL_DLLPRIVATE void setOptionChangeHdl( const Link& ); + SAL_DLLPRIVATE void createProgressDialog(); + SAL_DLLPRIVATE void setMultipage( const MultiPageSetup& ); + SAL_DLLPRIVATE const MultiPageSetup& getMultipage() const; + SAL_DLLPRIVATE void setLastPage( sal_Bool i_bLastPage ); + SAL_DLLPRIVATE void setReversePrint( sal_Bool i_bReverse ); + SAL_DLLPRIVATE bool getReversePrint() const; + SAL_DLLPRIVATE void pushPropertiesToPrinter(); + SAL_DLLPRIVATE void setJobState( com::sun::star::view::PrintableState ); + SAL_DLLPRIVATE bool setupPrinter( Window* i_pDlgParent ); + + SAL_DLLPRIVATE int getPageCountProtected() const; + SAL_DLLPRIVATE com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getPageParametersProtected( int i_nPage ) const; + + SAL_DLLPRIVATE ULONG removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut ); }; +class VCL_DLLPUBLIC PrinterOptionsHelper +{ + protected: + std::hash_map< rtl::OUString, com::sun::star::uno::Any, rtl::OUStringHash > m_aPropertyMap; + com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > m_aUIProperties; + + public: + PrinterOptionsHelper() {} // create without ui properties + PrinterOptionsHelper( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& i_rUIProperties ) + : m_aUIProperties( i_rUIProperties ) + {} + ~PrinterOptionsHelper() + {} + + /* process a new set of properties + * merges changed properties and returns "true" if any occured + * if the optional output set is not NULL then the names of the changed properties are returned + **/ + bool processProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& i_rNewProp, + std::set< rtl::OUString >* o_pChangeProp = NULL ); + /* append to a sequence of property values the ui property sequence passed at creation + * as the "ExtraPrintUIOptions" property. if that sequence was empty, no "ExtraPrintUIOptions" property + * will be appended. + **/ + void appendPrintUIOptions( com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& io_rProps ) const; + + // check if a property exists + bool hasProperty( const rtl::OUString& i_rPropertyName ) const; + bool hasProperty( const char* i_pPropertyName ) const + { return hasProperty( rtl::OUString::createFromAscii( i_pPropertyName ) ); } + + // returns an empty Any for not existing properties + com::sun::star::uno::Any getValue( const rtl::OUString& i_rPropertyName ) const; + // change a value in the property set; this will not have an effect to an eventual PrinterController + // the user of setValue must decide whether it is necessary to set the value there also + void setValue( const rtl::OUString& i_rPropertyName, const com::sun::star::uno::Any& i_rValue ); + void setValue( const char* i_pPropertyName, const com::sun::star::uno::Any& i_rValue ) + { setValue( rtl::OUString::createFromAscii( i_pPropertyName ), i_rValue ); } + + sal_Bool getBoolValue( const rtl::OUString& i_rPropertyName, sal_Bool i_bDefault = sal_False ) const; + // convenience for fixed strings + sal_Bool getBoolValue( const char* i_pPropName, sal_Bool i_bDefault = sal_False ) const + { return getBoolValue( rtl::OUString::createFromAscii( i_pPropName ), i_bDefault ); } + + sal_Int64 getIntValue( const rtl::OUString& i_rPropertyName, sal_Int64 i_nDefault = 0 ) const; + // convenience for fixed strings + sal_Int64 getIntValue( const char* i_pPropName, sal_Int64 i_nDefault = 0 ) const + { return getIntValue( rtl::OUString::createFromAscii( i_pPropName ), i_nDefault ); } + + rtl::OUString getStringValue( const rtl::OUString& i_rPropertyName, const rtl::OUString& i_rDefault = rtl::OUString() ) const; + // convenience for fixed strings + rtl::OUString getStringValue( const char* i_pPropName, const rtl::OUString& i_rDefault = rtl::OUString() ) const + { return getStringValue( rtl::OUString::createFromAscii( i_pPropName ), i_rDefault ); } + + // helper functions for user to create a single control + struct UIControlOptions + { + rtl::OUString maDependsOnName; + sal_Int32 mnDependsOnEntry; + sal_Bool mbAttachToDependency; + rtl::OUString maGroupHint; + sal_Bool mbInternalOnly; + sal_Bool mbEnabled; + com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > maAddProps; + + UIControlOptions( const rtl::OUString& i_rDependsOnName = rtl::OUString(), + sal_Int32 i_nDependsOnEntry = -1, + sal_Bool i_bAttachToDependency = sal_False, + const rtl::OUString& i_rGroupHint = rtl::OUString(), + sal_Bool i_bInternalOnly = sal_False, + sal_Bool i_bEnabled = sal_True + ) + : maDependsOnName( i_rDependsOnName ) + , mnDependsOnEntry( i_nDependsOnEntry ) + , mbAttachToDependency( i_bAttachToDependency ) + , maGroupHint( i_rGroupHint ) + , mbInternalOnly( i_bInternalOnly ) + , mbEnabled( i_bEnabled ) {} + }; + + // general control + static com::sun::star::uno::Any getUIControlOpt( const rtl::OUString& i_rTitle, + const com::sun::star::uno::Sequence< rtl::OUString >& i_rHelpText, + const rtl::OUString& i_rType, + const com::sun::star::beans::PropertyValue* i_pValue = NULL, + const UIControlOptions& i_rControlOptions = UIControlOptions() + ); + // create a group (e.g. a TabPage); following controls will be grouped in it until the next + // group begins + static com::sun::star::uno::Any getGroupControlOpt( const rtl::OUString& i_rTitle, const rtl::OUString& i_rHelpText ); + + // create a subgroup (e.g. a FixedLine); following controls will be grouped in it until the next + // subgroup or group begins + // setting bJobPage = true will make the subgroup appear on the first page of the print dialog + static com::sun::star::uno::Any getSubgroupControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const UIControlOptions& i_rControlOptions = UIControlOptions() + ); + + // create a bool option (usually a checkbox) + static com::sun::star::uno::Any getBoolControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + sal_Bool i_bValue, + const UIControlOptions& i_rControlOptions = UIControlOptions() + ); + + // create a set of choices (either a radio button group or a list box) + static com::sun::star::uno::Any getChoiceControlOpt( const rtl::OUString& i_rTitle, + const com::sun::star::uno::Sequence< rtl::OUString >& i_rHelpText, + const rtl::OUString& i_rProperty, + const com::sun::star::uno::Sequence< rtl::OUString >& i_rChoices, + sal_Int32 i_nValue, + const rtl::OUString& i_rType = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Radio" ) ), + const UIControlOptions& i_rControlOptions = UIControlOptions() + ); + + // create an integer range (e.g. a spin field) + // note: max value < min value means do not apply min/max values + static com::sun::star::uno::Any getRangeControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + sal_Int32 i_nValue, + sal_Int32 i_nMinValue = -1, + sal_Int32 i_nMaxValue = -2, + const UIControlOptions& i_rControlOptions = UIControlOptions() + ); + + // create a string field + // note: max value < min value means do not apply min/max values + static com::sun::star::uno::Any getEditControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + const rtl::OUString& i_rValue, + const UIControlOptions& i_rControlOptions = UIControlOptions() + ); +}; + +} + + #endif // _SV_PRINT_HXX diff --git a/vcl/inc/vcl/printerjob.hxx b/vcl/inc/vcl/printerjob.hxx index 9880700d4008..e445a81d54c8 100644 --- a/vcl/inc/vcl/printerjob.hxx +++ b/vcl/inc/vcl/printerjob.hxx @@ -91,7 +91,7 @@ private: // private methods bool writeFeatureList( osl::File* pFile, const JobData&, bool bDocumentSetup ); bool writeSetup( osl::File* pFile, const JobData& ); - bool writePageSetup( osl::File* pFile, const JobData& ); + bool writePageSetup( osl::File* pFile, const JobData&, bool bWriteFeatures = true ); void writeJobPatch( osl::File* File, const JobData& ); bool writeProlog (osl::File* pFile, const JobData& ); diff --git a/vcl/inc/vcl/prndlg.hxx b/vcl/inc/vcl/prndlg.hxx index 4fd6eaa999da..f1b69e1ca3aa 100644 --- a/vcl/inc/vcl/prndlg.hxx +++ b/vcl/inc/vcl/prndlg.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: prndlg.hxx,v $ - * $Revision: 1.3 $ + * $Revision: 1.3.114.5 $ * * This file is part of OpenOffice.org. * @@ -33,19 +33,301 @@ #include <vcl/dllapi.h> -#include <vcl/dialog.hxx> +#include "vcl/print.hxx" +#include "vcl/print.h" -class Printer; +#include "vcl/dialog.hxx" +#include "vcl/fixed.hxx" +#include "vcl/button.hxx" +#include "vcl/gdimtf.hxx" +#include "vcl/lstbox.hxx" +#include "vcl/field.hxx" +#include "vcl/tabctrl.hxx" +#include "vcl/tabpage.hxx" +#include "vcl/arrange.hxx" +#include "vcl/virdev.hxx" -class VCL_DLLPUBLIC SystemDialog : public ModalDialog +#include <boost/shared_ptr.hpp> +#include <map> + +namespace vcl { -public: - SystemDialog( Window* pParent, WinBits nWinStyle ) : - ModalDialog( pParent, nWinStyle ) {} - SystemDialog( Window* pParent, const ResId& rResId ) : - ModalDialog( pParent, rResId ) {} - - virtual short Execute() { return 0; } -}; + class PrintDialog : public ModalDialog + { + class PrintPreviewWindow : public Window + { + GDIMetaFile maMtf; + Size maOrigSize; + VirtualDevice maPageVDev; + rtl::OUString maReplacementString; + rtl::OUString maToolTipString; + public: + PrintPreviewWindow( Window* pParent, const ResId& ); + virtual ~PrintPreviewWindow(); + + virtual void Paint( const Rectangle& rRect ); + virtual void Command( const CommandEvent& ); + virtual void Resize(); + virtual void DataChanged( const DataChangedEvent& ); + + void setPreview( const GDIMetaFile&, const Size&, const rtl::OUString&, + sal_Int32 i_nDPIX, sal_Int32 i_nDPIY + ); + }; + + class ShowNupOrderWindow : public Window + { + int mnOrderMode; + int mnRows; + int mnColumns; + void ImplInitSettings(); + public: + ShowNupOrderWindow( Window* pParent ); + virtual ~ShowNupOrderWindow(); + + virtual void Paint( const Rectangle& ); + + void setValues( int i_nOrderMode, int i_nColumns, int i_nRows ) + { + mnOrderMode = i_nOrderMode; + mnRows = i_nRows; + mnColumns = i_nColumns; + Invalidate(); + } + }; + + class NUpTabPage : public TabPage + { + public: + FixedLine maNupLine; + RadioButton maPagesBtn; + RadioButton maBrochureBtn; + FixedText maPagesBoxTitleTxt; + ListBox maNupPagesBox; + + // controls for "Custom" page mode + FixedText maNupNumPagesTxt; + NumericField maNupColEdt; + FixedText maNupTimesTxt; + NumericField maNupRowsEdt; + FixedText maPageMarginTxt1; + MetricField maPageMarginEdt; + FixedText maPageMarginTxt2; + FixedText maSheetMarginTxt1; + MetricField maSheetMarginEdt; + FixedText maSheetMarginTxt2; + FixedText maNupOrientationTxt; + ListBox maNupOrientationBox; + + // page order ("left to right, then down") + FixedText maNupOrderTxt; + ListBox maNupOrderBox; + ShowNupOrderWindow maNupOrderWin; + // border around each page + CheckBox maBorderCB; + + vcl::RowOrColumn maLayout; + boost::shared_ptr< vcl::RowOrColumn > mxBrochureDep; + boost::shared_ptr< vcl::LabeledElement >mxPagesBtnLabel; + + void setupLayout(); + + NUpTabPage( Window*, const ResId& ); + virtual ~NUpTabPage(); + + void readFromSettings(); + void storeToSettings(); + void initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& ); + void enableNupControls( bool bEnable ); + + void showAdvancedControls( bool ); + + virtual void Resize(); + }; + + class JobTabPage : public TabPage + { + public: + FixedLine maPrinterFL; + ListBox maPrinters; + DisclosureButton maDetailsBtn; + FixedText maStatusLabel; + FixedText maStatusTxt; + FixedText maLocationLabel; + FixedText maLocationTxt; + FixedText maCommentLabel; + FixedText maCommentTxt; + + PushButton maSetupButton; + + FixedLine maCopies; + FixedLine maCopySpacer; + FixedText maCopyCount; + NumericField maCopyCountField; + CheckBox maCollateBox; + FixedImage maCollateImage; + + Image maCollateImg; + Image maCollateHCImg; + Image maNoCollateImg; + Image maNoCollateHCImg; + + long mnCollateUIMode; + + vcl::RowOrColumn maLayout; + boost::shared_ptr<vcl::RowOrColumn> mxPrintRange; + boost::shared_ptr<vcl::WindowArranger> mxDetails; + + JobTabPage( Window*, const ResId& ); + virtual ~JobTabPage(); + + void readFromSettings(); + void storeToSettings(); + + virtual void Resize(); + + void setupLayout(); + }; + + class OutputOptPage : public TabPage + { + public: + FixedLine maOptionsLine; + CheckBox maToFileBox; + CheckBox maCollateSingleJobsBox; + CheckBox maReverseOrderBox; + + vcl::RowOrColumn maLayout; + boost::shared_ptr<vcl::RowOrColumn> mxOptGroup; + + OutputOptPage( Window*, const ResId& ); + virtual ~OutputOptPage(); + + void readFromSettings(); + void storeToSettings(); + + virtual void Resize(); + + void setupLayout(); + }; + + OKButton maOKButton; + CancelButton maCancelButton; + HelpButton maHelpButton; + PrintPreviewWindow maPreviewWindow; + NumericField maPageEdit; + FixedText maNumPagesText; + PushButton maBackwardBtn; + PushButton maForwardBtn; + + TabControl maTabCtrl; + NUpTabPage maNUpPage; + JobTabPage maJobPage; + OutputOptPage maOptionsPage; + + FixedLine maButtonLine; + + boost::shared_ptr< PrinterController > maPController; + + rtl::OUString maPageStr; + rtl::OUString maNoPageStr; + sal_Int32 mnCurPage; + sal_Int32 mnCachedPages; + + std::list< Window* > maControls; + std::map< Window*, rtl::OUString > maControlToPropertyMap; + std::map< rtl::OUString, std::vector< Window* > > + maPropertyToWindowMap; + std::map< Window*, sal_Int32 > maControlToNumValMap; + std::set< rtl::OUString > maReverseDependencySet; + + Size maNupPortraitSize; + Size maNupLandscapeSize; + + // internal, used for automatic Nup-Portrait/landscape + Size maFirstPageSize; + + rtl::OUString maPrintToFileText; + rtl::OUString maPrintText; + rtl::OUString maDefPrtText; + + vcl::RowOrColumn maLayout; + boost::shared_ptr<vcl::RowOrColumn> mxPreviewCtrls; + + Size maDetailsCollapsedSize; + Size maDetailsExpandedSize; + + sal_Bool mbShowLayoutPage; + + Size getJobPageSize(); + void updateNup(); + void updateNupFromPages(); + void preparePreview( bool i_bPrintChanged = true, bool i_bMayUseCache = false ); + void setPreviewText( sal_Int32 ); + void updatePrinterText(); + void checkControlDependencies(); + void checkOptionalControlDependencies(); + void makeEnabled( Window* ); + void updateWindowFromProperty( const rtl::OUString& ); + void setupOptionalUI(); + void readFromSettings(); + void storeToSettings(); + com::sun::star::beans::PropertyValue* getValueForWindow( Window* ) const; + + virtual void Resize(); + virtual void Command( const CommandEvent& ); + virtual void DataChanged( const DataChangedEvent& ); + + DECL_LINK( SelectHdl, ListBox* ); + DECL_LINK( ClickHdl, Button* ); + DECL_LINK( ModifyHdl, Edit* ); + DECL_LINK( UIOptionsChanged, void* ); + + DECL_LINK( UIOption_CheckHdl, CheckBox* ); + DECL_LINK( UIOption_RadioHdl, RadioButton* ); + DECL_LINK( UIOption_SelectHdl, ListBox* ); + DECL_LINK( UIOption_ModifyHdl, Edit* ); + + void setupLayout(); + public: + PrintDialog( Window*, const boost::shared_ptr< PrinterController >& ); + virtual ~PrintDialog(); + + bool isPrintToFile(); + int getCopyCount(); + bool isCollate(); + + void previewForward(); + void previewBackward(); + }; + + class PrintProgressDialog : public ModelessDialog + { + String maStr; + FixedText maText; + CancelButton maButton; + + bool mbCanceled; + sal_Int32 mnCur; + sal_Int32 mnMax; + long mnProgressHeight; + Rectangle maProgressRect; + bool mbNativeProgress; + + DECL_LINK( ClickHdl, Button* ); + + void implCalcProgressRect(); + public: + PrintProgressDialog( Window* i_pParent, int i_nMax ); + ~PrintProgressDialog(); + + bool isCanceled() const { return mbCanceled; } + void setProgress( int i_nCurrent, int i_nMax = -1 ); + void tick(); + + virtual void Paint( const Rectangle& ); + }; +} + #endif // _SV_PRNDLG_HXX diff --git a/vcl/inc/vcl/prntypes.hxx b/vcl/inc/vcl/prntypes.hxx index 681f4f972a7c..a61c1a275474 100644 --- a/vcl/inc/vcl/prntypes.hxx +++ b/vcl/inc/vcl/prntypes.hxx @@ -39,7 +39,7 @@ // - Duplex Mode - // --------------- -enum DuplexMode { DUPLEX_UNKNOWN, DUPLEX_OFF, DUPLEX_ON }; +enum DuplexMode { DUPLEX_UNKNOWN, DUPLEX_OFF, DUPLEX_LONGEDGE, DUPLEX_SHORTEDGE }; // --------------- // - Orientation - @@ -93,5 +93,6 @@ enum Orientation { ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE }; #define PRINTER_CAPABILITIES_FAX ((USHORT)8) #define PRINTER_CAPABILITIES_PDF ((USHORT)9) #define PRINTER_CAPABILITIES_EXTERNALDIALOG ((USHORT)10) +#define PRINTER_CAPABILITIES_SETDUPLEX ((USHORT)11) #endif // _SV_PRNTYPES_HXX diff --git a/vcl/inc/vcl/salprn.hxx b/vcl/inc/vcl/salprn.hxx index 2927215034b5..73f5454457cf 100644 --- a/vcl/inc/vcl/salprn.hxx +++ b/vcl/inc/vcl/salprn.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: salprn.hxx,v $ - * $Revision: 1.5 $ + * $Revision: 1.5.114.1 $ * * This file is part of OpenOffice.org. * @@ -41,7 +41,7 @@ class SalGraphics; class SalFrame; struct ImplJobSetup; -class ImplQPrinter; +namespace vcl { class PrinterController; } // ----------------------- // - SalPrinterQueueInfo - @@ -101,7 +101,6 @@ public: virtual void InitPaperFormats( const ImplJobSetup* pSetupData ) = 0; // returns angle that a landscape page will be turned counterclockwise wrt to portrait virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ) = 0; - virtual DuplexMode GetDuplexMode( const ImplJobSetup* pSetupData ) = 0; }; // -------------- @@ -114,18 +113,21 @@ public: // public for Sal Implementation SalPrinter() {} virtual ~SalPrinter(); - virtual BOOL StartJob( const XubString* pFileName, - const XubString& rJobName, - const XubString& rAppName, - ULONG nCopies, BOOL bCollate, + virtual BOOL StartJob( const String* pFileName, + const String& rJobName, + const String& rAppName, + ULONG nCopies, + bool bCollate, + bool bDirect, ImplJobSetup* pSetupData ) = 0; // implement for pull model print systems only, // default implementations (see salvtables.cxx) just returns FALSE virtual BOOL StartJob( const String* pFileName, + const String& rJobName, const String& rAppName, ImplJobSetup* pSetupData, - ImplQPrinter* pQPrinter ); + vcl::PrinterController& rController ); virtual BOOL EndJob() = 0; virtual BOOL AbortJob() = 0; diff --git a/vcl/inc/vcl/salptype.hxx b/vcl/inc/vcl/salptype.hxx index 7f1c82079f38..bc9883757432 100644 --- a/vcl/inc/vcl/salptype.hxx +++ b/vcl/inc/vcl/salptype.hxx @@ -40,7 +40,11 @@ #define SAL_JOBSET_ORIENTATION ((ULONG)0x00000001) #define SAL_JOBSET_PAPERBIN ((ULONG)0x00000002) #define SAL_JOBSET_PAPERSIZE ((ULONG)0x00000004) -#define SAL_JOBSET_ALL (SAL_JOBSET_ORIENTATION | SAL_JOBSET_PAPERBIN | SAL_JOBSET_PAPERSIZE) +#define SAL_JOBSET_DUPLEXMODE ((ULONG)0x00000008) +#define SAL_JOBSET_ALL (SAL_JOBSET_ORIENTATION |\ + SAL_JOBSET_PAPERBIN |\ + SAL_JOBSET_PAPERSIZE |\ + SAL_JOBSET_DUPLEXMODE) // ------------------- // - SalPrinterError - diff --git a/vcl/inc/vcl/svdata.hxx b/vcl/inc/vcl/svdata.hxx index 17ad1aa28c1a..081b2fffca0b 100644 --- a/vcl/inc/vcl/svdata.hxx +++ b/vcl/inc/vcl/svdata.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: svdata.hxx,v $ - * $Revision: 1.13 $ + * $Revision: 1.13.16.1 $ * * This file is part of OpenOffice.org. * @@ -87,6 +87,7 @@ class Timer; class AutoTimer; class Help; class ImageList; +class Image; class PopupMenu; class Application; class OutputDevice; @@ -259,6 +260,10 @@ struct ImplSVCtrlData ImageList* mpSplitVPinImgList; // ImageList for Vertikale SplitWindows (PIN's) ImageList* mpSplitHArwImgList; // ImageList for Horizontale SplitWindows (Arrows) ImageList* mpSplitVArwImgList; // ImageList for Vertikale SplitWindows (Arrows) + Image* mpDisclosurePlus; + Image* mpDisclosurePlusHC; + Image* mpDisclosureMinus; + Image* mpDisclosureMinusHC; ImplTBDragMgr* mpTBDragMgr; // DragMgr for ToolBox USHORT mnCheckStyle; // CheckBox-Style for ImageList-Update USHORT mnRadioStyle; // Radio-Style for ImageList-Update @@ -367,6 +372,7 @@ void ImplDeInitSVData(); void ImplDestroySVData(); Window* ImplGetDefaultWindow(); VCL_DLLPUBLIC ResMgr* ImplGetResMgr(); +VCL_DLLPUBLIC ResId VclResId( sal_Int32 nId ); // throws std::bad_alloc if no res mgr DockingManager* ImplGetDockingManager(); void ImplWindowAutoMnemonic( Window* pWindow ); diff --git a/vcl/inc/vcl/svids.hrc b/vcl/inc/vcl/svids.hrc index 48297a04ea0e..e2a8226ac878 100644 --- a/vcl/inc/vcl/svids.hrc +++ b/vcl/inc/vcl/svids.hrc @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: svids.hrc,v $ - * $Revision: 1.8 $ + * $Revision: 1.8.84.3 $ * * This file is part of OpenOffice.org. * @@ -31,6 +31,8 @@ #ifndef _SV_SVIDS_HRC #define _SV_SVIDS_HRC +#include "svl/solar.hrc" + #define SV_RESID_STDOFFSET 0 #define SV_RESID_WINOFFSET 1 #define SV_RESID_OS2OFFSET 2 @@ -58,6 +60,11 @@ #define SV_RESID_BITMAP_CLOSEDOC 1052 #define SV_RESID_BITMAP_CLOSEDOCHC 1053 +#define SV_DISCLOSURE_PLUS 1060 +#define SV_DISCLOSURE_MINUS 1061 +#define SV_DISCLOSURE_PLUS_HC 1062 +#define SV_DISCLOSURE_MINUS_HC 1063 + #define SV_RESID_MENU_EDIT 2000 #define SV_MENU_EDIT_UNDO 1 #define SV_MENU_EDIT_CUT 2 @@ -74,6 +81,92 @@ #define SV_MENU_MAC_SHOWALL 2005 #define SV_MENU_MAC_QUITAPP 2006 +#define SV_DLG_PRINT 2048 +#define SV_PRINT_OK 1 +#define SV_PRINT_CANCEL 2 +#define SV_PRINT_HELP 3 +#define SV_PRINT_PAGE_PREVIEW 4 +#define SV_PRINT_PAGE_TXT 5 +#define SV_PRINT_PAGE_FORWARD 6 +#define SV_PRINT_PAGE_BACKWARD 7 +#define SV_PRINT_PAGE_EDIT 8 +#define SV_PRINT_TABCTRL 9 +#define SV_PRINT_PRT_TYPE 10 +#define SV_PRINT_PRT_STATUS 11 +#define SV_PRINT_PRT_LOCATION 12 +#define SV_PRINT_PRT_COMMENT 13 +#define SV_PRINT_TOFILE_TXT 14 +#define SV_PRINT_DEFPRT_TXT 15 +#define SV_PRINT_PRINTPREVIEW_TXT 16 + +#define SV_PRINT_TAB_NUP 1 +#define SV_PRINT_PRT_NUP_LAYOUT_FL 1 +#define SV_PRINT_PRT_NUP_DEFAULT_BTN 2 +#define SV_PRINT_PRT_NUP_BROCHURE_BTN 3 +#define SV_PRINT_PRT_NUP_PAGES_BTN 4 +#define SV_PRINT_PRT_NUP_PAGES_BOX 5 +#define SV_PRINT_PRT_NUP_NUM_PAGES_TXT 6 +#define SV_PRINT_PRT_NUP_COLS_EDT 7 +#define SV_PRINT_PRT_NUP_TIMES_TXT 8 +#define SV_PRINT_PRT_NUP_ROWS_EDT 9 +#define SV_PRINT_PRT_NUP_MARGINS_PAGES_1_TXT 10 +#define SV_PRINT_PRT_NUP_MARGINS_PAGES_EDT 11 +#define SV_PRINT_PRT_NUP_MARGINS_PAGES_2_TXT 12 +#define SV_PRINT_PRT_NUP_MARGINS_SHEET_1_TXT 13 +#define SV_PRINT_PRT_NUP_MARGINS_SHEET_EDT 14 +#define SV_PRINT_PRT_NUP_MARGINS_SHEET_2_TXT 15 +#define SV_PRINT_PRT_NUP_ORIENTATION_TXT 16 +#define SV_PRINT_PRT_NUP_ORIENTATION_BOX 17 +#define SV_PRINT_PRT_NUP_ORDER_TXT 18 +#define SV_PRINT_PRT_NUP_ORDER_BOX 19 +#define SV_PRINT_PRT_NUP_BORDER_CB 20 + +#define SV_PRINT_PRT_NUP_ORIENTATION_AUTOMATIC 0 +#define SV_PRINT_PRT_NUP_ORIENTATION_PORTRAIT 1 +#define SV_PRINT_PRT_NUP_ORIENTATION_LANDSCAPE 2 + +#define SV_PRINT_PRT_NUP_ORDER_LRTD 0 +#define SV_PRINT_PRT_NUP_ORDER_TDLR 1 + +#define SV_PRINT_TAB_JOB 2 +#define SV_PRINT_PRINTERS_FL 1 +#define SV_PRINT_PRINTERS 2 +#define SV_PRINT_PRT_SETUP 3 +#define SV_PRINT_RANGE 4 +#define SV_PRINT_ALL 5 +#define SV_PRINT_PAGERANGE 6 +#define SV_PRINT_SELECTION 7 +#define SV_PRINT_PAGERANGE_EDIT 8 +#define SV_PRINT_COPIES 9 +#define SV_PRINT_COPYCOUNT 10 +#define SV_PRINT_COPYCOUNT_FIELD 11 +#define SV_PRINT_COLLATE 12 +#define SV_PRINT_COLLATE_IMAGE 13 +#define SV_PRINT_BUTTONLINE 14 +#define SV_PRINT_COLLATE_IMG 15 +#define SV_PRINT_NOCOLLATE_IMG 16 +#define SV_PRINT_COLLATE_HC_IMG 17 +#define SV_PRINT_NOCOLLATE_HC_IMG 18 +#define SV_PRINT_NOPAGES 19 +#define SV_PRINT_STATUS_TXT 20 +#define SV_PRINT_LOCATION_TXT 21 +#define SV_PRINT_COMMENT_TXT 22 +#define SV_PRINT_DETAILS_BTN 23 + +#define SV_PRINT_TAB_OPT 3 +#define SV_PRINT_OPT_PRINT_FL 1 +#define SV_PRINT_OPT_TOFILE 2 +#define SV_PRINT_OPT_SINGLEJOBS 3 +#define SV_PRINT_OPT_REVERSE 4 + +#define SV_DLG_PRINT_PROGRESS 2049 +#define SV_PRINT_PROGRESS_CANCEL 1 +#define SV_PRINT_PROGRESS_TEXT 2 + +#define SV_PRINT_NATIVE_STRINGS 2050 +#define SV_PRINT_NOPRINTERWARNING 2051 +#define SV_PRINT_NOCONTENT 2052 + #define SV_HELPTEXT_CLOSE 10000 #define SV_HELPTEXT_MINIMIZE 10001 #define SV_HELPTEXT_MAXIMIZE 10002 @@ -108,7 +201,8 @@ #define SV_STDTEXT_ABOUT 10204 #define SV_STDTEXT_PREFERENCES 10205 #define SV_MAC_SCREENNNAME 10206 -#define SV_STDTEXT_LAST SV_MAC_SCREENNNAME +#define SV_STDTEXT_ALLFILETYPES 10207 +#define SV_STDTEXT_LAST SV_STDTEXT_ALLFILETYPES #define SV_ACCESSERROR_FIRST SV_ACCESSERROR_WRONG_VERSION #define SV_ACCESSERROR_WRONG_VERSION 10500 @@ -165,4 +259,6 @@ #define SV_ICON_ID_MACRO 17 #define SV_ICON_ID_PRINTERADMIN 501 +#define HID_PRINTDLG HID_VCL_START + #endif // _SV_SVIDS_HRC diff --git a/vcl/inc/vcl/tabctrl.hxx b/vcl/inc/vcl/tabctrl.hxx index 30edf6227a60..f6646426b2e7 100644 --- a/vcl/inc/vcl/tabctrl.hxx +++ b/vcl/inc/vcl/tabctrl.hxx @@ -31,15 +31,16 @@ #ifndef _SV_TABCTRL_HXX #define _SV_TABCTRL_HXX -#include <vcl/sv.h> -#include <vcl/dllapi.h> -#include <vcl/ctrl.hxx> +#include "vcl/sv.h" +#include "vcl/dllapi.h" +#include "vcl/ctrl.hxx" struct ImplTabItem; struct ImplTabCtrlData; class ImplTabItemList; class TabPage; class PushButton; +class ListBox; // -------------------- // - TabControl-Types - @@ -72,7 +73,7 @@ private: BOOL mbRestoreUnqId; BOOL mbSingleLine; BOOL mbScroll; - BOOL mbColored; + BOOL mbRestoreSmartId; BOOL mbSmallInvalidate; BOOL mbExtraSpace; Link maActivateHdl; @@ -95,6 +96,7 @@ private: SAL_DLLPRIVATE void ImplPaint( const Rectangle& rRect, bool bLayout = false ); SAL_DLLPRIVATE void ImplFreeLayoutData(); DECL_DLLPRIVATE_LINK( ImplScrollBtnHdl, PushButton* pBtn ); + DECL_DLLPRIVATE_LINK( ImplListBoxSelectHdl, ListBox* ); protected: using Window::ImplInit; @@ -128,6 +130,9 @@ public: virtual void ActivatePage(); virtual long DeactivatePage(); + virtual Size GetOptimalSize(WindowSizeType eType) const; + void SetMinimumSizePixel( const Size& ); + void SetTabPageSizePixel( const Size& rSize ); Size GetTabPageSizePixel() const; diff --git a/vcl/inc/vcl/virdev.hxx b/vcl/inc/vcl/virdev.hxx index bc21dde6f4ac..ea2b49eb8290 100644 --- a/vcl/inc/vcl/virdev.hxx +++ b/vcl/inc/vcl/virdev.hxx @@ -74,7 +74,6 @@ private: #define REFDEV_FORCE_ZERO_EXTLEAD 0x80 SAL_DLLPRIVATE bool ForceZeroExtleadBug() const { return ((meRefDevMode & REFDEV_FORCE_ZERO_EXTLEAD) != 0); } - public: VirtualDevice( USHORT nBitCount = 0 ); VirtualDevice( const OutputDevice& rCompDev, @@ -115,11 +114,19 @@ public: REFDEV_MODE06 = 1, // 600 dpi REFDEV_MODE48 = 2, // 4800 dpi REFDEV_MODE_MSO1 = 3, - REFDEV_MODE_PDF1 = 4 }; + REFDEV_MODE_PDF1 = 4, + REFDEV_CUSTOM = 5 + }; void SetReferenceDevice( RefDevMode ); void Compat_ZeroExtleadBug(); // enable workaround for #i60495# + + void SetReferenceDevice( sal_Int32 i_nDPIX, sal_Int32 i_nDPIY ); + +private: + SAL_DLLPRIVATE void ImplSetReferenceDevice( RefDevMode, sal_Int32 i_nDPIX, sal_Int32 i_nDPIY ); + }; #endif // _SV_VIRDEV_HXX diff --git a/vcl/inc/vcl/window.h b/vcl/inc/vcl/window.h index d745f3dcf081..563849873e3b 100644 --- a/vcl/inc/vcl/window.h +++ b/vcl/inc/vcl/window.h @@ -358,7 +358,8 @@ public: mbToolbarFloatingWindow:1, mbCallHandlersDuringInputDisabled:1, mbDisableAccessibleLabelForRelation:1, - mbDisableAccessibleLabeledByRelation:1; + mbDisableAccessibleLabeledByRelation:1, + mbHelpTextDynamic:1; ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > mxDNDListenerContainer; }; diff --git a/vcl/os2/inc/salprn.h b/vcl/os2/inc/salprn.h index 25ecfe87ed89..2c95965bc609 100644 --- a/vcl/os2/inc/salprn.h +++ b/vcl/os2/inc/salprn.h @@ -83,7 +83,6 @@ public: virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin ); virtual void InitPaperFormats( const ImplJobSetup* pSetupData ); virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ); - virtual DuplexMode GetDuplexMode( const ImplJobSetup* pSetupData ); }; // ------------------ @@ -136,7 +135,9 @@ public: virtual BOOL StartJob( const XubString* pFileName, const XubString& rJobName, const XubString& rAppName, - ULONG nCopies, BOOL bCollate, + ULONG nCopies, + bool bCollate, + bool bDirect, ImplJobSetup* pSetupData ); virtual BOOL EndJob(); virtual BOOL AbortJob(); diff --git a/vcl/os2/source/gdi/salprn.cxx b/vcl/os2/source/gdi/salprn.cxx index 0c254e2f6e62..a31a4bb779f8 100644 --- a/vcl/os2/source/gdi/salprn.cxx +++ b/vcl/os2/source/gdi/salprn.cxx @@ -1559,7 +1559,9 @@ Os2SalPrinter::~Os2SalPrinter() BOOL Os2SalPrinter::StartJob( const XubString* pFileName, const XubString& rJobName, const XubString& rAppName, - ULONG nCopies, BOOL bCollate, + ULONG nCopies, + bool bCollate, + bool bDirect, ImplJobSetup* pSetupData ) { DEVOPENSTRUC aDevOpenStruc; @@ -1831,9 +1833,4 @@ int Os2SalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData ) printf("Os2SalInfoPrinter::GetLandscapeAngle\n"); return 0; } -DuplexMode Os2SalInfoPrinter::GetDuplexMode( const ImplJobSetup* pSetupData ) -{ - DuplexMode nRet = DUPLEX_UNKNOWN; - printf("Os2SalInfoPrinter::GetDuplexMode\n"); - return nRet; -} + diff --git a/vcl/prj/build.lst b/vcl/prj/build.lst index 5d2aaf90c6f7..cf2824f72942 100644 --- a/vcl/prj/build.lst +++ b/vcl/prj/build.lst @@ -1,4 +1,4 @@ -vc vcl : l10n apple_remote BOOST:boost rsc sot ucbhelper unotools ICU:icu GRAPHITE:graphite i18npool i18nutil unoil ridljar X11_EXTENSIONS:x11_extensions offuh basegfx basebmp tools transex3 icc SO:print_header cpputools shell NULL +vc vcl : l10n apple_remote BOOST:boost rsc sot ucbhelper unotools ICU:icu GRAPHITE:graphite i18npool i18nutil unoil ridljar X11_EXTENSIONS:x11_extensions offuh basegfx basebmp tools transex3 icc SO:print_header cpputools shell svl NULL vc vcl usr1 - all vc_mkout NULL vc vcl\inc nmake - all vc_inc NULL vc vcl\source\glyphs nmake - all vc_glyphs vc_inc NULL diff --git a/vcl/prj/d.lst b/vcl/prj/d.lst index 54af0d2e289d..b106ff73729e 100644 --- a/vcl/prj/d.lst +++ b/vcl/prj/d.lst @@ -81,10 +81,10 @@ mkdir: %_DEST%\inc%_EXT%\vcl ..\inc\vcl\morebtn.hxx %_DEST%\inc%_EXT%\vcl\morebtn.hxx ..\inc\vcl\msgbox.hxx %_DEST%\inc%_EXT%\vcl\msgbox.hxx ..\inc\vcl\octree.hxx %_DEST%\inc%_EXT%\vcl\octree.hxx +..\inc\vcl\oldprintadaptor.hxx %_DEST%\inc%_EXT%\vcl\oldprintadaptor.hxx ..\inc\vcl\outdev.hxx %_DEST%\inc%_EXT%\vcl\outdev.hxx ..\inc\vcl\pointr.hxx %_DEST%\inc%_EXT%\vcl\pointr.hxx ..\inc\vcl\print.hxx %_DEST%\inc%_EXT%\vcl\print.hxx -..\inc\vcl\prndlg.hxx %_DEST%\inc%_EXT%\vcl\prndlg.hxx ..\inc\vcl\prntypes.hxx %_DEST%\inc%_EXT%\vcl\prntypes.hxx ..\inc\vcl\ptrstyle.hxx %_DEST%\inc%_EXT%\vcl\ptrstyle.hxx ..\inc\vcl\regband.hxx %_DEST%\inc%_EXT%\vcl\regband.hxx diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 516b23dd76be..31971468d9c6 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -97,8 +97,8 @@ SalPrinter::~SalPrinter() { } -BOOL SalPrinter::StartJob( const String*, const String&, - ImplJobSetup*, ImplQPrinter* ) +BOOL SalPrinter::StartJob( const String*, const String&, const String&, + ImplJobSetup*, vcl::PrinterController& ) { return FALSE; } diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx index 6a61d15db4c0..e8e56c6ee5a8 100644 --- a/vcl/source/app/svdata.cxx +++ b/vcl/source/app/svdata.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: svdata.cxx,v $ - * $Revision: 1.56 $ + * $Revision: 1.56.114.1 $ * * This file is part of OpenOffice.org. * @@ -234,6 +234,15 @@ ResMgr* ImplGetResMgr() return pSVData->mpResMgr; } +ResId VclResId( sal_Int32 nId ) +{ + ResMgr* pMgr = ImplGetResMgr(); + if( ! pMgr ) + throw std::bad_alloc(); + + return ResId( nId, *pMgr ); +} + DockingManager* ImplGetDockingManager() { ImplSVData* pSVData = ImplGetSVData(); diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx index 310c01a40673..f1af78662813 100644 --- a/vcl/source/app/svmain.cxx +++ b/vcl/source/app/svmain.cxx @@ -444,6 +444,26 @@ void DeInitVCL() delete pSVData->maCtrlData.mpSplitVArwImgList; pSVData->maCtrlData.mpSplitVArwImgList = NULL; } + if ( pSVData->maCtrlData.mpDisclosurePlus ) + { + delete pSVData->maCtrlData.mpDisclosurePlus; + pSVData->maCtrlData.mpDisclosurePlus = NULL; + } + if ( pSVData->maCtrlData.mpDisclosurePlusHC ) + { + delete pSVData->maCtrlData.mpDisclosurePlusHC; + pSVData->maCtrlData.mpDisclosurePlusHC = NULL; + } + if ( pSVData->maCtrlData.mpDisclosureMinus ) + { + delete pSVData->maCtrlData.mpDisclosureMinus; + pSVData->maCtrlData.mpDisclosureMinus = NULL; + } + if ( pSVData->maCtrlData.mpDisclosureMinusHC ) + { + delete pSVData->maCtrlData.mpDisclosureMinusHC; + pSVData->maCtrlData.mpDisclosureMinusHC = NULL; + } if ( pSVData->mpDefaultWin ) { delete pSVData->mpDefaultWin; diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx index 53a060af6bd6..b5915cc35daf 100644 --- a/vcl/source/control/button.cxx +++ b/vcl/source/control/button.cxx @@ -1983,8 +1983,11 @@ Size PushButton::CalcMinimumSize( long nMaxWidth ) const } // cf. ImplDrawPushButton ... - aSize.Width() += 8; - aSize.Height() += 8; + if( (GetStyle() & WB_SMALLSTYLE) == 0 ) + { + aSize.Width() += 8; + aSize.Height() += 8; + } return CalcWindowSize( aSize ); } @@ -4376,3 +4379,95 @@ TriStateBox::TriStateBox( Window* pParent, const ResId& rResId ) : TriStateBox::~TriStateBox() { } + +// ======================================================================= + +DisclosureButton::DisclosureButton( Window* pParent, WinBits ) : + CheckBox( pParent, WB_NOBORDER ) +{ +} + +// ----------------------------------------------------------------------- + +DisclosureButton::DisclosureButton( Window* pParent, const ResId& rResId ) : + CheckBox( pParent, rResId.SetRT( RSC_CHECKBOX ) ) +{ +} + +// ----------------------------------------------------------------------- + +void DisclosureButton::ImplDrawCheckBoxState() +{ + /* HACK: DisclosureButton is currently assuming, that the disclosure sign + will fit into the rectangle occupied by a normal checkbox on all themes. + If this does not hold true for some theme, ImplGetCheckImageSize + would have to be overloaded for DisclosureButton; also GetNativeControlRegion + for CTRL_LISTNODE would have to be implemented and taken into account + */ + + Rectangle aStateRect( GetStateRect() ); + + ImplControlValue aControlValue( GetState() == STATE_CHECK ? BUTTONVALUE_ON : BUTTONVALUE_OFF, rtl::OUString(), 0 ); + Region aCtrlRegion( aStateRect ); + ControlState nState = 0; + + if ( HasFocus() ) nState |= CTRL_STATE_FOCUSED; + if ( ImplGetButtonState() & BUTTON_DRAW_DEFAULT ) nState |= CTRL_STATE_DEFAULT; + if ( Window::IsEnabled() ) nState |= CTRL_STATE_ENABLED; + if ( IsMouseOver() && GetMouseRect().IsInside( GetPointerPosPixel() ) ) + nState |= CTRL_STATE_ROLLOVER; + + if( ! DrawNativeControl( CTRL_LISTNODE, PART_ENTIRE_CONTROL, aCtrlRegion, nState, + aControlValue, rtl::OUString() ) ) + { + ImplSVCtrlData& rCtrlData( ImplGetSVData()->maCtrlData ); + if( ! rCtrlData.mpDisclosurePlus ) + rCtrlData.mpDisclosurePlus = new Image( BitmapEx( VclResId( SV_DISCLOSURE_PLUS ) ) ); + if( ! rCtrlData.mpDisclosurePlusHC ) + rCtrlData.mpDisclosurePlusHC = new Image( BitmapEx( VclResId( SV_DISCLOSURE_PLUS_HC ) ) ); + if( ! rCtrlData.mpDisclosureMinus ) + rCtrlData.mpDisclosureMinus = new Image( BitmapEx( VclResId( SV_DISCLOSURE_MINUS ) ) ); + if( ! rCtrlData.mpDisclosureMinusHC ) + rCtrlData.mpDisclosureMinusHC = new Image( BitmapEx( VclResId( SV_DISCLOSURE_MINUS_HC ) ) ); + + Image* pImg = NULL; + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) + pImg = IsChecked() ? rCtrlData.mpDisclosureMinusHC : rCtrlData.mpDisclosurePlusHC; + else + pImg = IsChecked() ? rCtrlData.mpDisclosureMinus : rCtrlData.mpDisclosurePlus; + + DBG_ASSERT( pImg, "no disclosure image" ); + if( ! pImg ) + return; + + USHORT nStyle = 0; + if( ! IsEnabled() ) + nStyle |= IMAGE_DRAW_DISABLE; + + Size aSize( aStateRect.GetSize() ); + Size aImgSize( pImg->GetSizePixel() ); + Point aOff( (aSize.Width() - aImgSize.Width())/2, + (aSize.Height() - aImgSize.Height())/2 ); + aOff += aStateRect.TopLeft(); + DrawImage( aOff, *pImg, nStyle ); + } +} + +// ----------------------------------------------------------------------- + +void DisclosureButton::KeyInput( const KeyEvent& rKEvt ) +{ + KeyCode aKeyCode = rKEvt.GetKeyCode(); + + if( !aKeyCode.GetModifier() && + ( ( aKeyCode.GetCode() == KEY_ADD ) || + ( aKeyCode.GetCode() == KEY_SUBTRACT ) ) + ) + { + Check( aKeyCode.GetCode() == KEY_ADD ); + } + else + Button::KeyInput( rKEvt ); +} + + diff --git a/vcl/source/control/edit.cxx b/vcl/source/control/edit.cxx index 0632dcdd3f41..320f235a8c30 100644 --- a/vcl/source/control/edit.cxx +++ b/vcl/source/control/edit.cxx @@ -2840,7 +2840,29 @@ void Edit::SetSubEdit( Edit* pEdit ) Size Edit::CalcMinimumSize() const { Size aSize ( GetTextWidth( GetText() ), GetTextHeight() ); - return CalcWindowSize( aSize ); + // do not create edit fields in which one cannot enter anything + // a default minimum width should exist for at least 3 characters + Size aMinSize ( CalcSize( 3 ) ); + if( aSize.Width() < aMinSize.Width() ) + aSize.Width() = aMinSize.Width(); + // add some space between text entry an border + aSize.Height() += 4; + + aSize = CalcWindowSize( aSize ); + + // ask NWF what if it has an opinion, too + ImplControlValue aControlValue; + Rectangle aRect( Point( 0, 0 ), aSize ); + Region aContent, aBound; + if( const_cast<Edit*>(this)->GetNativeControlRegion( + CTRL_EDITBOX, PART_ENTIRE_CONTROL, + aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) ) + { + Rectangle aBoundRect( aContent.GetBoundRect() ); + if( aBoundRect.GetHeight() > aSize.Height() ) + aSize.Height() = aBoundRect.GetHeight(); + } + return aSize; } // ----------------------------------------------------------------------- diff --git a/vcl/source/control/fixed.cxx b/vcl/source/control/fixed.cxx index 3d19e288a1ce..df2673ede10c 100644 --- a/vcl/source/control/fixed.cxx +++ b/vcl/source/control/fixed.cxx @@ -1062,6 +1062,14 @@ void FixedImage::Paint( const Rectangle& ) // ----------------------------------------------------------------------- +Size FixedImage::GetOptimalSize( WindowSizeType ) const +{ + const Image* pImage = GetSettings().GetStyleSettings().GetHighContrastMode() ? &maImageHC : &maImage; + return pImage->GetSizePixel(); +} + +// ----------------------------------------------------------------------- + void FixedImage::UserDraw( const UserDrawEvent& ) { } diff --git a/vcl/source/control/ilstbox.cxx b/vcl/source/control/ilstbox.cxx index a915d8e6b9e8..fd5cd7ae4dac 100644 --- a/vcl/source/control/ilstbox.cxx +++ b/vcl/source/control/ilstbox.cxx @@ -1873,6 +1873,8 @@ void ImplListBoxWindow::DrawEntry( USHORT nPos, BOOL bDrawImage, BOOL bDrawText, USHORT nDrawStyle = ImplGetTextStyle(); if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) ) nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS; + if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) ) + nDrawStyle |= TEXT_DRAW_DISABLE; DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText ); } diff --git a/vcl/source/control/lstbox.cxx b/vcl/source/control/lstbox.cxx index ceabbe4ab166..81a8dc0e8242 100644 --- a/vcl/source/control/lstbox.cxx +++ b/vcl/source/control/lstbox.cxx @@ -108,6 +108,7 @@ void ListBox::ImplInitListBoxData() mnDDHeight = 0; mbDDAutoSize = TRUE; mnSaveValue = LISTBOX_ENTRY_NOTFOUND; + mnLineCount = 0; } // ----------------------------------------------------------------------- @@ -1286,31 +1287,47 @@ Size ListBox::CalcMinimumSize() const else { aSz.Height() = mpImplLB->CalcSize( 1 ).Height(); - if( aSz.Height() < mnDDHeight ) + aSz.Height() += 4; // add a space between entry and border + // size to maxmimum entry width and add a little breathing space + aSz.Width() = mpImplLB->GetMaxEntryWidth() + 4; + // do not create ultrathin ListBoxes, it doesn't look good + if( aSz.Width() < GetSettings().GetStyleSettings().GetScrollBarSize() ) + aSz.Width() = GetSettings().GetStyleSettings().GetScrollBarSize(); + + // try native borders; scrollbar size may not be a good indicator + // see how large the edit area inside is to estimate what is needed for the dropdown + ImplControlValue aControlValue; + Point aPoint; + Region aContent, aBound; + Size aTestSize( 100, 20 ); + Region aArea( Rectangle( aPoint, aTestSize ) ); + if( const_cast<ListBox*>(this)->GetNativeControlRegion( + CTRL_LISTBOX, PART_SUB_EDIT, aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) ) { - aSz.Height() = mnDDHeight; - // FIXME: this is currently only on mac/aqua - if( ImplGetSVData()->maNWFData.mbNoFocusRects && - IsNativeWidgetEnabled() && - const_cast<ListBox*>(this)->IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) ) - { - ImplControlValue aControlValue; - Region aCtrlRegion( Rectangle( (const Point&)Point(), Size( 20, mnDDHeight ) ) ); - Region aBoundingRgn( aCtrlRegion ); - Region aContentRgn( aCtrlRegion ); - // adjust the size of the edit field - if( const_cast<ListBox*>(this)->GetNativeControlRegion( CTRL_LISTBOX, PART_ENTIRE_CONTROL, - aCtrlRegion, 0, aControlValue, rtl::OUString(), aBoundingRgn, aContentRgn) ) - { - aSz.Height() = aContentRgn.GetBoundRect().GetHeight(); - } - } + // use the themes drop down size + Rectangle aContentRect = aContent.GetBoundRect(); + aSz.Width() += aTestSize.Width() - aContentRect.GetWidth(); } - aSz.Width() = mpImplLB->GetMaxEntryWidth(); - aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize(); + else + aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize(); } aSz = CalcWindowSize( aSz ); + + if ( IsDropDownBox() ) // check minimum height of dropdown box + { + ImplControlValue aControlValue; + Rectangle aRect( Point( 0, 0 ), aSz ); + Region aContent, aBound; + if( const_cast<ListBox*>(this)->GetNativeControlRegion( + CTRL_LISTBOX, PART_ENTIRE_CONTROL, aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) ) + { + Rectangle aBoundRect( aBound.GetBoundRect() ); + if( aBoundRect.GetHeight() > aSz.Height() ) + aSz.Height() = aBoundRect.GetHeight(); + } + } + return aSz; } diff --git a/vcl/source/control/tabctrl.cxx b/vcl/source/control/tabctrl.cxx index 9a34629ddf8e..56cc2c3fb012 100644 --- a/vcl/source/control/tabctrl.cxx +++ b/vcl/source/control/tabctrl.cxx @@ -30,25 +30,24 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#include <tools/debug.hxx> - -#ifndef _SV_RC_H -#include <tools/rc.h> -#endif -#include <vcl/svdata.hxx> -#ifndef _SV_APP_HXX -#include <vcl/svapp.hxx> -#endif -#include <vcl/help.hxx> -#include <vcl/event.hxx> -#include <vcl/menu.hxx> -#include <vcl/button.hxx> -#include <vcl/tabpage.hxx> -#include <vcl/tabctrl.hxx> -#include <vcl/controldata.hxx> -#include <vcl/sound.hxx> - -#include <vcl/window.h> +#include "tools/debug.hxx" + +#include "tools/rc.h" +#include "vcl/svdata.hxx" +#include "vcl/svapp.hxx" +#include "vcl/help.hxx" +#include "vcl/event.hxx" +#include "vcl/menu.hxx" +#include "vcl/button.hxx" +#include "vcl/tabpage.hxx" +#include "vcl/tabctrl.hxx" +#include "vcl/controllayout.hxx" +#include "vcl/controldata.hxx" +#include "vcl/sound.hxx" +#include "vcl/lstbox.hxx" +#include "vcl/smartid.hxx" + +#include "vcl/window.h" #include <hash_map> #include <vector> @@ -87,6 +86,8 @@ struct ImplTabCtrlData std::vector< Rectangle > maTabRectangles; Point maItemsOffset; // offset of the tabitems std::vector< ImplTabItem > maItemList; + ListBox* mpListBox; + Size maMinSize; }; // ----------------------------------------------------------------------- @@ -153,16 +154,25 @@ void TabControl::ImplInit( Window* pParent, WinBits nStyle ) mbRestoreUnqId = FALSE; mbSingleLine = FALSE; mbScroll = FALSE; - mbColored = FALSE; + mbRestoreSmartId = FALSE; mbSmallInvalidate = FALSE; mbExtraSpace = FALSE; mpTabCtrlData = new ImplTabCtrlData; mpTabCtrlData->mpLeftBtn = NULL; mpTabCtrlData->mpRightBtn = NULL; + mpTabCtrlData->mpListBox = NULL; ImplInitSettings( TRUE, TRUE, TRUE ); + if( (nStyle & WB_DROPDOWN) ) + { + mpTabCtrlData->mpListBox = new ListBox( this, WB_DROPDOWN ); + mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) ); + mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) ); + mpTabCtrlData->mpListBox->Show(); + } + // if the tabcontrol is drawn (ie filled) by a native widget, make sure all contols will have transparent background // otherwise they will paint with a wrong background if( IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) @@ -286,6 +296,8 @@ TabControl::~TabControl() // TabCtrl-Daten loeschen if ( mpTabCtrlData ) { + if( mpTabCtrlData->mpListBox ) + delete mpTabCtrlData->mpListBox; if ( mpTabCtrlData->mpLeftBtn ) delete mpTabCtrlData->mpLeftBtn; if ( mpTabCtrlData->mpRightBtn ) @@ -693,6 +705,8 @@ void TabControl::ImplChangeTabPage( USHORT nId, USHORT nOldId ) pCtrlParent->SetHelpId( 0 ); if ( mbRestoreUnqId ) pCtrlParent->SetUniqueId( 0 ); + if( mbRestoreSmartId ) + pCtrlParent->SetSmartHelpId( SmartId() ); pOldPage->DeactivatePage(); } @@ -700,8 +714,8 @@ void TabControl::ImplChangeTabPage( USHORT nId, USHORT nOldId ) { pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() ); - // Hier Page aktivieren, damit die Controls entsprechend umgeschaltet - // werden koennen und HilfeId gegebenenfalls beim Parent umsetzen + // activate page here so the conbtrols can be switched + // also set the help id of the parent window to that of the tab page if ( !GetHelpId() ) { mbRestoreHelpId = TRUE; @@ -712,6 +726,11 @@ void TabControl::ImplChangeTabPage( USHORT nId, USHORT nOldId ) mbRestoreUnqId = TRUE; pCtrlParent->SetUniqueId( pPage->GetUniqueId() ); } + if( ! GetSmartHelpId().HasAny() ) + { + mbRestoreSmartId = TRUE; + pCtrlParent->SetSmartHelpId( pPage->GetSmartHelpId() ); + } pPage->ActivatePage(); @@ -791,7 +810,7 @@ void TabControl::ImplSetFirstPagePos( USHORT ) void TabControl::ImplShowFocus() { - if ( !GetPageCount() ) + if ( !GetPageCount() || mpTabCtrlData->mpListBox ) return; // make sure the focussed item rect is computed using a bold font @@ -1062,16 +1081,27 @@ IMPL_LINK( TabControl, ImplScrollBtnHdl, PushButton*, EMPTYARG ) // ----------------------------------------------------------------------- +IMPL_LINK( TabControl, ImplListBoxSelectHdl, ListBox*, EMPTYARG ) +{ + SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectEntryPos() ) ); + return 0; +} + +// ----------------------------------------------------------------------- + void TabControl::MouseButtonDown( const MouseEvent& rMEvt ) { - if ( rMEvt.IsLeft() ) + if( mpTabCtrlData->mpListBox == NULL ) { - USHORT nPageId = GetPageId( rMEvt.GetPosPixel() ); - ImplTabItem* pItem = ImplGetItem( nPageId ); - if( pItem && pItem->mbEnabled ) - SelectTabPage( nPageId ); - else - Sound::Beep( SOUND_ERROR, this ); + if( rMEvt.IsLeft() ) + { + USHORT nPageId = GetPageId( rMEvt.GetPosPixel() ); + ImplTabItem* pItem = ImplGetItem( nPageId ); + if( pItem && pItem->mbEnabled ) + SelectTabPage( nPageId ); + else + Sound::Beep( SOUND_ERROR, this ); + } } } @@ -1079,7 +1109,9 @@ void TabControl::MouseButtonDown( const MouseEvent& rMEvt ) void TabControl::KeyInput( const KeyEvent& rKEvt ) { - if ( GetPageCount() > 1 ) + if( mpTabCtrlData->mpListBox ) + mpTabCtrlData->mpListBox->KeyInput( rKEvt ); + else if ( GetPageCount() > 1 ) { KeyCode aKeyCode = rKEvt.GetKeyCode(); USHORT nKeyCode = aKeyCode.GetCode(); @@ -1224,7 +1256,7 @@ void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout ) } } - if ( !mpTabCtrlData->maItemList.empty() ) + if ( !mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == NULL ) { // Some native toolkits (GTK+) draw tabs right-to-left, with an // overlap between adjacent tabs @@ -1294,6 +1326,18 @@ void TabControl::Resize() if ( !IsReallyShown() ) return; + if( mpTabCtrlData->mpListBox ) + { + // get the listbox' preferred size + Size aTabCtrlSize( GetSizePixel() ); + long nPrefWidth = mpTabCtrlData->mpListBox->GetOptimalSize( WINDOWSIZE_PREFERRED ).Width(); + if( nPrefWidth > aTabCtrlSize.Width() ) + nPrefWidth = aTabCtrlSize.Width(); + Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MAP_APPFONT ) ).Height() ); + Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 ); + mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize ); + } + mbFormat = TRUE; // Aktuelle TabPage resizen/positionieren @@ -1343,8 +1387,16 @@ void TabControl::Resize() void TabControl::GetFocus() { - ImplShowFocus(); - SetInputContext( InputContext( GetFont() ) ); + if( ! mpTabCtrlData->mpListBox ) + { + ImplShowFocus(); + SetInputContext( InputContext( GetFont() ) ); + } + else + { + if( mpTabCtrlData->mpListBox->IsReallyVisible() ) + mpTabCtrlData->mpListBox->GrabFocus(); + } Control::GetFocus(); } @@ -1352,7 +1404,8 @@ void TabControl::GetFocus() void TabControl::LoseFocus() { - HideFocus(); + if( ! mpTabCtrlData->mpListBox ) + HideFocus(); Control::LoseFocus(); } @@ -1446,7 +1499,7 @@ void TabControl::RequestHelp( const HelpEvent& rHEvt ) void TabControl::Command( const CommandEvent& rCEvt ) { - if ( (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) ) + if( (mpTabCtrlData->mpListBox == NULL) && (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) ) { Point aMenuPos; BOOL bMenu; @@ -1490,7 +1543,11 @@ void TabControl::StateChanged( StateChangedType nType ) Control::StateChanged( nType ); if ( nType == STATE_CHANGE_INITSHOW ) + { ImplPosCurTabPage(); + if( mpTabCtrlData->mpListBox ) + Resize(); + } else if ( nType == STATE_CHANGE_UPDATEMODE ) { if ( IsUpdateMode() ) @@ -1708,24 +1765,34 @@ void TabControl::InsertPage( USHORT nPageId, const XubString& rText, DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND, "TabControl::InsertPage(): PageId already exists" ); - // set current page id - if ( !mnCurPageId ) - mnCurPageId = nPageId; - // insert new page item ImplTabItem* pItem = NULL; if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() ) { mpTabCtrlData->maItemList.push_back( ImplTabItem() ); pItem = &mpTabCtrlData->maItemList.back(); + if( mpTabCtrlData->mpListBox ) + mpTabCtrlData->mpListBox->InsertEntry( rText ); } else { std::vector< ImplTabItem >::iterator new_it = mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() ); pItem = &(*new_it); + if( mpTabCtrlData->mpListBox ) + mpTabCtrlData->mpListBox->InsertEntry( rText, nPos); + } + if( mpTabCtrlData->mpListBox ) + { + if( ! mnCurPageId ) + mpTabCtrlData->mpListBox->SelectEntryPos( 0 ); + mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() ); } + // set current page id + if ( !mnCurPageId ) + mnCurPageId = nPageId; + // init new page item pItem->mnId = nPageId; pItem->mpTabPage = NULL; @@ -1739,6 +1806,8 @@ void TabControl::InsertPage( USHORT nPageId, const XubString& rText, Invalidate(); ImplFreeLayoutData(); + if( mpTabCtrlData->mpListBox ) // reposition/resize listbox + Resize(); ImplCallEventListeners( VCLEVENT_TABPAGE_INSERTED, (void*) (ULONG)nPageId ); } @@ -1756,6 +1825,11 @@ void TabControl::RemovePage( USHORT nPageId ) std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos; bool bIsCurrentPage = (it->mnId == mnCurPageId); mpTabCtrlData->maItemList.erase( it ); + if( mpTabCtrlData->mpListBox ) + { + mpTabCtrlData->mpListBox->RemoveEntry( nPos ); + mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() ); + } // If current page is removed, than first page gets the current page if ( bIsCurrentPage ) @@ -1793,6 +1867,8 @@ void TabControl::Clear() // clear item list mpTabCtrlData->maItemList.clear(); mnCurPageId = 0; + if( mpTabCtrlData->mpListBox ) + mpTabCtrlData->mpListBox->Clear(); ImplFreeLayoutData(); @@ -1813,6 +1889,9 @@ void TabControl::EnablePage( USHORT i_nPageId, bool i_bEnable ) { pItem->mbEnabled = i_bEnable; mbFormat = TRUE; + if( mpTabCtrlData->mpListBox ) + mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ), + i_bEnable ? 0 : (LISTBOX_ENTRY_FLAG_DISABLE_SELECTION | LISTBOX_ENTRY_FLAG_DRAW_DISABLED) ); if( pItem->mnId == mnCurPageId ) { // SetCurPageId will change to an enabled page @@ -1937,6 +2016,8 @@ void TabControl::SelectTabPage( USHORT nPageId ) nPageId = mnActPageId; mnActPageId = 0; SetCurPageId( nPageId ); + if( mpTabCtrlData->mpListBox ) + mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) ); ImplCallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, (void*) (ULONG) nPageId ); } } @@ -2001,6 +2082,12 @@ void TabControl::SetPageText( USHORT nPageId, const XubString& rText ) { pItem->maText = rText; mbFormat = TRUE; + if( mpTabCtrlData->mpListBox ) + { + USHORT nPos = GetPagePos( nPageId ); + mpTabCtrlData->mpListBox->RemoveEntry( nPos ); + mpTabCtrlData->mpListBox->InsertEntry( rText, nPos ); + } if ( IsUpdateMode() ) Invalidate(); ImplFreeLayoutData(); @@ -2216,3 +2303,25 @@ Point TabControl::GetItemsOffset() const } // ----------------------------------------------------------------------- + +Size TabControl::GetOptimalSize(WindowSizeType eType) const +{ + switch (eType) { + case WINDOWSIZE_MINIMUM: + return mpTabCtrlData ? mpTabCtrlData->maMinSize : Size(); + default: + return Control::GetOptimalSize( eType ); + } +} + +// ----------------------------------------------------------------------- + +void TabControl::SetMinimumSizePixel( const Size& i_rSize ) +{ + if( mpTabCtrlData ) + mpTabCtrlData->maMinSize = i_rSize; +} + +// ----------------------------------------------------------------------- + + diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx index 6483c8292df7..951d80f9af9d 100644 --- a/vcl/source/gdi/gdimtf.cxx +++ b/vcl/source/gdi/gdimtf.cxx @@ -876,6 +876,40 @@ void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY ) // ------------------------------------------------------------------------ +void GDIMetaFile::Clip( const Rectangle& i_rClipRect ) +{ + Rectangle aCurRect( i_rClipRect ); + VirtualDevice aMapVDev; + + aMapVDev.EnableOutput( FALSE ); + aMapVDev.SetMapMode( GetPrefMapMode() ); + + for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() ) + { + const long nType = pAct->GetType(); + + if( ( META_MAPMODE_ACTION == nType ) || + ( META_PUSH_ACTION == nType ) || + ( META_POP_ACTION == nType ) ) + { + pAct->Execute( &aMapVDev ); + aCurRect = aMapVDev.LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev.GetMapMode() ); + } + else if( nType == META_CLIPREGION_ACTION ) + { + MetaClipRegionAction* pOldAct = (MetaClipRegionAction*)pAct; + Region aNewReg( aCurRect ); + if( pOldAct->IsClipping() ) + aNewReg.Intersect( pOldAct->GetRegion() ); + MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, TRUE ); + Replace( pNewAct, GetCurPos() ); + pOldAct->Delete(); + } + } +} + +// ------------------------------------------------------------------------ + Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt, const Size& rOffset, double fSin, double fCos ) { diff --git a/vcl/source/gdi/impprn.cxx b/vcl/source/gdi/impprn.cxx index 539c879c89ea..28d92a0b3832 100644 --- a/vcl/source/gdi/impprn.cxx +++ b/vcl/source/gdi/impprn.cxx @@ -478,10 +478,12 @@ void ImplQPrinter::EndQueuePrint() DBG_ASSERT( mpPrinter, "no SalPrinter in ImplQPrinter" ); if( mpPrinter ) { + #if 0 mpPrinter->StartJob( mbPrintFile ? &maPrintFile : NULL, Application::GetDisplayName(), maJobSetup.ImplGetConstData(), this ); + #endif EndJob(); mpParent->ImplEndPrint(); } diff --git a/vcl/source/gdi/jobset.cxx b/vcl/source/gdi/jobset.cxx index 686d33593466..4823a5492ded 100644 --- a/vcl/source/gdi/jobset.cxx +++ b/vcl/source/gdi/jobset.cxx @@ -73,6 +73,7 @@ ImplJobSetup::ImplJobSetup() mnRefCount = 1; mnSystem = 0; meOrientation = ORIENTATION_PORTRAIT; + meDuplexMode = DUPLEX_UNKNOWN; mnPaperBin = 0; mePaperFormat = PAPER_USER; mnPaperWidth = 0; @@ -90,6 +91,7 @@ ImplJobSetup::ImplJobSetup( const ImplJobSetup& rJobSetup ) : mnRefCount = 1; mnSystem = rJobSetup.mnSystem; meOrientation = rJobSetup.meOrientation; + meDuplexMode = rJobSetup.meDuplexMode; mnPaperBin = rJobSetup.mnPaperBin; mePaperFormat = rJobSetup.mePaperFormat; mnPaperWidth = rJobSetup.mnPaperWidth; @@ -277,6 +279,7 @@ BOOL JobSetup::operator==( const JobSetup& rJobSetup ) const (pData1->maPrinterName == pData2->maPrinterName) && (pData1->maDriver == pData2->maDriver) && (pData1->meOrientation == pData2->meOrientation) && + (pData1->meDuplexMode == pData2->meDuplexMode) && (pData1->mnPaperBin == pData2->mnPaperBin) && (pData1->mePaperFormat == pData2->mePaperFormat) && (pData1->mnPaperWidth == pData2->mnPaperWidth) && @@ -337,6 +340,7 @@ SvStream& operator>>( SvStream& rIStream, JobSetup& rJobSetup ) pJobData->mnSystem = SVBT16ToShort( pOldJobData->nSystem ); pJobData->mnDriverDataLen = SVBT32ToUInt32( pOldJobData->nDriverDataLen ); pJobData->meOrientation = (Orientation)SVBT16ToShort( pOldJobData->nOrientation ); + pJobData->meDuplexMode = DUPLEX_UNKNOWN; pJobData->mnPaperBin = SVBT16ToShort( pOldJobData->nPaperBin ); pJobData->mePaperFormat = (Paper)SVBT16ToShort( pOldJobData->nPaperFormat ); pJobData->mnPaperWidth = (long)SVBT32ToUInt32( pOldJobData->nPaperWidth ); @@ -355,7 +359,19 @@ SvStream& operator>>( SvStream& rIStream, JobSetup& rJobSetup ) String aKey, aValue; rIStream.ReadByteString( aKey, RTL_TEXTENCODING_UTF8 ); rIStream.ReadByteString( aValue, RTL_TEXTENCODING_UTF8 ); - pJobData->maValueMap[ aKey ] = aValue; + if( aKey.EqualsAscii( "COMPAT_DUPLEX_MODE" ) ) + { + if( aValue.EqualsAscii( "DUPLEX_UNKNOWN" ) ) + pJobData->meDuplexMode = DUPLEX_UNKNOWN; + else if( aValue.EqualsAscii( "DUPLEX_OFF" ) ) + pJobData->meDuplexMode = DUPLEX_OFF; + else if( aValue.EqualsAscii( "DUPLEX_SHORTEDGE" ) ) + pJobData->meDuplexMode = DUPLEX_SHORTEDGE; + else if( aValue.EqualsAscii( "DUPLEX_LONGEDGE" ) ) + pJobData->meDuplexMode = DUPLEX_LONGEDGE; + } + else + pJobData->maValueMap[ aKey ] = aValue; } DBG_ASSERT( rIStream.Tell() == nFirstPos+nLen, "corrupted job setup" ); // ensure correct stream position @@ -421,6 +437,14 @@ SvStream& operator<<( SvStream& rOStream, const JobSetup& rJobSetup ) rOStream.WriteByteString( it->first, RTL_TEXTENCODING_UTF8 ); rOStream.WriteByteString( it->second, RTL_TEXTENCODING_UTF8 ); } + rOStream.WriteByteString( "COMPAT_DUPLEX_MODE" ) ; + switch( pJobData->meDuplexMode ) + { + case DUPLEX_UNKNOWN: rOStream.WriteByteString( "DUPLEX_UNKNOWN" );break; + case DUPLEX_OFF: rOStream.WriteByteString( "DUPLEX_OFF" );break; + case DUPLEX_SHORTEDGE: rOStream.WriteByteString( "DUPLEX_SHORTEDGE" );break; + case DUPLEX_LONGEDGE: rOStream.WriteByteString( "DUPLEX_LONGEDGE" );break; + } nLen = sal::static_int_cast<USHORT>(rOStream.Tell() - nPos); rOStream.Seek( nPos ); rOStream << nLen; diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk index eda537bf629a..ed2a9b2ba1e1 100755..100644 --- a/vcl/source/gdi/makefile.mk +++ b/vcl/source/gdi/makefile.mk @@ -57,6 +57,8 @@ EXCEPTIONSFILES= $(SLO)$/salmisc.obj \ $(SLO)$/gfxlink.obj \ $(SLO)$/print.obj \ $(SLO)$/print2.obj \ + $(SLO)$/print3.obj \ + $(SLO)$/oldprintadaptor.obj \ $(SLO)$/configsettings.obj \ $(SLO)$/sallayout.obj \ $(SLO)$/image.obj \ @@ -72,7 +74,6 @@ EXCEPTIONSFILES= $(SLO)$/salmisc.obj \ $(SLO)$/pngread.obj \ $(SLO)$/pngwrite.obj \ $(SLO)$/virdev.obj \ - $(SLO)$/impprn.obj \ $(SLO)$/gdimtf.obj \ $(SLO)$/graphictools.obj \ $(SLO)$/textlayout.obj \ @@ -118,6 +119,7 @@ SLOFILES= $(EXCEPTIONSFILES) \ $(SLO)$/extoutdevdata.obj \ $(SLO)$/salnativewidgets-none.obj + # --- Targets ------------------------------------------------------ .INCLUDE : target.mk diff --git a/vcl/source/gdi/oldprintadaptor.cxx b/vcl/source/gdi/oldprintadaptor.cxx new file mode 100644 index 000000000000..cffd11daaad6 --- /dev/null +++ b/vcl/source/gdi/oldprintadaptor.cxx @@ -0,0 +1,117 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/oldprintadaptor.hxx" +#include "vcl/gdimtf.hxx" + +#include "com/sun/star/awt/Size.hpp" + +#include <vector> + +namespace vcl +{ + struct AdaptorPage + { + GDIMetaFile maPage; + com::sun::star::awt::Size maPageSize; + }; + + struct ImplOldStyleAdaptorData + { + std::vector< AdaptorPage > maPages; + }; +} + +using namespace vcl; +using namespace cppu; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; + +OldStylePrintAdaptor::OldStylePrintAdaptor( const boost::shared_ptr< Printer >& i_pPrinter ) + : PrinterController( i_pPrinter ) + , mpData( new ImplOldStyleAdaptorData() ) +{ +} + +OldStylePrintAdaptor::~OldStylePrintAdaptor() +{ +} + +void OldStylePrintAdaptor::StartPage() +{ + Size aPaperSize( getPrinter()->PixelToLogic( getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + mpData->maPages.push_back( AdaptorPage() ); + mpData->maPages.back().maPageSize.Width = aPaperSize.getWidth(); + mpData->maPages.back().maPageSize.Height = aPaperSize.getHeight(); + getPrinter()->SetConnectMetaFile( &mpData->maPages.back().maPage ); + + // copy state into metafile + boost::shared_ptr<Printer> pPrinter( getPrinter() ); + pPrinter->SetMapMode( pPrinter->GetMapMode() ); + pPrinter->SetFont( pPrinter->GetFont() ); + pPrinter->SetDrawMode( pPrinter->GetDrawMode() ); + pPrinter->SetLineColor( pPrinter->GetLineColor() ); + pPrinter->SetFillColor( pPrinter->GetFillColor() ); +} + +void OldStylePrintAdaptor::EndPage() +{ + getPrinter()->SetConnectMetaFile( NULL ); + mpData->maPages.back().maPage.WindStart(); +} + +int OldStylePrintAdaptor::getPageCount() const +{ + return int(mpData->maPages.size()); +} + +Sequence< PropertyValue > OldStylePrintAdaptor::getPageParameters( int i_nPage ) const +{ + Sequence< PropertyValue > aRet( 1 ); + aRet[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("PageSize") ); + if( i_nPage < int(mpData->maPages.size() ) ) + aRet[0].Value = makeAny( mpData->maPages[i_nPage].maPageSize ); + else + { + awt::Size aEmpty( 0, 0 ); + aRet[0].Value = makeAny( aEmpty ); + } + return aRet; +} + +void OldStylePrintAdaptor::printPage( int i_nPage ) const +{ + if( i_nPage < int(mpData->maPages.size()) ) + { + mpData->maPages[ i_nPage ].maPage.WindStart(); + mpData->maPages[ i_nPage ].maPage.Play( getPrinter().get() ); + } +} + diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index 937d966b3978..16f6b53af7a8 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: print.cxx,v $ - * $Revision: 1.65 $ + * $Revision: 1.65.114.1 $ * * This file is part of OpenOffice.org. * @@ -31,8 +31,6 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#define _SPOOLPRINTER_EXT -#define _RMPRINTER_EXT #define ENABLE_BYTESTRING_STREAM_OPERATORS #include <list> @@ -58,7 +56,6 @@ #include <vcl/print.h> #include <vcl/gdimtf.hxx> #include <vcl/metaact.hxx> -#include <vcl/impprn.hxx> #include <vcl/print.hxx> #include <comphelper/processfactory.hxx> @@ -280,7 +277,9 @@ static void ImplInitPrnQueueList() pSVData->maGDIData.mpPrinterQueueList = new ImplPrnQueueList; - pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList ); + static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" ); + if( !pEnv || !*pEnv ) + pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList ); } // ----------------------------------------------------------------------- @@ -339,16 +338,20 @@ const QueueInfo* Printer::GetQueueInfo( const String& rPrinterName, bool bStatus XubString Printer::GetDefaultPrinterName() { - ImplSVData* pSVData = ImplGetSVData(); + static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" ); + if( !pEnv || !*pEnv ) + { + ImplSVData* pSVData = ImplGetSVData(); - return pSVData->mpDefInst->GetDefaultPrinter(); + return pSVData->mpDefInst->GetDefaultPrinter(); + } + return XubString(); } // ======================================================================= void Printer::ImplInitData() { - mpPrinterData = new ImplPrivatePrinterData(); mbDevOutput = FALSE; meOutDevType = OUTDEV_PRINTER; mbDefPrinter = FALSE; @@ -366,8 +369,6 @@ void Printer::ImplInitData() mpInfoPrinter = NULL; mpPrinter = NULL; mpDisplayDev = NULL; - mpQPrinter = NULL; - mpQMtf = NULL; mbIsQueuePrinter = FALSE; mpPrinterOptions = new PrinterOptions; @@ -414,7 +415,6 @@ void Printer::ImplInit( SalPrinterQueueInfo* pInfo ) mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, pJobSetup ); mpPrinter = NULL; - mpJobPrinter = NULL; mpJobGraphics = NULL; ImplUpdateJobSetupPaper( maJobSetup ); @@ -446,7 +446,6 @@ void Printer::ImplInitDisplay( const Window* pWindow ) mpInfoPrinter = NULL; mpPrinter = NULL; - mpJobPrinter = NULL; mpJobGraphics = NULL; if ( pWindow ) @@ -518,6 +517,26 @@ void Printer::ImplUpdatePageData() mnOutWidth, mnOutHeight, maPageOffset.X(), maPageOffset.Y(), maPaperSize.Width(), maPaperSize.Height() ); + static const char* pDebugOffset = getenv( "SAL_DBG_PAGEOFFSET" ); + if( pDebugOffset ) + { + rtl::OString aLine( pDebugOffset ); + sal_Int32 nIndex = 0; + rtl::OString aToken( aLine.getToken( 0, ',', nIndex ) ); + sal_Int32 nLeft = aToken.toInt32(); + sal_Int32 nTop = nLeft; + if( nIndex > 0 ) + { + aToken = aLine.getToken( 0, ',', nIndex ); + nTop = aToken.toInt32(); + } + maPageOffset = LogicToPixel( Point( static_cast<long>(nLeft), + static_cast<long>(nTop) ), + MapMode( MAP_100TH_MM ) + ); + mnOutWidth = maPaperSize.Width() - 2*maPageOffset.X(); + mnOutWidth = maPaperSize.Width() - 2*maPageOffset.Y(); + } } // ----------------------------------------------------------------------- @@ -602,11 +621,6 @@ Printer::~Printer() { DBG_ASSERT( !IsPrinting(), "Printer::~Printer() - Job is printing" ); DBG_ASSERT( !IsJobActive(), "Printer::~Printer() - Job is active" ); - DBG_ASSERT( !mpQPrinter, "Printer::~Printer() - QueuePrinter not destroyed" ); - DBG_ASSERT( !mpQMtf, "Printer::~Printer() - QueueMetafile not destroyed" ); - - delete mpPrinterData; - mpPrinterData = NULL; delete mpPrinterOptions; @@ -653,21 +667,11 @@ Printer::~Printer() } // ----------------------------------------------------------------------- -void Printer::SetNextJobIsQuick( bool bQuick ) -{ - mpPrinterData->mbNextJobIsQuick = bQuick; - if( mpQPrinter ) - mpQPrinter->SetNextJobIsQuick( bQuick ); -} - -// ----------------------------------------------------------------------- void Printer::Compat_OldPrinterMetrics( bool bSet ) { // propagate flag if( mpInfoPrinter ) mpInfoPrinter->m_bCompatMetrics = bSet; - if( mpQPrinter ) - mpQPrinter->Compat_OldPrinterMetrics( bSet ); // get new font data ImplUpdateFontData( TRUE ); @@ -977,12 +981,13 @@ USHORT Printer::GetPaperBin() const // ----------------------------------------------------------------------- // Map user paper format to a available printer paper formats -void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) +void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup, bool bMatchNearest ) { ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); int nLandscapeAngle = GetLandscapeAngle(); int nPaperCount = GetPaperInfoCount(); + bool bFound = false; PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight); @@ -995,6 +1000,8 @@ void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) { pSetupData->mePaperFormat = ImplGetPaperFormat( rPaperInfo.getWidth(), rPaperInfo.getHeight() ); + pSetupData->meOrientation = ORIENTATION_PORTRAIT; + bFound = true; break; } } @@ -1017,10 +1024,49 @@ void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) { pSetupData->mePaperFormat = ImplGetPaperFormat( rPaperInfo.getWidth(), rPaperInfo.getHeight() ); + pSetupData->meOrientation = ORIENTATION_LANDSCAPE; + bFound = true; break; } } } + + if( ! bFound && bMatchNearest ) + { + sal_Int64 nBestMatch = SAL_MAX_INT64; + int nBestIndex = 0; + Orientation eBestOrientation = ORIENTATION_PORTRAIT; + for( int i = 0; i < nPaperCount; i++ ) + { + const PaperInfo& rPaperInfo = GetPaperInfo( i ); + + // check protrait match + sal_Int64 nDX = pSetupData->mnPaperWidth - rPaperInfo.getWidth(); + sal_Int64 nDY = pSetupData->mnPaperHeight - rPaperInfo.getHeight(); + sal_Int64 nMatch = nDX*nDX + nDY*nDY; + if( nMatch < nBestMatch ) + { + nBestMatch = nMatch; + nBestIndex = i; + eBestOrientation = ORIENTATION_PORTRAIT; + } + + // check landscape match + nDX = pSetupData->mnPaperWidth - rPaperInfo.getHeight(); + nDY = pSetupData->mnPaperHeight - rPaperInfo.getWidth(); + nMatch = nDX*nDX + nDY*nDY; + if( nMatch < nBestMatch ) + { + nBestMatch = nMatch; + nBestIndex = i; + eBestOrientation = ORIENTATION_LANDSCAPE; + } + } + const PaperInfo& rBestInfo = GetPaperInfo( nBestIndex ); + pSetupData->mePaperFormat = ImplGetPaperFormat( rBestInfo.getWidth(), + rBestInfo.getHeight() ); + pSetupData->meOrientation = eBestOrientation; + } } // ----------------------------------------------------------------------- @@ -1051,7 +1097,7 @@ BOOL Printer::SetPaper( Paper ePaper ) ImplReleaseGraphics(); if ( ePaper == PAPER_USER ) - ImplFindPaperFormatForUserSize( aJobSetup ); + ImplFindPaperFormatForUserSize( aJobSetup, false ); if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE|SAL_JOBSET_ORIENTATION, pSetupData ) ) { ImplUpdateJobSetupPaper( aJobSetup ); @@ -1072,6 +1118,11 @@ BOOL Printer::SetPaper( Paper ePaper ) BOOL Printer::SetPaperSizeUser( const Size& rSize ) { + return SetPaperSizeUser( rSize, false ); +} + +BOOL Printer::SetPaperSizeUser( const Size& rSize, bool bMatchNearest ) +{ if ( mbInPrintPage ) return FALSE; @@ -1095,7 +1146,7 @@ BOOL Printer::SetPaperSizeUser( const Size& rSize ) } ImplReleaseGraphics(); - ImplFindPaperFormatForUserSize( aJobSetup ); + ImplFindPaperFormatForUserSize( aJobSetup, bMatchNearest ); // Changing the paper size can also change the orientation! if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE|SAL_JOBSET_ORIENTATION, pSetupData ) ) @@ -1142,7 +1193,44 @@ const PaperInfo& Printer::GetPaperInfo( int nPaper ) const DuplexMode Printer::GetDuplexMode() const { - return mpInfoPrinter ? mpInfoPrinter->GetDuplexMode( maJobSetup.ImplGetConstData() ) : DUPLEX_UNKNOWN; + return maJobSetup.ImplGetConstData()->meDuplexMode; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetDuplexMode( DuplexMode eDuplex ) +{ + if ( mbInPrintPage ) + return FALSE; + + if ( maJobSetup.ImplGetConstData()->meDuplexMode != eDuplex ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); + pSetupData->meDuplexMode = eDuplex; + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + return TRUE; + } + + ImplReleaseGraphics(); + if ( mpInfoPrinter->SetData( SAL_JOBSET_DUPLEXMODE, pSetupData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + else + return FALSE; + } + + return TRUE; } // ----------------------------------------------------------------------- @@ -1184,9 +1272,10 @@ XubString Printer::GetPaperBinName( USHORT nPaperBin ) const // ----------------------------------------------------------------------- -BOOL Printer::SetCopyCount( USHORT nCopy, BOOL /*bCollate*/ ) +BOOL Printer::SetCopyCount( USHORT nCopy, BOOL bCollate ) { mnCopyCount = nCopy; + mbCollateCopy = bCollate; return TRUE; } @@ -1199,29 +1288,8 @@ void Printer::Error() // ----------------------------------------------------------------------- -void Printer::StartPrint() -{ - maStartPrintHdl.Call( this ); -} - -// ----------------------------------------------------------------------- - -void Printer::EndPrint() -{ - maEndPrintHdl.Call( this ); -} - -// ----------------------------------------------------------------------- - -void Printer::PrintPage() -{ - maPrintPageHdl.Call( this ); -} - -// ----------------------------------------------------------------------- - -ULONG ImplSalPrinterErrorCodeToVCL( ULONG nError ) +ULONG Printer::ImplSalPrinterErrorCodeToVCL( ULONG nError ) { ULONG nVCLError; switch ( nError ) @@ -1247,12 +1315,6 @@ void Printer::ImplEndPrint() mbPrinting = FALSE; mnCurPrintPage = 0; maJobName.Erase(); - if( mpQPrinter ) // not necessarily filled e.g. after AbortJob - { - mpQPrinter->Destroy(); - mpQPrinter = NULL; - } - EndPrint(); } // ----------------------------------------------------------------------- @@ -1267,180 +1329,6 @@ IMPL_LINK( Printer, ImplDestroyPrinterAsync, void*, pSalPrinter ) // ----------------------------------------------------------------------- -void Printer::ImplUpdateQuickStatus() -{ - // remove possibly added "IsQuickJob" - if( mpPrinterData->mbNextJobIsQuick ) - { - rtl::OUString aKey( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ); - // const data means not really const, but change all references - // to refcounted job setup - ImplJobSetup* pImpSetup = maJobSetup.ImplGetConstData(); - pImpSetup->maValueMap.erase( aKey ); - mpPrinterData->mbNextJobIsQuick = false; - } -} - -class QuickGuard -{ - Printer* mpPrinter; - public: - QuickGuard( Printer* pPrn ) : mpPrinter( pPrn ) {} - ~QuickGuard() - { - mpPrinter->ImplUpdateQuickStatus(); - } -}; - -BOOL Printer::StartJob( const XubString& rJobName ) -{ - mnError = PRINTER_OK; - - if ( IsDisplayPrinter() ) - return FALSE; - - if ( IsJobActive() || IsPrinting() ) - return FALSE; - - if( mpPrinterData->mbNextJobIsQuick ) - { - String aKey( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ); - if( maJobSetup.GetValue( aKey ).Len() == 0 ) - maJobSetup.SetValue( aKey, String( RTL_CONSTASCII_USTRINGPARAM( "true" ) ) ); - } - - QuickGuard aQGuard( this ); - - ULONG nCopies = mnCopyCount; - BOOL bCollateCopy = mbCollateCopy; - BOOL bUserCopy = FALSE; - if ( IsQueuePrinter() ) - { - if ( ((ImplQPrinter*)this)->IsUserCopy() ) - { - nCopies = 1; - bCollateCopy = FALSE; - } - } - else - { - if ( nCopies > 1 ) - { - ULONG nDevCopy; - - if ( bCollateCopy ) - nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES ); - else - nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COPIES ); - - // Muessen Kopien selber gemacht werden? - if ( nCopies > nDevCopy ) - { - bUserCopy = TRUE; - nCopies = 1; - bCollateCopy = FALSE; - } - } - else - bCollateCopy = FALSE; - - // we need queue printing - if( !mnPageQueueSize ) - mnPageQueueSize = 1; - } - - if ( !mnPageQueueSize ) - { - ImplSVData* pSVData = ImplGetSVData(); - mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter ); - - if ( !mpPrinter ) - return FALSE; - - XubString* pPrintFile; - if ( mbPrintFile ) - pPrintFile = &maPrintFile; - else - pPrintFile = NULL; - - // #125075# StartJob can Reschedule on Windows, sfx - // depends on IsPrinting() in case of closing a document - BOOL bSaveNewJobSetup = mbNewJobSetup; - mbNewJobSetup = FALSE; - String aSaveJobName = maJobName; - maJobName = rJobName; - mnCurPage = 1; - mnCurPrintPage = 1; - mbPrinting = TRUE; - - if( ! ImplGetSVData()->maGDIData.mbPrinterPullModel ) - { - // in the pull model the job can only be started when - // we have collected all pages to be printed - if ( !mpPrinter->StartJob( pPrintFile, rJobName, Application::GetDisplayName(), - nCopies, bCollateCopy, - maJobSetup.ImplGetConstData() ) ) - { - mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); - if ( !mnError ) - mnError = PRINTER_GENERALERROR; - pSVData->mpDefInst->DestroyPrinter( mpPrinter ); - mbNewJobSetup = bSaveNewJobSetup; - maJobName = aSaveJobName; - mnCurPage = 0; - mnCurPrintPage = 0; - mbPrinting = FALSE; - mpPrinter = NULL; - return FALSE; - } - } - - mbJobActive = TRUE; - StartPrint(); - } - else - { - mpQPrinter = new ImplQPrinter( this ); - if( mpInfoPrinter ) - mpQPrinter->Compat_OldPrinterMetrics( mpInfoPrinter->m_bCompatMetrics ); - mpQPrinter->SetDigitLanguage( GetDigitLanguage() ); - mpQPrinter->SetUserCopy( bUserCopy ); - mpQPrinter->SetPrinterOptions( *mpPrinterOptions ); - - // #125075# StartJob can Reschedule on Windows, sfx - // depends on IsPrinting() in case of closing a document - BOOL bSaveNewJobSetup = mbNewJobSetup; - mbNewJobSetup = FALSE; - String aSaveJobName = maJobName; - maJobName = rJobName; - mnCurPage = 1; - mbPrinting = TRUE; - - if ( mpQPrinter->StartJob( rJobName ) ) - { - mbJobActive = TRUE; - StartPrint(); - mpQPrinter->StartQueuePrint(); - } - else - { - mbNewJobSetup = bSaveNewJobSetup; - maJobName = aSaveJobName; - mnCurPage = 0; - mbPrinting = FALSE; - mnError = mpQPrinter->GetErrorCode(); - mpQPrinter->Destroy(); - mpQPrinter = NULL; - return FALSE; - } - } - - - return TRUE; -} - -// ----------------------------------------------------------------------- - BOOL Printer::EndJob() { BOOL bRet = FALSE; @@ -1451,7 +1339,7 @@ BOOL Printer::EndJob() mbJobActive = FALSE; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { ImplReleaseGraphics(); @@ -1459,23 +1347,17 @@ BOOL Printer::EndJob() bRet = TRUE; - if ( mpPrinter ) - { - mbPrinting = FALSE; - mnCurPrintPage = 0; - maJobName.Erase(); - - mbDevOutput = FALSE; - bRet = mpPrinter->EndJob(); - // Hier den Drucker nicht asyncron zerstoeren, da es - // W95 nicht verkraftet, wenn gleichzeitig gedruckt wird - // und ein Druckerobjekt zerstoert wird - ImplGetSVData()->mpDefInst->DestroyPrinter( mpPrinter ); - mpPrinter = NULL; - EndPrint(); - } - else - mpQPrinter->EndQueuePrint(); + mbPrinting = FALSE; + mnCurPrintPage = 0; + maJobName.Erase(); + + mbDevOutput = FALSE; + bRet = mpPrinter->EndJob(); + // Hier den Drucker nicht asyncron zerstoeren, da es + // W95 nicht verkraftet, wenn gleichzeitig gedruckt wird + // und ein Druckerobjekt zerstoert wird + ImplGetSVData()->mpDefInst->DestroyPrinter( mpPrinter ); + mpPrinter = NULL; } return bRet; @@ -1494,35 +1376,18 @@ BOOL Printer::AbortJob() mbInPrintPage = FALSE; mpJobGraphics = NULL; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { mbPrinting = FALSE; mnCurPage = 0; mnCurPrintPage = 0; maJobName.Erase(); - if ( mpPrinter ) - { - ImplReleaseGraphics(); - mbDevOutput = FALSE; - mpPrinter->AbortJob(); - Application::PostUserEvent( LINK( this, Printer, ImplDestroyPrinterAsync ), mpPrinter ); - mpPrinter = NULL; - EndPrint(); - } - else - { - mpQPrinter->AbortQueuePrint(); - mpQPrinter->Destroy(); - mpQPrinter = NULL; - if ( mpQMtf ) - { - mpQMtf->Clear(); - delete mpQMtf; - mpQMtf = NULL; - } - EndPrint(); - } + ImplReleaseGraphics(); + mbDevOutput = FALSE; + mpPrinter->AbortJob(); + Application::PostUserEvent( LINK( this, Printer, ImplDestroyPrinterAsync ), mpPrinter ); + mpPrinter = NULL; return TRUE; } @@ -1532,88 +1397,49 @@ BOOL Printer::AbortJob() // ----------------------------------------------------------------------- -BOOL Printer::StartPage() +void Printer::ImplStartPage() { if ( !IsJobActive() ) - return FALSE; + return; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { - if ( mpPrinter ) - { - SalGraphics* pGraphics = mpPrinter->StartPage( maJobSetup.ImplGetConstData(), mbNewJobSetup ); - if ( pGraphics ) - { - ImplReleaseGraphics(); - mpJobGraphics = pGraphics; - } - mbDevOutput = TRUE; - } - else + SalGraphics* pGraphics = mpPrinter->StartPage( maJobSetup.ImplGetConstData(), mbNewJobSetup ); + if ( pGraphics ) { - ImplGetGraphics(); - mpJobGraphics = mpGraphics; + ImplReleaseGraphics(); + mpJobGraphics = pGraphics; } + mbDevOutput = TRUE; // PrintJob not aborted ??? if ( IsJobActive() ) { mbInPrintPage = TRUE; mnCurPage++; - if ( mpQPrinter ) - { - mpQPrinter->SetPrinterOptions( *mpPrinterOptions ); - mpQMtf = new GDIMetaFile; - mpQMtf->Record( this ); - mpQMtf->SaveStatus(); - } - else - { - mnCurPrintPage++; - PrintPage(); - } + mnCurPrintPage++; } - - return TRUE; } - - return FALSE; } // ----------------------------------------------------------------------- -BOOL Printer::EndPage() +void Printer::ImplEndPage() { if ( !IsJobActive() ) - return FALSE; + return; mbInPrintPage = FALSE; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { - if ( mpPrinter ) - { - mpPrinter->EndPage(); - ImplReleaseGraphics(); - mbDevOutput = FALSE; - } - else if ( mpQPrinter ) - { - // Eigentuemeruebergang an QPrinter - mpQMtf->Stop(); - mpQMtf->WindStart(); - GDIMetaFile* pPage = mpQMtf; - mpQMtf = NULL; - mpQPrinter->AddQueuePage( pPage, mnCurPage, mbNewJobSetup ); - } + mpPrinter->EndPage(); + ImplReleaseGraphics(); + mbDevOutput = FALSE; mpJobGraphics = NULL; mbNewJobSetup = FALSE; - - return TRUE; } - - return FALSE; } // ----------------------------------------------------------------------- diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx index 685f68fe7af3..9d435af5f4b1 100644 --- a/vcl/source/gdi/print2.cxx +++ b/vcl/source/gdi/print2.cxx @@ -31,8 +31,6 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#define _SPOOLPRINTER_EXT - #include <functional> #include <algorithm> #include <utility> @@ -648,7 +646,9 @@ static bool ImplIsActionHandlingTransparency( const MetaAction& rAct ) bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf, long nMaxBmpDPIX, long nMaxBmpDPIY, bool bReduceTransparency, bool bTransparencyAutoMode, - bool bDownsampleBitmaps ) + bool bDownsampleBitmaps, + const Color& rBackground + ) { MetaAction* pCurrAct; bool bTransparent( false ); @@ -737,6 +737,20 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, bool bStillBackground=true; // true until first non-bg action nActionNum=0; nLastBgAction=-1; pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(); + if( rBackground != Color( COL_TRANSPARENT ) ) + { + aBackgroundComponent.aBgColor = rBackground; + if( meOutDevType == OUTDEV_PRINTER ) + { + Printer* pThis = dynamic_cast<Printer*>(this); + Point aPageOffset = pThis->GetPageOffsetPixel(); + aPageOffset = Point( 0, 0 ) - aPageOffset; + Size aSize = pThis->GetPaperSizePixel(); + aBackgroundComponent.aBounds = Rectangle( aPageOffset, aSize ); + } + else + aBackgroundComponent.aBounds = Rectangle( Point( 0, 0 ), GetOutputSizePixel() ); + } while( pCurrAct && bStillBackground ) { switch( pCurrAct->GetType() ) @@ -880,7 +894,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // // if aBBCurrAct is empty, it will intersect with no - // aCCList member. Thus, we can safe us the check. + // aCCList member. Thus, we can save the check. // Furthermore, this ensures that non-output-generating // actions get their own aCCList entry, which is necessary // when copying them to the output metafile (see stage 4 @@ -1110,7 +1124,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // ==================================================== // - Point aTmpPoint; + Point aPageOffset; Size aTmpSize( GetOutputSizePixel() ); if( mpPDFWriter ) { @@ -1120,7 +1134,14 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // also add error code to PDFWriter mpPDFWriter->insertError( vcl::PDFWriter::Warning_Transparency_Converted ); } - const Rectangle aOutputRect( aTmpPoint, aTmpSize ); + else if( meOutDevType == OUTDEV_PRINTER ) + { + Printer* pThis = dynamic_cast<Printer*>(this); + aPageOffset = pThis->GetPageOffsetPixel(); + aPageOffset = Point( 0, 0 ) - aPageOffset; + aTmpSize = pThis->GetPaperSizePixel(); + } + const Rectangle aOutputRect( aPageOffset, aTmpSize ); bool bTiling = dynamic_cast<Printer*>(this) != NULL; // iterate over all aCCList members and generate bitmaps for the special ones @@ -1228,7 +1249,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, pCurrAct->Execute( &aPaintVDev ); } - if( !( nActionNum % 4 ) ) + if( !( nActionNum % 8 ) ) Application::Reschedule(); } diff --git a/vcl/source/gdi/print3.cxx b/vcl/source/gdi/print3.cxx new file mode 100644 index 000000000000..6778cfbc867e --- /dev/null +++ b/vcl/source/gdi/print3.cxx @@ -0,0 +1,1765 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: print3.cxx,v $ + * $Revision: 1.1.2.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/print.hxx" +#include "vcl/prndlg.hxx" +#include "vcl/svapp.hxx" +#include "vcl/svdata.hxx" +#include "vcl/salinst.hxx" +#include "vcl/salprn.hxx" +#include "vcl/svids.hrc" +#include "vcl/metaact.hxx" +#include "vcl/msgbox.hxx" + +#include "tools/urlobj.hxx" + +#include "com/sun/star/ui/dialogs/XFilePicker.hpp" +#include "com/sun/star/ui/dialogs/XFilterManager.hpp" +#include "com/sun/star/ui/dialogs/TemplateDescription.hpp" +#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" +#include "com/sun/star/view/DuplexMode.hpp" +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/awt/Size.hpp" +#include "comphelper/processfactory.hxx" + +#include <hash_map> +#include <hash_set> + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace vcl; + +class ImplPageCache +{ + struct CacheEntry + { + GDIMetaFile aPage; + PrinterController::PageSize aSize; + }; + + std::vector< CacheEntry > maPages; + std::vector< sal_Int32 > maPageNumbers; + std::vector< sal_Int32 > maCacheRanking; + + static const sal_Int32 nCacheSize = 6; + + void updateRanking( sal_Int32 nLastHit ) + { + if( maCacheRanking[0] != nLastHit ) + { + bool bMove = false; + for( sal_Int32 i = nCacheSize-1; i > 0; i-- ) + { + if( maCacheRanking[i] == nLastHit ) + bMove = true; + maCacheRanking[i] = maCacheRanking[i-1]; + } + maCacheRanking[0] = nLastHit; + } + } + +public: + ImplPageCache() + : maPages( nCacheSize ) + , maPageNumbers( nCacheSize, -1 ) + , maCacheRanking( nCacheSize ) + { + for( sal_Int32 i = 0; i < nCacheSize; i++ ) + maCacheRanking[i] = nCacheSize - i - 1; + } + + // caution: does not ensure uniqueness + void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize ) + { + sal_Int32 nReplacePage = maCacheRanking.back(); + maPages[ nReplacePage ].aPage = i_rPage; + maPages[ nReplacePage ].aSize = i_rSize; + maPageNumbers[ nReplacePage ] = i_nPageNo; + // cache insertion means in our case, the page was just queried + // so update the ranking + updateRanking( nReplacePage ); + } + + // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6 + // this needs to be urgently rewritten. However do NOT increase the cache size lightly, + // whole pages can be rather memory intensive + bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize ) + { + for( sal_Int32 i = 0; i < nCacheSize; ++i ) + { + if( maPageNumbers[i] == i_nPageNo ) + { + updateRanking( i ); + o_rPageFile = maPages[i].aPage; + o_rSize = maPages[i].aSize; + return true; + } + } + return false; + } + + void invalidate() + { + for( sal_Int32 i = 0; i < nCacheSize; ++i ) + { + maPageNumbers[i] = -1; + maPages[i].aPage.Clear(); + maCacheRanking[i] = nCacheSize - i - 1; + } + } +}; + +class vcl::ImplPrinterControllerData +{ +public: + struct ControlDependency + { + rtl::OUString maDependsOnName; + sal_Int32 mnDependsOnEntry; + + ControlDependency() : mnDependsOnEntry( -1 ) {} + }; + + typedef std::hash_map< rtl::OUString, size_t, rtl::OUStringHash > PropertyToIndexMap; + typedef std::hash_map< rtl::OUString, ControlDependency, rtl::OUStringHash > ControlDependencyMap; + + boost::shared_ptr<Printer> mpPrinter; + Sequence< PropertyValue > maUIOptions; + std::vector< PropertyValue > maUIProperties; + std::vector< bool > maUIPropertyEnabled; + PropertyToIndexMap maPropertyToIndex; + Link maOptionChangeHdl; + ControlDependencyMap maControlDependencies; + sal_Bool mbFirstPage; + sal_Bool mbLastPage; + sal_Bool mbReversePageOrder; + view::PrintableState meJobState; + + vcl::PrinterController::MultiPageSetup maMultiPage; + + vcl::PrintProgressDialog* mpProgress; + + ImplPageCache maPageCache; + + // set by user through printer config dialog + // if set, pages are centered and trimmed onto the fixed page + Size maFixedPageSize; + + ImplPrinterControllerData() : + mbFirstPage( sal_True ), + mbLastPage( sal_False ), + mbReversePageOrder( sal_False ), + meJobState( view::PrintableState_JOB_STARTED ), + mpProgress( NULL ) + {} + ~ImplPrinterControllerData() { delete mpProgress; } + + Size getRealPaperSize( const Size& i_rPageSize ) const + { + if( maFixedPageSize.Width() > 0 && maFixedPageSize.Height() > 0 ) + return maFixedPageSize; + if( maMultiPage.nRows * maMultiPage.nColumns > 1 ) + return maMultiPage.aPaperSize; + return i_rPageSize; + } + bool isFixedPageSize() const + { return maFixedPageSize.Width() != 0 && maFixedPageSize.Height() != 0; } + PrinterController::PageSize modifyJobSetup( const Sequence< PropertyValue >& i_rProps ); +}; + +PrinterController::PrinterController() + : mpImplData( new ImplPrinterControllerData ) +{ +} + +PrinterController::PrinterController( const boost::shared_ptr<Printer>& i_pPrinter ) + : mpImplData( new ImplPrinterControllerData ) +{ + mpImplData->mpPrinter = i_pPrinter; +} + +static rtl::OUString queryFile( Printer* pPrinter ) +{ + rtl::OUString aResult; + + uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() ); + if( xFactory.is() ) + { + uno::Sequence< uno::Any > aTempl( 1 ); + aTempl.getArray()[0] <<= ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION; + uno::Reference< ui::dialogs::XFilePicker > xFilePicker( + xFactory->createInstanceWithArguments( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FilePicker" ) ), + aTempl ), uno::UNO_QUERY ); + DBG_ASSERT( xFilePicker.is(), "could not get FilePicker service" ); + + uno::Reference< ui::dialogs::XFilterManager > xFilterMgr( xFilePicker, uno::UNO_QUERY ); + if( xFilePicker.is() && xFilterMgr.is() ) + { + try + { +#ifdef UNX + // add PostScript and PDF + bool bPS = true, bPDF = true; + if( pPrinter ) + { + if( pPrinter->GetCapabilities( PRINTER_CAPABILITIES_PDF ) ) + bPS = false; + else + bPDF = false; + } + if( bPS ) + xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PostScript" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.ps" ) ) ); + if( bPDF ) + xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Portable Document Format" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.pdf" ) ) ); +#elif defined WNT + (void)pPrinter; + xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.PRN" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.prn" ) ) ); +#endif + // add arbitrary files + xFilterMgr->appendFilter( String( VclResId( SV_STDTEXT_ALLFILETYPES ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.*" ) ) ); + } + catch( lang::IllegalArgumentException rExc ) + { + DBG_ERRORFILE( "caught IllegalArgumentException when registering filter\n" ); + } + + if( xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK ) + { + uno::Sequence< ::rtl::OUString > aPathSeq( xFilePicker->getFiles() ); + INetURLObject aObj( aPathSeq[0] ); + aResult = aObj.PathToFileName(); + } + } + } + return aResult; +} + +struct PrintJobAsync +{ + boost::shared_ptr<PrinterController> mpController; + JobSetup maInitSetup; + + PrintJobAsync( const boost::shared_ptr<PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ) + : mpController( i_pController ), maInitSetup( i_rInitSetup ) + {} + + DECL_LINK( ExecJob, void* ); +}; + +IMPL_LINK( PrintJobAsync, ExecJob, void*, EMPTYARG ) +{ + Printer::ImplPrintJob( mpController, maInitSetup ); + + // clean up, do not access members after this + delete this; + + return 0; +} + +void Printer::PrintJob( const boost::shared_ptr<PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ) +{ + sal_Bool bSynchronous = sal_False; + beans::PropertyValue* pVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Wait" ) ) ); + if( pVal ) + pVal->Value >>= bSynchronous; + + if( bSynchronous ) + ImplPrintJob( i_pController, i_rInitSetup ); + else + { + PrintJobAsync* pAsync = new PrintJobAsync( i_pController, i_rInitSetup ); + Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob ) ); + } +} + +void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ) +{ + boost::shared_ptr<PrinterController> pController( i_pController ); + + // check if there is a default printer; if not, show an error box (if appropriate) + if( GetDefaultPrinterName().Len() == 0 ) + { + if( pController->isShowDialogs() + // && ! pController->isDirectPrint() + ) + { + ErrorBox aBox( NULL, VclResId( SV_PRINT_NOPRINTERWARNING ) ); + aBox.Execute(); + } + pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ), + makeAny( sal_False ) ); + } + + // setup printer + + // if no specific printer is already set, create one + if( ! pController->getPrinter() ) + { + boost::shared_ptr<Printer> pPrinter( new Printer( i_rInitSetup.GetPrinterName() ) ); + pController->setPrinter( pPrinter ); + } + + // reset last page property + i_pController->setLastPage( sal_False ); + + // update "PageRange" property inferring from other properties: + // case 1: "Pages" set from UNO API -> + // setup "Print Selection" and insert "PageRange" attribute + // case 2: "All pages" is selected + // update "Page range" attribute to have a sensible default, + // but leave "All" as selected + + // "Pages" attribute from API is now equivalent to "PageRange" + // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1 + // Argh ! That sure needs cleaning up + beans::PropertyValue* pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintRange" ) ) ); + if( ! pContentVal ) + pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintContent" ) ) ); + + // case 1: UNO API has set "Pages" + beans::PropertyValue* pPagesVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pages" ) ) ); + if( pPagesVal ) + { + rtl::OUString aPagesVal; + pPagesVal->Value >>= aPagesVal; + if( aPagesVal.getLength() ) + { + // "Pages" attribute from API is now equivalent to "PageRange" + // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1 + // Argh ! That sure needs cleaning up + if( pContentVal ) + { + pContentVal->Value = makeAny( sal_Int32( 1 ) ); + i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), pPagesVal->Value ); + } + } + } + // case 2: is "All" selected ? + else if( pContentVal ) + { + sal_Int32 nContent = -1; + if( pContentVal->Value >>= nContent ) + { + if( nContent == 0 ) + { + sal_Int32 nPages = i_pController->getPageCount(); + if( nPages > 0 ) + { + rtl::OUStringBuffer aBuf( 32 ); + aBuf.appendAscii( "1" ); + if( nPages > 1 ) + { + aBuf.appendAscii( "-" ); + aBuf.append( nPages ); + } + i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), makeAny( aBuf.makeStringAndClear() ) ); + } + } + } + } + + beans::PropertyValue* pReverseVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintReverse" ) ) ); + if( pReverseVal ) + { + sal_Bool bReverse = sal_False; + pReverseVal->Value >>= bReverse; + pController->setReversePrint( bReverse ); + } + + // in direct print case check whether there is anything to print. + // if not, show an errorbox (if appropriate) + if( pController->isShowDialogs() && pController->isDirectPrint() ) + { + if( pController->getFilteredPageCount() == 0 ) + { + ErrorBox aBox( NULL, VclResId( SV_PRINT_NOCONTENT ) ); + aBox.Execute(); + return; + } + } + + // check if the printer brings up its own dialog + // in that case leave the work to that dialog + if( ! pController->getPrinter()->GetCapabilities( PRINTER_CAPABILITIES_EXTERNALDIALOG ) && + ! pController->isDirectPrint() && + pController->isShowDialogs() + ) + { + try + { + PrintDialog aDlg( NULL, i_pController ); + if( ! aDlg.Execute() ) + { + GDIMetaFile aPageFile; + i_pController->setLastPage( sal_True ); + i_pController->getFilteredPageFile( 0, aPageFile ); + return; + } + if( aDlg.isPrintToFile() ) + { + rtl::OUString aFile = queryFile( pController->getPrinter().get() ); + if( ! aFile.getLength() ) + { + GDIMetaFile aPageFile; + i_pController->setLastPage( sal_True ); + i_pController->getFilteredPageFile( 0, aPageFile ); + return; + } + pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ), + makeAny( aFile ) ); + } + } + catch( std::bad_alloc& ) + { + } + } + + pController->pushPropertiesToPrinter(); + + rtl::OUString aJobName; + beans::PropertyValue* pJobNameVal = pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "JobName" ) ) ); + if( pJobNameVal ) + pJobNameVal->Value >>= aJobName; + + pController->getPrinter()->StartJob( String( aJobName ), pController ); + + pController->jobFinished( pController->getJobState() ); +} + +bool Printer::StartJob( const rtl::OUString& i_rJobName, boost::shared_ptr<vcl::PrinterController>& i_pController ) +{ + mnError = PRINTER_OK; + + if ( IsDisplayPrinter() ) + return FALSE; + + if ( IsJobActive() || IsPrinting() ) + return FALSE; + + ULONG nCopies = mnCopyCount; + bool bCollateCopy = mbCollateCopy; + bool bUserCopy = FALSE; + + if ( nCopies > 1 ) + { + ULONG nDevCopy; + + if ( bCollateCopy ) + nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES ); + else + nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COPIES ); + + // need to do copies by hand ? + if ( nCopies > nDevCopy ) + { + bUserCopy = TRUE; + nCopies = 1; + bCollateCopy = FALSE; + } + } + else + bCollateCopy = FALSE; + + + ImplSVData* pSVData = ImplGetSVData(); + mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter ); + + if ( !mpPrinter ) + return FALSE; + + // remark: currently it is still possible to use EnablePrintFile and + // SetPrintFileName to redirect printout into file + // it can be argued that those methods should be removed in favor + // of only using the LocalFileName property + beans::PropertyValue* pFileValue = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ) ); + if( pFileValue ) + { + rtl::OUString aFile; + pFileValue->Value >>= aFile; + if( aFile.getLength() ) + { + mbPrintFile = TRUE; + maPrintFile = aFile; + } + } + + XubString* pPrintFile = NULL; + if ( mbPrintFile ) + pPrintFile = &maPrintFile; + + maJobName = i_rJobName; + mnCurPage = 1; + mnCurPrintPage = 1; + mbPrinting = TRUE; + if( ImplGetSVData()->maGDIData.mbPrinterPullModel ) + { + mbJobActive = TRUE; + // sallayer does all necessary page printing + // and also handles showing a dialog + // that also means it must call jobStarted when the dialog is finished + // it also must set the JobState of the Controller + if( mpPrinter->StartJob( pPrintFile, + i_rJobName, + Application::GetDisplayName(), + maJobSetup.ImplGetConstData(), + *i_pController ) ) + { + EndJob(); + } + else + { + mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); + if ( !mnError ) + mnError = PRINTER_GENERALERROR; + pSVData->mpDefInst->DestroyPrinter( mpPrinter ); + mnCurPage = 0; + mnCurPrintPage = 0; + mbPrinting = FALSE; + mpPrinter = NULL; + + return false; + } + } + else + { + // possibly a dialog has been shown + // now the real job starts + i_pController->setJobState( view::PrintableState_JOB_STARTED ); + i_pController->jobStarted(); + + if( mpPrinter->StartJob( pPrintFile, + i_rJobName, + Application::GetDisplayName(), + nCopies, + bCollateCopy, + i_pController->isDirectPrint(), + maJobSetup.ImplGetConstData() ) ) + { + mbJobActive = TRUE; + i_pController->createProgressDialog(); + int nPages = i_pController->getFilteredPageCount(); + int nRepeatCount = bUserCopy ? mnCopyCount : 1; + for( int nIteration = 0; nIteration < nRepeatCount; nIteration++ ) + { + for( int nPage = 0; nPage < nPages; nPage++ ) + { + if( nPage == nPages-1 && nIteration == nRepeatCount-1 ) + i_pController->setLastPage( sal_True ); + i_pController->printFilteredPage( nPage ); + } + // FIXME: duplex ? + } + EndJob(); + + if( i_pController->getJobState() == view::PrintableState_JOB_STARTED ) + i_pController->setJobState( view::PrintableState_JOB_SPOOLED ); + } + else + { + mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); + if ( !mnError ) + mnError = PRINTER_GENERALERROR; + i_pController->setJobState( mnError == PRINTER_ABORT + ? view::PrintableState_JOB_ABORTED + : view::PrintableState_JOB_FAILED ); + pSVData->mpDefInst->DestroyPrinter( mpPrinter ); + mnCurPage = 0; + mnCurPrintPage = 0; + mbPrinting = FALSE; + mpPrinter = NULL; + + return false; + } + } + + return true; +} + +PrinterController::~PrinterController() +{ + delete mpImplData; +} + +view::PrintableState PrinterController::getJobState() const +{ + return mpImplData->meJobState; +} + +void PrinterController::setJobState( view::PrintableState i_eState ) +{ + mpImplData->meJobState = i_eState; +} + +const boost::shared_ptr<Printer>& PrinterController::getPrinter() const +{ + return mpImplData->mpPrinter; +} + +void PrinterController::setPrinter( const boost::shared_ptr<Printer>& i_rPrinter ) +{ + mpImplData->mpPrinter = i_rPrinter; + setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name" ) ), + makeAny( rtl::OUString( i_rPrinter->GetName() ) ) ); +} + +bool PrinterController::setupPrinter( Window* i_pParent ) +{ + bool bRet = false; + if( mpImplData->mpPrinter.get() ) + { + Size aPaperSize( mpImplData->mpPrinter->PixelToLogic( + mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + bRet = mpImplData->mpPrinter->Setup( i_pParent ); + if( bRet ) + { + // was the papersize overridden ? if so we need to take action + Size aNewPaperSize( mpImplData->mpPrinter->PixelToLogic( + mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + if( aNewPaperSize != aPaperSize ) + { + mpImplData->maFixedPageSize = aNewPaperSize; + mpImplData->maPageCache.invalidate(); + awt::Size aOverrideSize; + aOverrideSize.Width = aNewPaperSize.Width(); + aOverrideSize.Height = aNewPaperSize.Height(); + setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OverridePageSize" ) ), + makeAny( aOverrideSize ) ); + } + } + } + return bRet; +} + +PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const Sequence< PropertyValue >& i_rProps ) +{ + PrinterController::PageSize aPageSize; + aPageSize.aSize = mpPrinter->GetPaperSize(); + for( sal_Int32 nProperty = 0, nPropertyCount = i_rProps.getLength(); nProperty < nPropertyCount; ++nProperty ) + { + if( i_rProps[ nProperty ].Name.equalsAscii( "PageSize" ) ) + { + awt::Size aSize; + i_rProps[ nProperty].Value >>= aSize; + aPageSize.aSize.Width() = aSize.Width; + aPageSize.aSize.Height() = aSize.Height; + + Size aCurSize( mpPrinter->GetPaperSize() ); + Size aRealPaperSize( getRealPaperSize( aPageSize.aSize ) ); + if( aRealPaperSize != aCurSize ) + mpPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() ); + } + if( i_rProps[ nProperty ].Name.equalsAscii( "PageIncludesNonprintableArea" ) ) + { + sal_Bool bVal = sal_False; + i_rProps[ nProperty].Value >>= bVal; + aPageSize.bFullPaper = static_cast<bool>(bVal); + } + } + return aPageSize; +} + +int PrinterController::getPageCountProtected() const +{ + const MapMode aMapMode( MAP_100TH_MM ); + + mpImplData->mpPrinter->Push(); + mpImplData->mpPrinter->SetMapMode( aMapMode ); + int nPages = getPageCount(); + mpImplData->mpPrinter->Pop(); + return nPages; +} + +Sequence< beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const +{ + const MapMode aMapMode( MAP_100TH_MM ); + + mpImplData->mpPrinter->Push(); + mpImplData->mpPrinter->SetMapMode( aMapMode ); + Sequence< beans::PropertyValue > aResult( getPageParameters( i_nPage ) ); + mpImplData->mpPrinter->Pop(); + return aResult; +} + +PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache ) +{ + // update progress if necessary + if( mpImplData->mpProgress ) + { + // do nothing if printing is canceled + if( mpImplData->mpProgress->isCanceled() ) + return PrinterController::PageSize(); + mpImplData->mpProgress->tick(); + Application::Reschedule( true ); + } + + if( i_bMayUseCache ) + { + PrinterController::PageSize aPageSize; + if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) ) + { + return aPageSize; + } + } + else + mpImplData->maPageCache.invalidate(); + + o_rMtf.Clear(); + + // get page parameters + Sequence< PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) ); + const MapMode aMapMode( MAP_100TH_MM ); + + mpImplData->mpPrinter->Push(); + mpImplData->mpPrinter->SetMapMode( aMapMode ); + + // modify job setup if necessary + PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm ); + + o_rMtf.SetPrefSize( aPageSize.aSize ); + o_rMtf.SetPrefMapMode( aMapMode ); + + mpImplData->mpPrinter->EnableOutput( FALSE ); + + o_rMtf.Record( mpImplData->mpPrinter.get() ); + + printPage( i_nUnfilteredPage ); + + o_rMtf.Stop(); + o_rMtf.WindStart(); + mpImplData->mpPrinter->Pop(); + + if( i_bMayUseCache ) + mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize ); + + // reset "FirstPage" property to false now we've gotten at least our first one + mpImplData->mbFirstPage = sal_False; + + return aPageSize; +} + +static void appendSubPage( GDIMetaFile& o_rMtf, const Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder ) +{ + // intersect all clipregion actions with our clip rect + io_rSubPage.WindStart(); + io_rSubPage.Clip( i_rClipRect ); + + // save gstate + o_rMtf.AddAction( new MetaPushAction( PUSH_ALL ) ); + + // clip to page rect + o_rMtf.AddAction( new MetaClipRegionAction( Region( i_rClipRect ), TRUE ) ); + + // append the subpage + io_rSubPage.WindStart(); + io_rSubPage.Play( o_rMtf ); + + // restore gstate + o_rMtf.AddAction( new MetaPopAction() ); + + // draw a border + if( i_bDrawBorder ) + { + // save gstate + o_rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_CLIPREGION | PUSH_MAPMODE ) ); + o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) ); + + Rectangle aBorderRect( i_rClipRect ); + o_rMtf.AddAction( new MetaLineColorAction( Color( COL_BLACK ), TRUE ) ); + o_rMtf.AddAction( new MetaFillColorAction( Color( COL_TRANSPARENT ), FALSE ) ); + o_rMtf.AddAction( new MetaRectAction( aBorderRect ) ); + + // restore gstate + o_rMtf.AddAction( new MetaPopAction() ); + } +} + +PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache ) +{ + const MultiPageSetup& rMPS( mpImplData->maMultiPage ); + int nSubPages = rMPS.nRows * rMPS.nColumns; + if( nSubPages < 1 ) + nSubPages = 1; + + // reverse sheet order + if( mpImplData->mbReversePageOrder ) + { + int nDocPages = getFilteredPageCount(); + i_nFilteredPage = nDocPages - 1 - i_nFilteredPage; + } + + // there is no filtering to be done (and possibly the page size of the + // original page is to be set), when N-Up is "neutral" that is there is + // only one subpage and the margins are 0 + if( nSubPages == 1 && + rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 && + rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 ) + { + PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache ); + Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize ); + mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); + mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() ); + if( aPaperSize != aPageSize.aSize ) + { + // user overridden page size, center Metafile + o_rMtf.WindStart(); + long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2; + long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2; + o_rMtf.Move( nDX, nDY ); + o_rMtf.WindStart(); + o_rMtf.SetPrefSize( aPaperSize ); + aPageSize.aSize = aPaperSize; + } + return aPageSize; + } + + // set last page property really only on the very last page to be rendered + // that is on the last subpage of a NUp run + sal_Bool bIsLastPage = mpImplData->mbLastPage; + mpImplData->mbLastPage = sal_False; + + Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize ) ); + + // multi page area: page size minus margins + one time spacing right and down + // the added spacing is so each subpage can be calculated including its spacing + Size aMPArea( aPaperSize ); + aMPArea.Width() -= rMPS.nLeftMargin + rMPS.nRightMargin; + aMPArea.Width() += rMPS.nHorizontalSpacing; + aMPArea.Height() -= rMPS.nTopMargin + rMPS.nBottomMargin; + aMPArea.Height() += rMPS.nVerticalSpacing; + + // determine offsets + long nAdvX = aMPArea.Width() / rMPS.nColumns; + long nAdvY = aMPArea.Height() / rMPS.nRows; + + // determine size of a "cell" subpage, leave a little space around pages + Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing ); + + o_rMtf.Clear(); + o_rMtf.SetPrefSize( aPaperSize ); + o_rMtf.SetPrefMapMode( MapMode( MAP_100TH_MM ) ); + o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) ); + + int nDocPages = getPageCountProtected(); + for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ ) + { + // map current sub page to real page + int nPage = (i_nFilteredPage * nSubPages + nSubPage) / rMPS.nRepeat; + if( nSubPage == nSubPages-1 || + nPage == nDocPages-1 ) + { + mpImplData->mbLastPage = bIsLastPage; + } + if( nPage >= 0 && nPage < nDocPages ) + { + GDIMetaFile aPageFile; + PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache ); + if( aPageSize.aSize.Width() && aPageSize.aSize.Height() ) + { + long nCellX = 0, nCellY = 0; + switch( rMPS.nOrder ) + { + case PrinterController::LRTB: + nCellX = (nSubPage % rMPS.nColumns); + nCellY = (nSubPage / rMPS.nColumns); + break; + case PrinterController::TBLR: + nCellX = (nSubPage / rMPS.nRows); + nCellY = (nSubPage % rMPS.nRows); + break; + } + // scale the metafile down to a sub page size + double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width()); + double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height()); + double fScale = std::min( fScaleX, fScaleY ); + aPageFile.Scale( fScale, fScale ); + aPageFile.WindStart(); + + // move the subpage so it is centered in its "cell" + long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2; + long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2; + long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX; + long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY; + aPageFile.Move( nX, nY ); + aPageFile.WindStart(); + // calculate border rectangle + Rectangle aSubPageRect( Point( nX, nY ), + Size( long(double(aPageSize.aSize.Width())*fScale), + long(double(aPageSize.aSize.Height())*fScale) ) ); + + // append subpage to page + appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder ); + } + } + } + o_rMtf.WindStart(); + + // subsequent getPageFile calls have changed the paper, reset it to current value + mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); + mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() ); + + return PrinterController::PageSize( aPaperSize, true ); +} + +int PrinterController::getFilteredPageCount() +{ + int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns; + if( nDiv < 1 ) + nDiv = 1; + return (getPageCountProtected() * mpImplData->maMultiPage.nRepeat + (nDiv-1)) / nDiv; +} + +ULONG PrinterController::removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut ) +{ + ULONG nRestoreDrawMode = mpImplData->mpPrinter->GetDrawMode(); + sal_Int32 nMaxBmpDPIX = mpImplData->mpPrinter->ImplGetDPIX(); + sal_Int32 nMaxBmpDPIY = mpImplData->mpPrinter->ImplGetDPIY(); + + const PrinterOptions& rPrinterOptions = mpImplData->mpPrinter->GetPrinterOptions(); + + static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300; + static const sal_Int32 NORMAL_BMP_RESOLUTION = 200; + + + if( rPrinterOptions.IsReduceBitmaps() ) + { + // calculate maximum resolution for bitmap graphics + if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() ) + { + nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX ); + nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY ); + } + else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() ) + { + nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX ); + nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY ); + } + else + { + nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX ); + nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY ); + } + } + + // convert to greysacles + if( rPrinterOptions.IsConvertToGreyscales() ) + { + mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | + ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | + DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); + } + + // disable transparency output + if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) ) + { + mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | DRAWMODE_NOTRANSPARENCY ); + } + + Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic + if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 ) + { + // in N-Up printing we have no "page" background operation + // we also have no way to determine the paper color + // so let's go for white, which will kill 99.9% of the real cases + aBg = Color( COL_WHITE ); + } + mpImplData->mpPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY, + rPrinterOptions.IsReduceTransparency(), + rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO, + rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(), + aBg + ); + return nRestoreDrawMode; +} + +void PrinterController::printFilteredPage( int i_nPage ) +{ + if( mpImplData->meJobState != view::PrintableState_JOB_STARTED ) + return; + + GDIMetaFile aPageFile; + PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile ); + + if( mpImplData->mpProgress ) + { + // do nothing if printing is canceled + if( mpImplData->mpProgress->isCanceled() ) + { + setJobState( view::PrintableState_JOB_ABORTED ); + return; + } + } + + // in N-Up printing set the correct page size + mpImplData->mpPrinter->SetMapMode( MAP_100TH_MM ); + // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile() + mpImplData->mpPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() ); + + // if full paper are is meant, move the output to accomodate for pageoffset + if( aPageSize.bFullPaper ) + { + Point aPageOffset( mpImplData->mpPrinter->GetPageOffset() ); + aPageFile.WindStart(); + aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y() ); + } + + GDIMetaFile aCleanedFile; + ULONG nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile ); + + mpImplData->mpPrinter->EnableOutput( TRUE ); + + // actually print the page + mpImplData->mpPrinter->ImplStartPage(); + + mpImplData->mpPrinter->Push(); + aCleanedFile.WindStart(); + aCleanedFile.Play( mpImplData->mpPrinter.get() ); + mpImplData->mpPrinter->Pop(); + + mpImplData->mpPrinter->ImplEndPage(); + + mpImplData->mpPrinter->SetDrawMode( nRestoreDrawMode ); +} + +void PrinterController::jobStarted() +{ +} + +void PrinterController::jobFinished( view::PrintableState ) +{ +} + +void PrinterController::abortJob() +{ + setJobState( view::PrintableState_JOB_ABORTED ); +} + +void PrinterController::setLastPage( sal_Bool i_bLastPage ) +{ + mpImplData->mbLastPage = i_bLastPage; +} + +void PrinterController::setReversePrint( sal_Bool i_bReverse ) +{ + mpImplData->mbReversePageOrder = i_bReverse; +} + +bool PrinterController::getReversePrint() const +{ + return mpImplData->mbReversePageOrder; +} + +Sequence< PropertyValue > PrinterController::getJobProperties( const Sequence< PropertyValue >& i_rMergeList ) const +{ + std::hash_set< rtl::OUString, rtl::OUStringHash > aMergeSet; + size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3; + for( int i = 0; i < i_rMergeList.getLength(); i++ ) + aMergeSet.insert( i_rMergeList[i].Name ); + + Sequence< PropertyValue > aResult( nResultLen ); + for( int i = 0; i < i_rMergeList.getLength(); i++ ) + aResult[i] = i_rMergeList[i]; + int nCur = i_rMergeList.getLength(); + for( size_t i = 0; i < mpImplData->maUIProperties.size(); i++ ) + { + if( aMergeSet.find( mpImplData->maUIProperties[i].Name ) == aMergeSet.end() ) + aResult[nCur++] = mpImplData->maUIProperties[i]; + } + // append IsFirstPage + if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ) ) == aMergeSet.end() ) + { + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ); + aVal.Value <<= mpImplData->mbFirstPage; + aResult[nCur++] = aVal; + } + // append IsLastPage + if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ) ) == aMergeSet.end() ) + { + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ); + aVal.Value <<= mpImplData->mbLastPage; + aResult[nCur++] = aVal; + } + // append IsPrinter + if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ) ) == aMergeSet.end() ) + { + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ); + aVal.Value <<= sal_True; + aResult[nCur++] = aVal; + } + aResult.realloc( nCur ); + return aResult; +} + +const Sequence< beans::PropertyValue >& PrinterController::getUIOptions() const +{ + return mpImplData->maUIOptions; +} + +beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL; +} + +const beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) const +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL; +} + +Sequence< beans::PropertyValue > PrinterController::getValues( const Sequence< rtl::OUString >& i_rNames ) const +{ + Sequence< beans::PropertyValue > aRet( i_rNames.getLength() ); + sal_Int32 nFound = 0; + for( sal_Int32 i = 0; i < i_rNames.getLength(); i++ ) + { + const beans::PropertyValue* pVal = getValue( i_rNames[i] ); + if( pVal ) + aRet[ nFound++ ] = *pVal; + } + aRet.realloc( nFound ); + return aRet; +} + +void PrinterController::setValue( const rtl::OUString& i_rName, const Any& i_rValue ) +{ + beans::PropertyValue aVal; + aVal.Name = i_rName; + aVal.Value = i_rValue; + + setValue( aVal ); +} + +void PrinterController::setValue( const beans::PropertyValue& i_rValue ) +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rValue.Name ); + if( it != mpImplData->maPropertyToIndex.end() ) + mpImplData->maUIProperties[ it->second ] = i_rValue; + else + { + // insert correct index into property map + mpImplData->maPropertyToIndex[ i_rValue.Name ] = mpImplData->maUIProperties.size(); + mpImplData->maUIProperties.push_back( i_rValue ); + mpImplData->maUIPropertyEnabled.push_back( true ); + } +} + +void PrinterController::setUIOptions( const Sequence< beans::PropertyValue >& i_rOptions ) +{ + DBG_ASSERT( mpImplData->maUIOptions.getLength() == 0, "setUIOptions called twice !" ); + + mpImplData->maUIOptions = i_rOptions; + + for( int i = 0; i < i_rOptions.getLength(); i++ ) + { + Sequence< beans::PropertyValue > aOptProp; + i_rOptions[i].Value >>= aOptProp; + bool bIsEnabled = true; + bool bHaveProperty = false; + rtl::OUString aPropName; + vcl::ImplPrinterControllerData::ControlDependency aDep; + for( int n = 0; n < aOptProp.getLength(); n++ ) + { + const beans::PropertyValue& rEntry( aOptProp[ n ] ); + if( rEntry.Name.equalsAscii( "Property" ) ) + { + PropertyValue aVal; + rEntry.Value >>= aVal; + DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name ) + == mpImplData->maPropertyToIndex.end(), "duplicate property entry" ); + setValue( aVal ); + aPropName = aVal.Name; + bHaveProperty = true; + } + else if( rEntry.Name.equalsAscii( "Enabled" ) ) + { + sal_Bool bValue = sal_True; + rEntry.Value >>= bValue; + bIsEnabled = bValue; + } + else if( rEntry.Name.equalsAscii( "DependsOnName" ) ) + { + rEntry.Value >>= aDep.maDependsOnName; + } + else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) ) + { + rEntry.Value >>= aDep.mnDependsOnEntry; + } + } + if( bHaveProperty ) + { + vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it = + mpImplData->maPropertyToIndex.find( aPropName ); + // sanity check + if( it != mpImplData->maPropertyToIndex.end() ) + { + mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled; + } + if( aDep.maDependsOnName.getLength() > 0 ) + mpImplData->maControlDependencies[ aPropName ] = aDep; + } + } +} + +void PrinterController::enableUIOption( const rtl::OUString& i_rProperty, bool i_bEnable ) +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + if( it != mpImplData->maPropertyToIndex.end() ) + { + // call handler only for actual changes + if( ( mpImplData->maUIPropertyEnabled[ it->second ] && ! i_bEnable ) || + ( ! mpImplData->maUIPropertyEnabled[ it->second ] && i_bEnable ) ) + { + mpImplData->maUIPropertyEnabled[ it->second ] = i_bEnable; + rtl::OUString aPropName( i_rProperty ); + mpImplData->maOptionChangeHdl.Call( &aPropName ); + } + } +} + +bool PrinterController::isUIOptionEnabled( const rtl::OUString& i_rProperty ) const +{ + bool bEnabled = false; + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator prop_it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + if( prop_it != mpImplData->maPropertyToIndex.end() ) + { + bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second]; + + if( bEnabled ) + { + // check control dependencies + vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = + mpImplData->maControlDependencies.find( i_rProperty ); + if( it != mpImplData->maControlDependencies.end() ) + { + // check if the dependency is enabled + // if the dependency is disabled, we are too + bEnabled = isUIOptionEnabled( it->second.maDependsOnName ); + + if( bEnabled ) + { + // does the dependency have the correct value ? + const com::sun::star::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName ); + OSL_ENSURE( pVal, "unknown property in dependency" ); + if( pVal ) + { + sal_Int32 nDepVal = 0; + sal_Bool bDepVal = sal_False; + if( pVal->Value >>= nDepVal ) + { + bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1); + } + else if( pVal->Value >>= bDepVal ) + { + // could be a dependency on a checked boolean + // in this case the dependency is on a non zero for checked value + bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) || + ( ! bDepVal && it->second.mnDependsOnEntry == 0); + } + else + { + // if the type does not match something is awry + OSL_ENSURE( 0, "strange type in control dependency" ); + bEnabled = false; + } + } + } + } + } + } + return bEnabled; +} + +rtl::OUString PrinterController::getDependency( const rtl::OUString& i_rProperty ) const +{ + rtl::OUString aDependency; + + vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = + mpImplData->maControlDependencies.find( i_rProperty ); + if( it != mpImplData->maControlDependencies.end() ) + aDependency = it->second.maDependsOnName; + + return aDependency; +} + +rtl::OUString PrinterController::makeEnabled( const rtl::OUString& i_rProperty ) +{ + rtl::OUString aDependency; + + vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = + mpImplData->maControlDependencies.find( i_rProperty ); + if( it != mpImplData->maControlDependencies.end() ) + { + if( isUIOptionEnabled( it->second.maDependsOnName ) ) + { + aDependency = it->second.maDependsOnName; + const com::sun::star::beans::PropertyValue* pVal = getValue( aDependency ); + OSL_ENSURE( pVal, "unknown property in dependency" ); + if( pVal ) + { + sal_Int32 nDepVal = 0; + sal_Bool bDepVal = sal_False; + if( pVal->Value >>= nDepVal ) + { + if( it->second.mnDependsOnEntry != -1 ) + { + setValue( aDependency, makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) ); + } + } + else if( pVal->Value >>= bDepVal ) + { + setValue( aDependency, makeAny( sal_Bool( it->second.mnDependsOnEntry != 0 ) ) ); + } + else + { + // if the type does not match something is awry + OSL_ENSURE( 0, "strange type in control dependency" ); + } + } + } + } + + return aDependency; +} + +void PrinterController::setOptionChangeHdl( const Link& i_rHdl ) +{ + mpImplData->maOptionChangeHdl = i_rHdl; +} + +void PrinterController::createProgressDialog() +{ + if( ! mpImplData->mpProgress ) + { + sal_Bool bShow = sal_True; + beans::PropertyValue* pMonitor = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) ); + if( pMonitor ) + pMonitor->Value >>= bShow; + else + { + const com::sun::star::beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ) ); + if( pVal ) + { + sal_Bool bApi = sal_False; + pVal->Value >>= bApi; + bShow = ! bApi; + } + } + + if( bShow && ! Application::IsHeadlessModeEnabled() ) + { + mpImplData->mpProgress = new PrintProgressDialog( NULL, getPageCountProtected() ); + mpImplData->mpProgress->Show(); + } + } +} + +void PrinterController::setMultipage( const MultiPageSetup& i_rMPS ) +{ + mpImplData->maMultiPage = i_rMPS; +} + +const PrinterController::MultiPageSetup& PrinterController::getMultipage() const +{ + return mpImplData->maMultiPage; +} + +void PrinterController::pushPropertiesToPrinter() +{ + sal_Int32 nCopyCount = 1; + // set copycount and collate + const beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) ); + if( pVal ) + pVal->Value >>= nCopyCount; + sal_Bool bCollate = sal_False; + pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ); + if( pVal ) + pVal->Value >>= bCollate; + mpImplData->mpPrinter->SetCopyCount( static_cast<USHORT>(nCopyCount), bCollate ); + + // duplex mode + pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DuplexMode" ) ) ); + if( pVal ) + { + sal_Int16 nDuplex = view::DuplexMode::UNKNOWN; + pVal->Value >>= nDuplex; + switch( nDuplex ) + { + case view::DuplexMode::OFF: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_OFF ); break; + case view::DuplexMode::LONGEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_LONGEDGE ); break; + case view::DuplexMode::SHORTEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_SHORTEDGE ); break; + } + } +} + +bool PrinterController::isShowDialogs() const +{ + sal_Bool bApi = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ), sal_False ); + return ! bApi && ! Application::IsHeadlessModeEnabled(); +} + +bool PrinterController::isDirectPrint() const +{ + sal_Bool bDirect = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ), sal_False ); + return bDirect == sal_True; +} + +sal_Bool PrinterController::getBoolProperty( const rtl::OUString& i_rProperty, sal_Bool i_bFallback ) const +{ + sal_Bool bRet = i_bFallback; + const com::sun::star::beans::PropertyValue* pVal = getValue( i_rProperty ); + if( pVal ) + pVal->Value >>= bRet; + return bRet; +} + +/* + * PrinterOptionsHelper +**/ +Any PrinterOptionsHelper::getValue( const rtl::OUString& i_rPropertyName ) const +{ + Any aRet; + std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it = + m_aPropertyMap.find( i_rPropertyName ); + if( it != m_aPropertyMap.end() ) + aRet = it->second; + return aRet; +} + +void PrinterOptionsHelper::setValue( const rtl::OUString& i_rPropertyName, const Any& i_rValue ) +{ + m_aPropertyMap[ i_rPropertyName ] = i_rValue; +} + +bool PrinterOptionsHelper::hasProperty( const rtl::OUString& i_rPropertyName ) const +{ + Any aRet; + std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it = + m_aPropertyMap.find( i_rPropertyName ); + return it != m_aPropertyMap.end(); +} + +sal_Bool PrinterOptionsHelper::getBoolValue( const rtl::OUString& i_rPropertyName, sal_Bool i_bDefault ) const +{ + sal_Bool bRet = sal_False; + Any aVal( getValue( i_rPropertyName ) ); + return (aVal >>= bRet) ? bRet : i_bDefault; +} + +sal_Int64 PrinterOptionsHelper::getIntValue( const rtl::OUString& i_rPropertyName, sal_Int64 i_nDefault ) const +{ + sal_Int64 nRet = 0; + Any aVal( getValue( i_rPropertyName ) ); + return (aVal >>= nRet) ? nRet : i_nDefault; +} + +rtl::OUString PrinterOptionsHelper::getStringValue( const rtl::OUString& i_rPropertyName, const rtl::OUString& i_rDefault ) const +{ + rtl::OUString aRet; + Any aVal( getValue( i_rPropertyName ) ); + return (aVal >>= aRet) ? aRet : i_rDefault; +} + +bool PrinterOptionsHelper::processProperties( const Sequence< PropertyValue >& i_rNewProp, + std::set< rtl::OUString >* o_pChangeProp ) +{ + bool bChanged = false; + + // clear the changed set + if( o_pChangeProp ) + o_pChangeProp->clear(); + + sal_Int32 nElements = i_rNewProp.getLength(); + const PropertyValue* pVals = i_rNewProp.getConstArray(); + for( sal_Int32 i = 0; i < nElements; i++ ) + { + bool bElementChanged = false; + std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::iterator it = + m_aPropertyMap.find( pVals[ i ].Name ); + if( it != m_aPropertyMap.end() ) + { + if( it->second != pVals[ i ].Value ) + bElementChanged = true; + } + else + bElementChanged = true; + + if( bElementChanged ) + { + if( o_pChangeProp ) + o_pChangeProp->insert( pVals[ i ].Name ); + m_aPropertyMap[ pVals[i].Name ] = pVals[i].Value; + bChanged = true; + } + } + return bChanged; +} + +void PrinterOptionsHelper::appendPrintUIOptions( uno::Sequence< beans::PropertyValue >& io_rProps ) const +{ + if( m_aUIProperties.getLength() > 0 ) + { + sal_Int32 nIndex = io_rProps.getLength(); + io_rProps.realloc( nIndex+1 ); + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExtraPrintUIOptions" ) ); + aVal.Value = makeAny( m_aUIProperties ); + io_rProps[ nIndex ] = aVal; + } +} + +Any PrinterOptionsHelper::getUIControlOpt( const rtl::OUString& i_rTitle, + const Sequence< rtl::OUString >& i_rHelpTexts, + const rtl::OUString& i_rType, + const PropertyValue* i_pVal, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + sal_Int32 nElements = + 1 // ControlType + + (i_rTitle.getLength() ? 1 : 0) // Text + + (i_rHelpTexts.getLength() ? 1 : 0) // HelpText + + (i_pVal ? 1 : 0) // Property + + i_rControlOptions.maAddProps.getLength() // additional props + + (i_rControlOptions.maGroupHint.getLength() ? 1 : 0) // grouping + + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint + + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled + ; + if( i_rControlOptions.maDependsOnName.getLength() ) + { + nElements += 1; + if( i_rControlOptions.mnDependsOnEntry != -1 ) + nElements += 1; + if( i_rControlOptions.mbAttachToDependency ) + nElements += 1; + } + + Sequence< PropertyValue > aCtrl( nElements ); + sal_Int32 nUsed = 0; + if( i_rTitle.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) ); + aCtrl[nUsed++].Value = makeAny( i_rTitle ); + } + if( i_rHelpTexts.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpText" ) ); + aCtrl[nUsed++].Value = makeAny( i_rHelpTexts ); + } + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlType" ) ); + aCtrl[nUsed++].Value = makeAny( i_rType ); + if( i_pVal ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Property" ) ); + aCtrl[nUsed++].Value = makeAny( *i_pVal ); + } + if( i_rControlOptions.maDependsOnName.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnName" ) ); + aCtrl[nUsed++].Value = makeAny( i_rControlOptions.maDependsOnName ); + if( i_rControlOptions.mnDependsOnEntry != -1 ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnEntry" ) ); + aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mnDependsOnEntry ); + } + if( i_rControlOptions.mbAttachToDependency ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AttachToDependency" ) ); + aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mbAttachToDependency ); + } + } + if( i_rControlOptions.maGroupHint.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GroupingHint" ) ); + aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint; + } + if( i_rControlOptions.mbInternalOnly ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InternalUIOnly" ) ); + aCtrl[nUsed++].Value <<= sal_True; + } + if( ! i_rControlOptions.mbEnabled ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) ); + aCtrl[nUsed++].Value <<= sal_False; + } + + sal_Int32 nAddProps = i_rControlOptions.maAddProps.getLength(); + for( sal_Int32 i = 0; i < nAddProps; i++ ) + aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i]; + + DBG_ASSERT( nUsed == nElements, "nUsed != nElements, probable heap corruption" ); + + return makeAny( aCtrl ); +} + +Any PrinterOptionsHelper::getGroupControlOpt( const rtl::OUString& i_rTitle, const rtl::OUString& i_rHelpText ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Group" ) ) ); +} + +Any PrinterOptionsHelper::getSubgroupControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Subgroup" ) ), + NULL, i_rControlOptions ); +} + +Any PrinterOptionsHelper::getBoolControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + sal_Bool i_bValue, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_bValue ); + return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Bool" ) ), &aVal, i_rControlOptions ); +} + +Any PrinterOptionsHelper::getChoiceControlOpt( const rtl::OUString& i_rTitle, + const Sequence< rtl::OUString >& i_rHelpText, + const rtl::OUString& i_rProperty, + const Sequence< rtl::OUString >& i_rChoices, + sal_Int32 i_nValue, + const rtl::OUString& i_rType, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + UIControlOptions aOpt( i_rControlOptions ); + sal_Int32 nUsed = aOpt.maAddProps.getLength(); + aOpt.maAddProps.realloc( nUsed + 1 ); + aOpt.maAddProps[nUsed].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Choices" ) ); + aOpt.maAddProps[nUsed].Value = makeAny( i_rChoices ); + + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_nValue ); + return getUIControlOpt( i_rTitle, i_rHelpText, i_rType, &aVal, aOpt ); +} + +Any PrinterOptionsHelper::getRangeControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + sal_Int32 i_nValue, + sal_Int32 i_nMinValue, + sal_Int32 i_nMaxValue, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + UIControlOptions aOpt( i_rControlOptions ); + if( i_nMaxValue >= i_nMinValue ) + { + sal_Int32 nUsed = aOpt.maAddProps.getLength(); + aOpt.maAddProps.realloc( nUsed + 2 ); + aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MinValue" ) ); + aOpt.maAddProps[nUsed++].Value = makeAny( i_nMinValue ); + aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxValue" ) ); + aOpt.maAddProps[nUsed++].Value = makeAny( i_nMaxValue ); + } + + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_nValue ); + return getUIControlOpt( i_rTitle, + aHelpText, + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Range" ) ), + &aVal, + aOpt + ); +} + +Any PrinterOptionsHelper::getEditControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + const rtl::OUString& i_rValue, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_rValue ); + return getUIControlOpt( i_rTitle, + aHelpText, + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Edit" ) ), + &aVal, + i_rControlOptions + ); +} diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx index f1c532a9295f..a13e272e368b 100644 --- a/vcl/source/gdi/virdev.cxx +++ b/vcl/source/gdi/virdev.cxx @@ -359,27 +359,40 @@ BOOL VirtualDevice::SetOutputSizePixel( const Size& rNewSize, BOOL bErase ) // ----------------------------------------------------------------------- -void VirtualDevice::SetReferenceDevice( RefDevMode eRefDevMode ) +void VirtualDevice::SetReferenceDevice( RefDevMode i_eRefDevMode ) { - switch( eRefDevMode ) + sal_Int32 nDPIX = 600, nDPIY = 600; + switch( i_eRefDevMode ) { case REFDEV_NONE: default: DBG_ASSERT( FALSE, "VDev::SetRefDev illegal argument!" ); - // fall through + break; case REFDEV_MODE06: - mnDPIX = mnDPIY = 600; + nDPIX = nDPIY = 600; break; case REFDEV_MODE48: - mnDPIX = mnDPIY = 4800; + nDPIX = nDPIY = 4800; break; case REFDEV_MODE_MSO1: - mnDPIX = mnDPIY = 6*1440; + nDPIX = nDPIY = 6*1440; break; case REFDEV_MODE_PDF1: - mnDPIX = mnDPIY = 720; + nDPIX = nDPIY = 720; break; } + ImplSetReferenceDevice( i_eRefDevMode, nDPIX, nDPIY ); +} + +void VirtualDevice::SetReferenceDevice( sal_Int32 i_nDPIX, sal_Int32 i_nDPIY ) +{ + ImplSetReferenceDevice( REFDEV_CUSTOM, i_nDPIX, i_nDPIY ); +} + +void VirtualDevice::ImplSetReferenceDevice( RefDevMode i_eRefDevMode, sal_Int32 i_nDPIX, sal_Int32 i_nDPIY ) +{ + mnDPIX = i_nDPIX; + mnDPIY = i_nDPIY; EnableOutput( FALSE ); // prevent output on reference device mbScreenComp = FALSE; @@ -391,7 +404,7 @@ void VirtualDevice::SetReferenceDevice( RefDevMode eRefDevMode ) // avoid adjusting font lists when already in refdev mode BYTE nOldRefDevMode = meRefDevMode; BYTE nOldCompatFlag = (BYTE)meRefDevMode & REFDEV_FORCE_ZERO_EXTLEAD; - meRefDevMode = (BYTE)(eRefDevMode | nOldCompatFlag); + meRefDevMode = (BYTE)(i_eRefDevMode | nOldCompatFlag); if( (nOldRefDevMode ^ nOldCompatFlag) != REFDEV_NONE ) return; diff --git a/vcl/source/src/images.src b/vcl/source/src/images.src index a2b057c8d234..5a0e7b412a58 100644 --- a/vcl/source/src/images.src +++ b/vcl/source/src/images.src @@ -833,3 +833,23 @@ Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_PRINTERADMIN) File = "printeradmin_16_h.png" ; }; +Bitmap SV_DISCLOSURE_PLUS +{ + File = "plus.png"; +}; + +Bitmap SV_DISCLOSURE_PLUS_HC +{ + File = "plus_sch.png"; +}; + +Bitmap SV_DISCLOSURE_MINUS +{ + File = "minus.png"; +}; + +Bitmap SV_DISCLOSURE_MINUS_HC +{ + File = "minus_sch.png"; +}; + diff --git a/vcl/source/src/makefile.mk b/vcl/source/src/makefile.mk index cf01c74b977d..7772af5a0978 100644 --- a/vcl/source/src/makefile.mk +++ b/vcl/source/src/makefile.mk @@ -8,7 +8,7 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.8 $ +# $Revision: 1.8.114.1 $ # # This file is part of OpenOffice.org. # @@ -47,7 +47,8 @@ SRC1FILES= images.src \ stdtext.src \ helptext.src \ units.src \ - btntext.src + btntext.src \ + print.src RESLIB1NAME= $(RESTARGET) RESLIB1IMAGES= $(PRJ)$/source/src diff --git a/vcl/source/src/print.src b/vcl/source/src/print.src new file mode 100644 index 000000000000..0125c0dfbeb3 --- /dev/null +++ b/vcl/source/src/print.src @@ -0,0 +1,495 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: print.src,v $ + * $Revision: 1.1.2.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "vcl/svids.hrc" + +ModalDialog SV_DLG_PRINT +{ + Text [en-US] = "Print"; + Closeable = TRUE; + Sizeable = TRUE; + Moveable = TRUE; + Maxable = TRUE; + SVLook = TRUE; + + Size = MAP_APPFONT( 350, 215 ); + + OKButton SV_PRINT_OK + { + DefButton = TRUE; + Pos = MAP_APPFONT( 240, 195 ); + Size = MAP_APPFONT( 50, 15 ); + Text [en-US] = "~Print"; + }; + CancelButton SV_PRINT_CANCEL + { + Pos = MAP_APPFONT( 295, 195 ); + Size = MAP_APPFONT( 50, 15 ); + }; + HelpButton SV_PRINT_HELP + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 50, 15 ); + }; + + Window SV_PRINT_PAGE_PREVIEW + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 130, 130 ); + Border = FALSE; + }; + NumericField SV_PRINT_PAGE_EDIT + { + Pos = MAP_APPFONT( 5, 140 ); + Size = MAP_APPFONT( 30, 12 ); + SVLook = TRUE; + Spin = FALSE; + Border = TRUE; + HelpText [en-US] = "Select page to display in preview."; + }; + FixedText SV_PRINT_PAGE_TXT + { + Pos = MAP_APPFONT( 40,142 ); + Size = MAP_APPFONT( 30, 12 ); + Text [ en-US ] = "/ %n"; + VCenter = TRUE; + }; + PushButton SV_PRINT_PAGE_FORWARD + { + Pos = MAP_APPFONT( 95, 140 ); + Size = MAP_APPFONT( 15, 12 ); + HelpText [en-US] = "Scroll one page forward."; + }; + PushButton SV_PRINT_PAGE_BACKWARD + { + Pos = MAP_APPFONT( 80, 140 ); + Size = MAP_APPFONT( 15, 12 ); + HelpText [en-US] = "Scroll one page backward."; + }; + TabControl SV_PRINT_TABCTRL + { + Pos = MAP_APPFONT( 140, 5 ); + Size = MAP_APPFONT( 205, 175 ); + }; + FixedLine SV_PRINT_BUTTONLINE + { + Pos = MAP_APPFONT( 0, 185 ); + Size = MAP_APPFONT( 350, 8 ); + }; + String SV_PRINT_NOPAGES + { + Text [en-US] = "No pages"; + }; + + String SV_PRINT_TOFILE_TXT + { + Text [en-US] = "Print to File..."; + }; + + String SV_PRINT_DEFPRT_TXT + { + Text [en-US] = "Default printer"; + }; + + + String SV_PRINT_PRINTPREVIEW_TXT + { + Text [en-US] = "Print preview"; + }; + + TabPage SV_PRINT_TAB_NUP + { + Text [en-US] = "Page Layout"; + Hide = TRUE; + + FixedLine SV_PRINT_PRT_NUP_LAYOUT_FL + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 150, 10 ); + Text [en-US] = "Layout"; + }; + RadioButton SV_PRINT_PRT_NUP_DEFAULT_BTN + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 10 ); + Text [en-US] = "~Default"; + HelpText [en-US] = "Print one page per sheet of paper."; + }; + RadioButton SV_PRINT_PRT_NUP_BROCHURE_BTN + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 10 ); + Text = ""; + }; + RadioButton SV_PRINT_PRT_NUP_PAGES_BTN + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 10 ); + Text [en-US] = "Pa~ges per sheet"; + HelpText [en-US] = "Print multiple pages per sheet of paper."; + }; + ListBox SV_PRINT_PRT_NUP_PAGES_BOX + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 80 ); + Border = TRUE; + DropDown = TRUE; + CurPos = 0; + HelpText [en-US] = "Select how many pages to print per sheet of paper."; + StringList [en-US] = + { + < "1"; 1; >; + < "2"; 2; >; + < "4"; 4; >; + < "6"; 6; >; + < "9"; 9; >; + < "16"; 16; >; + < "Custom"; 0xffff; >; + }; + }; + FixedText SV_PRINT_PRT_NUP_NUM_PAGES_TXT + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 10 ); + Text [en-US] = "P~ages"; + VCenter = TRUE; + }; + NumericField SV_PRINT_PRT_NUP_COLS_EDT + { + Pos = MAP_APPFONT( 55, 20 ); + Size = MAP_APPFONT( 40, 12 ); + Border = TRUE; + Spin = TRUE; + Minimum = 1; + Maximum = 32; + Value = 1; + HelpText [en-US] = "Select number of columns."; + }; + FixedText SV_PRINT_PRT_NUP_TIMES_TXT + { + Pos = MAP_APPFONT( 10, 35 ); + Size = MAP_APPFONT( 40, 10 ); + Text [en-US] = "b~y"; + VCenter = TRUE; + }; + NumericField SV_PRINT_PRT_NUP_ROWS_EDT + { + Pos = MAP_APPFONT( 55, 35 ); + Size = MAP_APPFONT( 40, 12 ); + Border = TRUE; + Spin = TRUE; + Minimum = 1; + Maximum = 32; + Value = 1; + HelpText [en-US] = "Select number of rows."; + }; + FixedText SV_PRINT_PRT_NUP_MARGINS_PAGES_1_TXT + { + Pos = MAP_APPFONT( 10, 95 ); + Size = MAP_APPFONT( 40, 10 ); + Text [en-US] = "~Distance"; + }; + MetricField SV_PRINT_PRT_NUP_MARGINS_PAGES_EDT + { + Pos = MAP_APPFONT( 55, 95 ); + Size = MAP_APPFONT( 40, 12 ); + Spin = TRUE; + Border = TRUE; + Value = 0; + Unit = FUNIT_MM; + HelpText [en-US] = "Select margin between individual pages on each sheet of paper."; + }; + FixedText SV_PRINT_PRT_NUP_MARGINS_PAGES_2_TXT + { + Pos = MAP_APPFONT( 10, 95 ); + Size = MAP_APPFONT( 40, 10 ); + Text [en-US] = "between pages"; + }; + FixedText SV_PRINT_PRT_NUP_MARGINS_SHEET_1_TXT + { + Pos = MAP_APPFONT( 110, 95 ); + Size = MAP_APPFONT( 40, 10 ); + Text [en-US] = "~Margin"; + }; + MetricField SV_PRINT_PRT_NUP_MARGINS_SHEET_EDT + { + Pos = MAP_APPFONT( 155, 95 ); + Size = MAP_APPFONT( 40, 12 ); + Spin = TRUE; + Border = TRUE; + Value = 0; + Unit = FUNIT_MM; + HelpText [en-US] = "Select margin between the printed pages and paper edge."; + }; + FixedText SV_PRINT_PRT_NUP_MARGINS_SHEET_2_TXT + { + Pos = MAP_APPFONT( 110, 95 ); + Size = MAP_APPFONT( 40, 10 ); + Text [en-US] = "to sheet border"; + }; + FixedText SV_PRINT_PRT_NUP_ORIENTATION_TXT + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 10 ); + Text [en-US] = "~Orientation"; + }; + ListBox SV_PRINT_PRT_NUP_ORIENTATION_BOX + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 40 ); + Border = TRUE; + DropDown = TRUE; + CurPos = 0; + StringList [en-US] = + { + < "Automatic"; SV_PRINT_PRT_NUP_ORIENTATION_AUTOMATIC; >; + < "Portrait"; SV_PRINT_PRT_NUP_ORIENTATION_PORTRAIT; >; + < "Landscape"; SV_PRINT_PRT_NUP_ORIENTATION_LANDSCAPE; >; + }; + HelpText [en-US] = "Select the orientation of the paper."; + }; + FixedText SV_PRINT_PRT_NUP_ORDER_TXT + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 10 ); + Text [en-US] = "Order"; + }; + ListBox SV_PRINT_PRT_NUP_ORDER_BOX + { + Pos = MAP_APPFONT( 0, 0 ); + Size = MAP_APPFONT( 10, 20 ); + DropDown = TRUE; + Border = TRUE; + CurPos = 0; + StringList [en-US] = + { + < "left to right, then down"; SV_PRINT_PRT_NUP_ORDER_LRTD; >; + < "top to bottom, then right"; SV_PRINT_PRT_NUP_ORDER_TDLR; >; + }; + HelpText [en-US] = "Select order in which pages are to be printed."; + }; + CheckBox SV_PRINT_PRT_NUP_BORDER_CB + { + Pos = MAP_APPFONT( 10, 65 ); + Size = MAP_APPFONT( 150, 12 ); + Text [en-US] = "Draw a border around each page"; + HelpText [en-US] = "Check to draw a border around each page."; + }; + }; + + TabPage SV_PRINT_TAB_JOB + { + Text [en-US] = "General"; + Hide = TRUE; + + FixedLine SV_PRINT_PRINTERS_FL + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 100, 10 ); + Text [ en-US ] = "Prin~ter"; + }; + ListBox SV_PRINT_PRINTERS + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 100, 80 ); + Border = TRUE; + Sort = TRUE; + HelpText [en-US] = "Select the printer to print on."; + }; + CheckBox SV_PRINT_DETAILS_BTN + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 5, 5 ); + Text [en-US] = "Details"; + HelpText [en-US] = "Show/Hide detailed information of the selected printer."; + }; + FixedText SV_PRINT_STATUS_TXT + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 100, 10 ); + Text [en-US] = "Status:"; + }; + FixedText SV_PRINT_LOCATION_TXT + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 100, 10 ); + Text [en-US] = "Location:"; + }; + FixedText SV_PRINT_COMMENT_TXT + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 100, 10 ); + Text [en-US] = "Comment:"; + }; + PushButton SV_PRINT_PRT_SETUP + { + Pos = MAP_APPFONT( 115, 5 ); + Size = MAP_APPFONT( 50, 15 ); + Text [en-US] = "Properties..."; + HelpText [en-US] = "Call the setup dialog of the selected printer."; + }; + FixedLine SV_PRINT_COPIES + { + Pos = MAP_APPFONT( 5, 35 ); + Size = MAP_APPFONT( 150, 10 ); + Text [en-US] = "Range and Copies"; + }; + FixedText SV_PRINT_COPYCOUNT + { + Pos = MAP_APPFONT( 10, 45 ); + Size = MAP_APPFONT( 80, 10 ); + Text [en-US] = "Number of copies"; + }; + NumericField SV_PRINT_COPYCOUNT_FIELD + { + Pos = MAP_APPFONT( 10, 56 ); + Size = MAP_APPFONT( 40, 12 ); + Border = TRUE; + Spin = TRUE; + Minimum = 1; + Maximum = 16384; + Value = 1; + HelpText [en-US] = "Select the number of copies to be produced."; + }; + FixedImage SV_PRINT_COLLATE_IMAGE + { + Pos = MAP_APPFONT( 95, 60 ); + Size = MAP_PIXEL( 80, 30 ); + }; + CheckBox SV_PRINT_COLLATE + { + Pos = MAP_APPFONT( 95, 45 ); + Size = MAP_APPFONT( 70, 10 ); + Text [en-US] = "Collate"; + HelpText [en-US] = "Select whether copies should be collated or not."; + }; + + Image SV_PRINT_COLLATE_IMG + { + ImageBitmap = Bitmap { File = "collate.png" ; }; + }; + + Image SV_PRINT_NOCOLLATE_IMG + { + ImageBitmap = Bitmap { File = "ncollate.png" ; }; + }; + + Image SV_PRINT_COLLATE_HC_IMG + { + ImageBitmap = Bitmap { File = "collate_h.png" ; }; + }; + + Image SV_PRINT_NOCOLLATE_HC_IMG + { + ImageBitmap = Bitmap { File = "ncollate_h.png" ; }; + }; + }; + + TabPage SV_PRINT_TAB_OPT + { + Text [en-US] = "Options"; + Hide = TRUE; + + FixedLine SV_PRINT_OPT_PRINT_FL + { + Pos = MAP_APPFONT( 5, 5 ); + Size = MAP_APPFONT( 150, 10 ); + Text [en-US] = "Options"; + }; + CheckBox SV_PRINT_OPT_TOFILE + { + Pos = MAP_APPFONT( 10, 20 ); + Size = MAP_APPFONT( 200, 12 ); + Text [en-US] = "Print to ~file"; + HelpText [en-US] = "Check to send output to a file instead of the actual printer."; + }; + CheckBox SV_PRINT_OPT_SINGLEJOBS + { + Pos = MAP_APPFONT( 10, 35 ); + Size = MAP_APPFONT( 200, 12 ); + Text [en-US] = "~Create single print jobs for collated output"; + HelpText [en-US] = "Check to not rely on the printer to create collated copies but create a print job for each copy instead."; + }; + CheckBox SV_PRINT_OPT_REVERSE + { + Pos = MAP_APPFONT( 10, 50 ); + Size = MAP_APPFONT( 200, 12 ); + Text [en-US] = "Print in ~reverse page order"; + HelpText [en-US] = "Check to print pages in reverse order."; + }; + }; +}; + +ModelessDialog SV_DLG_PRINT_PROGRESS +{ + Text [en-US] = "Printing"; + Closeable = FALSE; + Sizeable = FALSE; + Moveable = TRUE; + SVLook = TRUE; + + Size = MAP_APPFONT( 120, 70 ); + + CancelButton SV_PRINT_PROGRESS_CANCEL + { + Pos = MAP_APPFONT( 35, 50 ); + Size = MAP_APPFONT( 50, 15 ); + }; + FixedText SV_PRINT_PROGRESS_TEXT + { + Pos = MAP_APPFONT( 5,10 ); + Size = MAP_APPFONT( 110, 10 ); + Text [ en-US ] = "Page %p of %n"; + Center = TRUE; + }; +}; + +ErrorBox SV_PRINT_NOPRINTERWARNING +{ + Title = "%PRODUCTNAME"; + Message [en-US] = "No default printer found.\nPlease choose a printer and try again."; +}; + +ErrorBox SV_PRINT_NOCONTENT +{ + Title = "%PRODUCTNAME"; + Message [en-US] = "There are no pages to be printed. Please check your document for ranges relevant to printing."; +}; + +StringArray SV_PRINT_NATIVE_STRINGS +{ + ItemList [en-US] = + { + < "Preview"; >; + < "Page number"; >; + < "Number of pages"; >; + < "More"; >; + }; +}; diff --git a/vcl/source/src/stdtext.src b/vcl/source/src/stdtext.src index 5ad1cdceeb61..d4dca4915b6b 100644 --- a/vcl/source/src/stdtext.src +++ b/vcl/source/src/stdtext.src @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: stdtext.src,v $ - * $Revision: 1.53 $ + * $Revision: 1.53.84.1 $ * * This file is part of OpenOffice.org. * @@ -123,3 +123,8 @@ String SV_MAC_SCREENNNAME { Text [en-US] = "Screen %d"; }; + +String SV_STDTEXT_ALLFILETYPES +{ + Text [en-US] = "Any type"; +}; diff --git a/vcl/source/window/arrange.cxx b/vcl/source/window/arrange.cxx new file mode 100644 index 000000000000..0199af7ed50d --- /dev/null +++ b/vcl/source/window/arrange.cxx @@ -0,0 +1,906 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: accel.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/arrange.hxx" +#include "vcl/edit.hxx" + +#include "osl/diagnose.h" + +using namespace vcl; + +// ---------------------------------------- +// vcl::WindowArranger +//----------------------------------------- + +WindowArranger::~WindowArranger() +{} + +void WindowArranger::setParent( WindowArranger* i_pParent ) +{ + OSL_VERIFY( i_pParent->m_pParentWindow == m_pParentWindow || m_pParentWindow == NULL ); + + m_pParentArranger = i_pParent; + m_pParentWindow = i_pParent->m_pParentWindow; + setParentWindow( m_pParentWindow ); +} + +void WindowArranger::setParentWindow( Window* i_pNewParent ) +{ + m_pParentWindow = i_pNewParent; + + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = getElement( i ); + if( pEle ) // sanity check + { + #if OSL_DEBUG_LEVEL > 0 + if( pEle->m_pElement ) + { + OSL_VERIFY( pEle->m_pElement->GetParent() == i_pNewParent ); + } + #endif + if( pEle->m_pChild ) + pEle->m_pChild->setParentWindow( i_pNewParent ); + } + } +} + +void WindowArranger::show( bool i_bShow, bool i_bImmediateUpdate ) +{ + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = getElement( i ); + if( pEle ) // sanity check + { + pEle->m_bHidden = ! i_bShow; + if( pEle->m_pElement ) + pEle->m_pElement->Show( i_bShow ); + if( pEle->m_pChild.get() ) + pEle->m_pChild->show( i_bShow, false ); + } + } + if( m_pParentArranger ) + { + nEle = m_pParentArranger->countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = m_pParentArranger->getElement( i ); + if( pEle && pEle->m_pChild.get() == this ) + { + pEle->m_bHidden = ! i_bShow; + break; + } + } + } + if( i_bImmediateUpdate ) + { + // find the topmost parent + WindowArranger* pResize = this; + while( pResize->m_pParentArranger ) + pResize = pResize->m_pParentArranger; + pResize->resize(); + } +} + +bool WindowArranger::isVisible() const +{ + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + const Element* pEle = getConstElement( i ); + if( pEle->isVisible() ) + return true; + } + return false; +} + +bool WindowArranger::Element::isVisible() const +{ + bool bVisible = false; + if( ! m_bHidden ) + { + if( m_pElement ) + bVisible = m_pElement->IsVisible(); + else if( m_pChild ) + bVisible = m_pChild->isVisible(); + } + return bVisible; +} + +sal_Int32 WindowArranger::Element::getExpandPriority() const +{ + sal_Int32 nPrio = m_nExpandPriority; + if( m_pChild && m_nExpandPriority >= 0 ) + { + size_t nElements = m_pChild->countElements(); + for( size_t i = 0; i < nElements; i++ ) + { + sal_Int32 nCPrio = m_pChild->getExpandPriority( i ); + if( nCPrio > nPrio ) + nPrio = nCPrio; + } + } + return nPrio; +} + +Size WindowArranger::Element::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aResult; + if( ! m_bHidden ) + { + if( m_pElement && m_pElement->IsVisible() ) + aResult = m_pElement->GetOptimalSize( i_eType ); + else if( m_pChild ) + aResult = m_pChild->getOptimalSize( i_eType ); + if( aResult.Width() < m_aMinSize.Width() ) + aResult.Width() = m_aMinSize.Width(); + if( aResult.Height() < m_aMinSize.Height() ) + aResult.Height() = m_aMinSize.Height(); + aResult.Width() += m_nLeftBorder + m_nRightBorder; + aResult.Height() += m_nTopBorder + m_nBottomBorder; + } + + return aResult; +} + +void WindowArranger::Element::setPosSize( const Point& i_rPos, const Size& i_rSize ) +{ + Point aPoint( i_rPos ); + Size aSize( i_rSize ); + aPoint.X() += m_nLeftBorder; + aPoint.Y() += m_nTopBorder; + aSize.Width() -= m_nLeftBorder + m_nRightBorder; + aSize.Height() -= m_nTopBorder + m_nBottomBorder; + if( m_pElement ) + m_pElement->SetPosSizePixel( aPoint, aSize ); + else if( m_pChild ) + m_pChild->setManagedArea( Rectangle( aPoint, aSize ) ); +} + +// ---------------------------------------- +// vcl::RowOrColumn +//----------------------------------------- + +RowOrColumn::~RowOrColumn() +{ + for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + it->deleteChild(); + } +} + +Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aRet( 0, 0 ); + for( std::vector< WindowArranger::Element >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->isVisible() ) + { + // get the size of type of the managed element + Size aElementSize( it->getOptimalSize( i_eType ) ); + if( m_bColumn ) + { + // add the distance between elements + aRet.Height() += m_nBorderWidth; + // check if the width needs adjustment + if( aRet.Width() < aElementSize.Width() ) + aRet.Width() = aElementSize.Width(); + aRet.Height() += aElementSize.Height(); + } + else + { + // add the distance between elements + aRet.Width() += m_nBorderWidth; + // check if the height needs adjustment + if( aRet.Height() < aElementSize.Height() ) + aRet.Height() = aElementSize.Height(); + aRet.Width() += aElementSize.Width(); + } + } + } + + if( aRet.Width() != 0 || aRet.Height() != 0 ) + { + // subtract the border for the first element + if( m_bColumn ) + aRet.Height() -= m_nBorderWidth; + else + aRet.Width() -= m_nBorderWidth; + + // add the outer border + aRet.Width() += 2*m_nOuterBorder; + aRet.Height() += 2*m_nOuterBorder; + } + + return aRet; +} + +void RowOrColumn::distributeRowWidth( std::vector<Size>& io_rSizes, long /*i_nUsedWidth*/, long i_nExtraWidth ) +{ + if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() ) + { + // find all elements with the highest expand priority + size_t nElements = m_aElements.size(); + std::vector< size_t > aIndices; + sal_Int32 nHighPrio = 0; + for( size_t i = 0; i < nElements; i++ ) + { + if( m_aElements[ i ].isVisible() ) + { + sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority(); + if( nCurPrio > nHighPrio ) + { + aIndices.clear(); + nHighPrio = nCurPrio; + } + if( nCurPrio == nHighPrio ) + aIndices.push_back( i ); + } + } + + // distribute extra space evenly among collected elements + nElements = aIndices.size(); + if( nElements > 0 ) + { + long nDelta = i_nExtraWidth / nElements; + for( size_t i = 0; i < nElements; i++ ) + { + io_rSizes[ aIndices[i] ].Width() += nDelta; + i_nExtraWidth -= nDelta; + } + // add the last pixels to the last row element + if( i_nExtraWidth > 0 && nElements > 0 ) + io_rSizes[aIndices.back()].Width() += i_nExtraWidth; + } + } +} + +void RowOrColumn::distributeColumnHeight( std::vector<Size>& io_rSizes, long /*i_nUsedHeight*/, long i_nExtraHeight ) +{ + if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() ) + { + // find all elements with the highest expand priority + size_t nElements = m_aElements.size(); + std::vector< size_t > aIndices; + sal_Int32 nHighPrio = 3; + for( size_t i = 0; i < nElements; i++ ) + { + if( m_aElements[ i ].isVisible() ) + { + sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority(); + if( nCurPrio > nHighPrio ) + { + aIndices.clear(); + nHighPrio = nCurPrio; + } + if( nCurPrio == nHighPrio ) + aIndices.push_back( i ); + } + } + + // distribute extra space evenly among collected elements + nElements = aIndices.size(); + if( nElements > 0 ) + { + long nDelta = i_nExtraHeight / nElements; + for( size_t i = 0; i < nElements; i++ ) + { + io_rSizes[ aIndices[i] ].Height() += nDelta; + i_nExtraHeight -= nDelta; + } + // add the last pixels to the last row element + if( i_nExtraHeight > 0 && nElements > 0 ) + io_rSizes[aIndices.back()].Height() += i_nExtraHeight; + } + } +} + +void RowOrColumn::resize() +{ + // check if we can get optimal size, else fallback to minimal size + Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED ) ); + WindowSizeType eType = WINDOWSIZE_PREFERRED; + if( m_bColumn ) + { + if( aOptSize.Height() > m_aManagedArea.GetHeight() ) + eType = WINDOWSIZE_MINIMUM; + } + else + { + if( aOptSize.Width() > m_aManagedArea.GetWidth() ) + eType = WINDOWSIZE_MINIMUM; + } + + size_t nElements = m_aElements.size(); + // get all element sizes for sizing + std::vector<Size> aElementSizes( nElements ); + long nUsedWidth = 2*m_nOuterBorder - (nElements ? m_nBorderWidth : 0); + for( size_t i = 0; i < nElements; i++ ) + { + if( m_aElements[i].isVisible() ) + { + aElementSizes[i] = m_aElements[i].getOptimalSize( eType ); + if( m_bColumn ) + { + aElementSizes[i].Width() = m_aManagedArea.GetWidth() - 2* m_nOuterBorder; + nUsedWidth += aElementSizes[i].Height() + m_nBorderWidth; + } + else + { + aElementSizes[i].Height() = m_aManagedArea.GetHeight() - 2* m_nOuterBorder; + nUsedWidth += aElementSizes[i].Width() + m_nBorderWidth; + } + } + } + + long nExtraWidth = (m_bColumn ? m_aManagedArea.GetHeight() : m_aManagedArea.GetWidth()) - nUsedWidth; + if( nExtraWidth > 0 ) + { + if( m_bColumn ) + distributeColumnHeight( aElementSizes, nUsedWidth, nExtraWidth ); + else + distributeRowWidth( aElementSizes, nUsedWidth, nExtraWidth ); + } + + // get starting position + Point aElementPos( m_aManagedArea.TopLeft() ); + // outer border + aElementPos.X() += m_nOuterBorder; + aElementPos.Y() += m_nOuterBorder; + + // position managed windows + for( size_t i = 0; i < nElements; i++ ) + { + // get the size of type of the managed element + if( m_aElements[i].isVisible() ) + { + m_aElements[i].setPosSize( aElementPos, aElementSizes[i] ); + if( m_bColumn ) + aElementPos.Y() += m_nBorderWidth + aElementSizes[i].Height(); + else + aElementPos.X() += m_nBorderWidth + aElementSizes[i].Width(); + } + } +} + +size_t RowOrColumn::addWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio, size_t i_nIndex ) +{ + size_t nIndex = i_nIndex; + if( i_nIndex >= m_aElements.size() ) + { + nIndex = m_aElements.size(); + m_aElements.push_back( WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) ); + } + else + { + std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + while( i_nIndex-- ) + ++it; + m_aElements.insert( it, WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) ); + } + return nIndex; +} + +size_t RowOrColumn::addChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio, size_t i_nIndex ) +{ + size_t nIndex = i_nIndex; + if( i_nIndex >= m_aElements.size() ) + { + nIndex = m_aElements.size(); + m_aElements.push_back( WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) ); + } + else + { + std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + while( i_nIndex-- ) + ++it; + m_aElements.insert( it, WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) ); + } + return nIndex; +} + +void RowOrColumn::remove( Window* i_pWindow ) +{ + if( i_pWindow ) + { + for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pElement == i_pWindow ) + { + m_aElements.erase( it ); + return; + } + } + } +} + +void RowOrColumn::remove( boost::shared_ptr<WindowArranger> const & i_pChild ) +{ + if( i_pChild ) + { + for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pChild == i_pChild ) + { + m_aElements.erase( it ); + return; + } + } + } +} + +// ---------------------------------------- +// vcl::LabeledElement +//----------------------------------------- + +LabeledElement::~LabeledElement() +{ + m_aLabel.deleteChild(); + m_aElement.deleteChild(); +} + +Size LabeledElement::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aRet( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) ); + if( aRet.Width() != 0 ) + { + if( m_nLabelColumnWidth != 0 ) + aRet.Width() = m_nLabelColumnWidth; + else + aRet.Width() += m_nDistance; + } + Size aElementSize( m_aElement.getOptimalSize( i_eType ) ); + aRet.Width() += aElementSize.Width(); + if( aElementSize.Height() > aRet.Height() ) + aRet.Height() = aElementSize.Height(); + if( aRet.Height() != 0 ) + aRet.Height() += 2*m_nOuterBorder; + + return aRet; +} + +void LabeledElement::resize() +{ + Size aLabelSize( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) ); + Size aElementSize( m_aElement.getOptimalSize( WINDOWSIZE_PREFERRED ) ); + if( m_nDistance + aLabelSize.Width() + aElementSize.Width() > m_aManagedArea.GetWidth() ) + aElementSize = m_aElement.getOptimalSize( WINDOWSIZE_MINIMUM ); + + // align label and element vertically in LabeledElement + long nYOff = (m_aManagedArea.GetHeight() - 2*m_nOuterBorder - aLabelSize.Height()) / 2; + Point aPos( m_aManagedArea.Left(), + m_aManagedArea.Top() + m_nOuterBorder + nYOff ); + Size aSize( aLabelSize ); + if( m_nLabelColumnWidth != 0 ) + aSize.Width() = m_nLabelColumnWidth; + m_aLabel.setPosSize( aPos, aSize ); + + aPos.X() += aSize.Width() + m_nDistance; + nYOff = (m_aManagedArea.GetHeight() - 2*m_nOuterBorder - aElementSize.Height()) / 2; + aPos.Y() = m_aManagedArea.Top() + m_nOuterBorder + nYOff; + aSize.Width() = aElementSize.Width(); + aSize.Height() = m_aManagedArea.GetHeight() - 2*m_nOuterBorder; + + // label style + // 0: position left and right + // 1: keep the element close to label and grow it + // 2: keep the element close and don't grow it + if( m_nLabelStyle == 0) + { + if( aPos.X() + aSize.Width() < m_aManagedArea.Right() ) + aPos.X() = m_aManagedArea.Right() - aSize.Width(); + } + else if( m_nLabelStyle == 1 ) + { + if( aPos.X() + aSize.Width() < m_aManagedArea.Right() ) + aSize.Width() = m_aManagedArea.Right() - aPos.X(); + } + m_aElement.setPosSize( aPos, aSize ); +} + +void LabeledElement::setLabel( Window* i_pLabel ) +{ + m_aLabel.m_pElement = i_pLabel; + m_aLabel.m_pChild.reset(); +} + +void LabeledElement::setLabel( boost::shared_ptr<WindowArranger> const & i_pLabel ) +{ + m_aLabel.m_pElement = NULL; + m_aLabel.m_pChild = i_pLabel; +} + +void LabeledElement::setElement( Window* i_pElement ) +{ + m_aElement.m_pElement = i_pElement; + m_aElement.m_pChild.reset(); +} + +void LabeledElement::setElement( boost::shared_ptr<WindowArranger> const & i_pElement ) +{ + m_aElement.m_pElement = NULL; + m_aElement.m_pChild = i_pElement; +} + +// ---------------------------------------- +// vcl::LabelColumn +//----------------------------------------- +LabelColumn::~LabelColumn() +{ +} + +long LabelColumn::getLabelWidth() const +{ + long nWidth = 0; + + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + const Element* pEle = getConstElement( i ); + if( pEle && pEle->m_pChild.get() ) + { + const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get()); + if( pLabel ) + { + Window* pLW = pLabel->getWindow( 0 ); + if( pLW ) + { + Size aLabSize( pLW->GetOptimalSize( WINDOWSIZE_MINIMUM ) ); + if( aLabSize.Width() > nWidth ) + nWidth = aLabSize.Width(); + } + } + } + } + return nWidth + getBorderWidth(); +} + +Size LabelColumn::getOptimalSize( WindowSizeType i_eType ) const +{ + long nWidth = getLabelWidth(); + Size aColumnSize; + + // every child is a LabeledElement + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Size aElementSize; + const Element* pEle = getConstElement( i ); + if( pEle && pEle->m_pChild.get() ) + { + const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get()); + if( pLabel ) // we have a label + { + aElementSize = pLabel->getLabelSize( WINDOWSIZE_MINIMUM ); + if( aElementSize.Width() ) + aElementSize.Width() = nWidth; + Size aSize( pLabel->getElementSize( i_eType ) ); + aElementSize.Width() += aSize.Width(); + if( aSize.Height() > aElementSize.Height() ) + aElementSize.Height() = aSize.Height(); + } + else // a non label, just treat it as a row + { + aElementSize = pEle->getOptimalSize( i_eType ); + } + } + else if( pEle && pEle->m_pElement ) // a general window, treat is as a row + { + aElementSize = pEle->getOptimalSize( i_eType ); + } + if( aElementSize.Width() ) + { + aElementSize.Width() += 2*m_nOuterBorder; + if( aElementSize.Width() > aColumnSize.Width() ) + aColumnSize.Width() = aElementSize.Width(); + } + if( aElementSize.Height() ) + { + aColumnSize.Height() += getBorderWidth() + aElementSize.Height(); + } + } + if( nEle > 0 && aColumnSize.Height() ) + { + aColumnSize.Height() -= getBorderWidth(); // for the first element + aColumnSize.Height() += 2*m_nOuterBorder; + } + return aColumnSize; +} + +void LabelColumn::resize() +{ + long nWidth = getLabelWidth(); + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = getElement( i ); + if( pEle && pEle->m_pChild.get() ) + { + LabeledElement* pLabel = dynamic_cast< LabeledElement* >(pEle->m_pChild.get()); + if( pLabel ) + pLabel->setLabelColumnWidth( nWidth ); + } + } + RowOrColumn::resize(); +} + +size_t LabelColumn::addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent ) +{ + boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) ); + xLabel->setLabel( i_pLabel ); + xLabel->setBorders( 0, i_nIndent, 0, 0, 0 ); + xLabel->setElement( i_rElement ); + size_t nIndex = addChild( xLabel ); + resize(); + return nIndex; +} + +size_t LabelColumn::addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent ) +{ + boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) ); + xLabel->setLabel( i_pLabel ); + xLabel->setBorders( 0, i_nIndent, 0, 0, 0 ); + xLabel->setElement( i_pElement ); + size_t nIndex = addChild( xLabel ); + resize(); + return nIndex; +} + +// ---------------------------------------- +// vcl::Indenter +//----------------------------------------- + +Indenter::~Indenter() +{ + m_aElement.deleteChild(); +} + +Size Indenter::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aSize( m_aElement.getOptimalSize( i_eType ) ); + aSize.Width() += 2*m_nOuterBorder + m_nIndent; + aSize.Height() += 2*m_nOuterBorder; + return aSize; +} + +void Indenter::resize() +{ + Point aPt( m_aManagedArea.TopLeft() ); + aPt.X() += m_nOuterBorder + m_nIndent; + aPt.Y() += m_nOuterBorder; + Size aSz( m_aManagedArea.GetSize() ); + aSz.Width() -= 2*m_nOuterBorder + m_nIndent; + aSz.Height() -= 2*m_nOuterBorder; + m_aElement.setPosSize( aPt, aSz ); +} + +void Indenter::setWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio ) +{ + OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0) || i_pWindow == 0 ); + OSL_VERIFY( i_pWindow == 0 || i_pWindow->GetParent() == m_pParentWindow ); + m_aElement.m_pElement = i_pWindow; + m_aElement.m_nExpandPriority = i_nExpandPrio; +} + +void Indenter::setChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio ) +{ + OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0 ) || i_pChild == 0 ); + m_aElement.m_pChild = i_pChild; + m_aElement.m_nExpandPriority = i_nExpandPrio; +} + +// ---------------------------------------- +// vcl::MatrixArranger +//----------------------------------------- +MatrixArranger::~MatrixArranger() +{ +} + +Size MatrixArranger::getOptimalSize( WindowSizeType i_eType, std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights ) const +{ + Size aMatrixSize( 2*m_nOuterBorder, 2*m_nOuterBorder ); + + // first find out the current number of rows and columns + sal_uInt32 nRows = 0, nColumns = 0; + for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_nX >= nColumns ) + nColumns = it->m_nX+1; + if( it->m_nY >= nRows ) + nRows = it->m_nY+1; + } + + // now allocate row and column depth vectors + o_rColumnWidths = std::vector< long >( nColumns, 0 ); + o_rRowHeights = std::vector< long >( nRows, 0 ); + + // get sizes an allocate them into rows/columns + for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + Size aSize( it->getOptimalSize( i_eType ) ); + if( aSize.Width() > o_rColumnWidths[ it->m_nX ] ) + o_rColumnWidths[ it->m_nX ] = aSize.Width(); + if( aSize.Height() > o_rRowHeights[ it->m_nY ] ) + o_rRowHeights[ it->m_nY ] = aSize.Height(); + } + + // add up sizes + for( sal_uInt32 i = 0; i < nColumns; i++ ) + aMatrixSize.Width() += o_rColumnWidths[i] + m_nBorderX; + if( nColumns > 0 ) + aMatrixSize.Width() -= m_nBorderX; + + for( sal_uInt32 i = 0; i < nRows; i++ ) + aMatrixSize.Height() += o_rRowHeights[i] + m_nBorderY; + if( nRows > 0 ) + aMatrixSize.Height() -= m_nBorderY; + + return aMatrixSize; +} + +Size MatrixArranger::getOptimalSize( WindowSizeType i_eType ) const +{ + std::vector<long> aColumnWidths, aRowHeights; + return getOptimalSize( i_eType, aColumnWidths, aRowHeights ); +} + +void MatrixArranger::resize() +{ + // assure that we have at least one row and column + if( m_aElements.empty() ) + return; + + // check if we can get optimal size, else fallback to minimal size + std::vector<long> aColumnWidths, aRowHeights; + Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED, aColumnWidths, aRowHeights ) ); + if( aOptSize.Height() > m_aManagedArea.GetHeight() || + aOptSize.Width() > m_aManagedArea.GetWidth() ) + { + std::vector<long> aMinColumnWidths, aMinRowHeights; + getOptimalSize( WINDOWSIZE_MINIMUM, aMinColumnWidths, aMinRowHeights ); + if( aOptSize.Height() > m_aManagedArea.GetHeight() ) + aRowHeights = aMinRowHeights; + if( aOptSize.Width() > m_aManagedArea.GetWidth() ) + aColumnWidths = aMinColumnWidths; + } + + // FIXME: distribute extra space available + + // prepare offsets + std::vector<long> aColumnX( aColumnWidths.size() ); + aColumnX[0] = m_aManagedArea.Left() + m_nOuterBorder; + for( size_t i = 1; i < aColumnX.size(); i++ ) + aColumnX[i] = aColumnX[i-1] + aColumnWidths[i-1] + m_nBorderX; + + std::vector<long> aRowY( aRowHeights.size() ); + aRowY[0] = m_aManagedArea.Top() + m_nOuterBorder; + for( size_t i = 1; i < aRowY.size(); i++ ) + aRowY[i] = aRowY[i-1] + aRowHeights[i-1] + m_nBorderY; + + // now iterate over the elements and assign their positions + for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + Point aCellPos( aColumnX[it->m_nX], aRowY[it->m_nY] ); + Size aCellSize( aColumnWidths[it->m_nX], aRowHeights[it->m_nY] ); + it->setPosSize( aCellPos, aCellSize ); + } +} + +size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio ) +{ + sal_uInt64 nMapValue = getMap( i_nX, i_nY ); + std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue ); + size_t nIndex = 0; + if( it == m_aMatrixMap.end() ) + { + m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size(); + m_aElements.push_back( MatrixElement( i_pWindow, i_nX, i_nY, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) ); + } + else + { + MatrixElement& rEle( m_aElements[ it->second ] ); + rEle.m_pElement = i_pWindow; + rEle.m_pChild.reset(); + rEle.m_nExpandPriority = i_nExpandPrio; + rEle.m_nX = i_nX; + rEle.m_nY = i_nY; + nIndex = it->second; + } + return nIndex; +} + +void MatrixArranger::remove( Window* i_pWindow ) +{ + if( i_pWindow ) + { + for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pElement == i_pWindow ) + { + m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) ); + m_aElements.erase( it ); + return; + } + } + } +} + +size_t MatrixArranger::addChild( boost::shared_ptr<WindowArranger> const &i_pChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio ) +{ + sal_uInt64 nMapValue = getMap( i_nX, i_nY ); + std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue ); + size_t nIndex = 0; + if( it == m_aMatrixMap.end() ) + { + m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size(); + m_aElements.push_back( MatrixElement( NULL, i_nX, i_nY, i_pChild, i_nExpandPrio ) ); + } + else + { + MatrixElement& rEle( m_aElements[ it->second ] ); + rEle.m_pElement = 0; + rEle.m_pChild = i_pChild; + rEle.m_nExpandPriority = i_nExpandPrio; + rEle.m_nX = i_nX; + rEle.m_nY = i_nY; + nIndex = it->second; + } + return nIndex; +} + +void MatrixArranger::remove( boost::shared_ptr<WindowArranger> const &i_pChild ) +{ + if( i_pChild ) + { + for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pChild == i_pChild ) + { + m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) ); + m_aElements.erase( it ); + return; + } + } + } +} + diff --git a/vcl/source/window/makefile.mk b/vcl/source/window/makefile.mk index 169cf44b2b13..21b8efe4c586 100644 --- a/vcl/source/window/makefile.mk +++ b/vcl/source/window/makefile.mk @@ -8,7 +8,7 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.25 $ +# $Revision: 1.25.114.1 $ # # This file is part of OpenOffice.org. # @@ -45,6 +45,7 @@ ENABLE_EXCEPTIONS=TRUE # --- Files -------------------------------------------------------- SLOFILES= \ + $(SLO)$/arrange.obj \ $(SLO)$/abstdlg.obj \ $(SLO)$/accel.obj \ $(SLO)$/accmgr.obj \ @@ -70,6 +71,7 @@ SLOFILES= \ $(SLO)$/mnemonicengine.obj \ $(SLO)$/msgbox.obj \ $(SLO)$/scrwnd.obj \ + $(SLO)$/printdlg.obj \ $(SLO)$/seleng.obj \ $(SLO)$/split.obj \ $(SLO)$/splitwin.obj \ diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx new file mode 100644 index 000000000000..649ca21a32b8 --- /dev/null +++ b/vcl/source/window/printdlg.cxx @@ -0,0 +1,2489 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: printdlg.cxx,v $ + * $Revision: 1.1.2.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/print.hxx" +#include "vcl/prndlg.hxx" +#include "vcl/dialog.hxx" +#include "vcl/button.hxx" +#include "vcl/svdata.hxx" +#include "vcl/svids.hrc" +#include "vcl/wall.hxx" +#include "vcl/jobset.h" +#include "vcl/status.hxx" +#include "vcl/decoview.hxx" +#include "vcl/arrange.hxx" +#include "vcl/configsettings.hxx" +#include "vcl/help.hxx" +#include "vcl/decoview.hxx" +#include "vcl/svapp.hxx" + +#include "unotools/localedatawrapper.hxx" + +#include "rtl/ustrbuf.hxx" + +#include "com/sun/star/awt/Size.hpp" + +using namespace vcl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; + +#define HELPID_PREFIX ".HelpId:vcl:PrintDialog" +#define SMHID2( a, b ) SetSmartHelpId( SmartId( String( RTL_CONSTASCII_USTRINGPARAM( HELPID_PREFIX ":" a ":" b ) ), HID_PRINTDLG ) ) +#define SMHID1( a ) SetSmartHelpId( SmartId( String( RTL_CONSTASCII_USTRINGPARAM( HELPID_PREFIX ":" a ) ), HID_PRINTDLG ) ) + +PrintDialog::PrintPreviewWindow::PrintPreviewWindow( Window* i_pParent, const ResId& i_rId ) + : Window( i_pParent, i_rId ) + , maOrigSize( 10, 10 ) + , maPageVDev( *this ) + , maToolTipString( String( VclResId( SV_PRINT_PRINTPREVIEW_TXT ) ) ) +{ + SetPaintTransparent( TRUE ); + SetBackground(); + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) + maPageVDev.SetBackground( GetSettings().GetStyleSettings().GetWindowColor() ); + else + maPageVDev.SetBackground( Color( COL_WHITE ) ); +} + +PrintDialog::PrintPreviewWindow::~PrintPreviewWindow() +{ +} + +void PrintDialog::PrintPreviewWindow::DataChanged( const DataChangedEvent& i_rDCEvt ) +{ + // react on settings changed + if( i_rDCEvt.GetType() == DATACHANGED_SETTINGS ) + { + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) + maPageVDev.SetBackground( GetSettings().GetStyleSettings().GetWindowColor() ); + else + maPageVDev.SetBackground( Color( COL_WHITE ) ); + } + Window::DataChanged( i_rDCEvt ); +} + +void PrintDialog::PrintPreviewWindow::Resize() +{ + Size aNewSize( GetSizePixel() ); + // leave small space for decoration + aNewSize.Width() -= 2; + aNewSize.Height() -= 2; + Size aScaledSize; + double fScale = 1.0; + + // #i106435# catch corner case of Size(0,0) + Size aOrigSize( maOrigSize ); + if( aOrigSize.Width() < 1 ) + aOrigSize.Width() = aNewSize.Width(); + if( aOrigSize.Height() < 1 ) + aOrigSize.Height() = aNewSize.Height(); + if( aOrigSize.Width() > aOrigSize.Height() ) + { + aScaledSize = Size( aNewSize.Width(), aNewSize.Width() * aOrigSize.Height() / aOrigSize.Width() ); + if( aScaledSize.Height() > aNewSize.Height() ) + fScale = double(aNewSize.Height())/double(aScaledSize.Height()); + } + else + { + aScaledSize = Size( aNewSize.Height() * aOrigSize.Width() / aOrigSize.Height(), aNewSize.Height() ); + if( aScaledSize.Width() > aNewSize.Width() ) + fScale = double(aNewSize.Width())/double(aScaledSize.Width()); + } + aScaledSize.Width() = long(aScaledSize.Width()*fScale); + aScaledSize.Height() = long(aScaledSize.Height()*fScale); + maPageVDev.SetOutputSizePixel( aScaledSize, FALSE ); +} + +void PrintDialog::PrintPreviewWindow::Paint( const Rectangle& ) +{ + Size aSize( GetSizePixel() ); + if( maReplacementString.getLength() != 0 ) + { + // replacement is active + Push(); + Rectangle aTextRect( Point( 0, 0 ), aSize ); + Font aFont( GetSettings().GetStyleSettings().GetFieldFont() ); + aFont.SetSize( Size( 0, aSize.Height()/12 ) ); + SetFont( aFont ); + DrawText( aTextRect, maReplacementString, + TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE + ); + Pop(); + } + else + { + GDIMetaFile aMtf( maMtf ); + + Size aPreviewSize = maPageVDev.GetOutputSizePixel(); + Point aOffset( (aSize.Width() - aPreviewSize.Width()) / 2, + (aSize.Height() - aPreviewSize.Height()) / 2 ); + + const Size aLogicSize( maPageVDev.PixelToLogic( aPreviewSize, MapMode( MAP_100TH_MM ) ) ); + Size aOrigSize( maOrigSize ); + if( aOrigSize.Width() < 1 ) + aOrigSize.Width() = aLogicSize.Width(); + if( aOrigSize.Height() < 1 ) + aOrigSize.Height() = aLogicSize.Height(); + double fScale = double(aLogicSize.Width())/double(aOrigSize.Width()); + + + maPageVDev.Erase(); + maPageVDev.Push(); + maPageVDev.SetMapMode( MAP_100TH_MM ); + aMtf.WindStart(); + aMtf.Scale( fScale, fScale ); + aMtf.WindStart(); + aMtf.Play( &maPageVDev, Point( 0, 0 ), aLogicSize ); + maPageVDev.Pop(); + + SetMapMode( MAP_PIXEL ); + maPageVDev.SetMapMode( MAP_PIXEL ); + DrawOutDev( aOffset, aPreviewSize, Point( 0, 0 ), aPreviewSize, maPageVDev ); + + DecorationView aVw( this ); + aOffset.X() -= 1; aOffset.Y() -=1; aPreviewSize.Width() += 2; aPreviewSize.Height() += 2; + aVw.DrawFrame( Rectangle( aOffset, aPreviewSize ), FRAME_DRAW_GROUP ); + } +} + +void PrintDialog::PrintPreviewWindow::Command( const CommandEvent& rEvt ) +{ + if( rEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pWheelData = rEvt.GetWheelData(); + PrintDialog* pDlg = dynamic_cast<PrintDialog*>(GetParent()); + if( pDlg ) + { + if( pWheelData->GetDelta() > 0 ) + pDlg->previewForward(); + else if( pWheelData->GetDelta() < 0 ) + pDlg->previewBackward(); + /* + else + huh ? + */ + } + } +} + +void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile& i_rNewPreview, + const Size& i_rOrigSize, + const rtl::OUString& i_rReplacement, + sal_Int32 i_nDPIX, + sal_Int32 i_nDPIY + ) +{ + rtl::OUStringBuffer aBuf( 256 ); + aBuf.append( maToolTipString ); + #if OSL_DEBUG_LEVEL > 0 + aBuf.appendAscii( "\n---\nPageSize: " ); + aBuf.append( sal_Int32( i_rOrigSize.Width()/100) ); + aBuf.appendAscii( "mm x " ); + aBuf.append( sal_Int32( i_rOrigSize.Height()/100) ); + aBuf.appendAscii( "mm" ); + #endif + SetQuickHelpText( aBuf.makeStringAndClear() ); + maMtf = i_rNewPreview; + if( GetSettings().GetStyleSettings().GetHighContrastMode() && + GetSettings().GetStyleSettings().GetWindowColor().IsDark() + ) + { + maMtf.ReplaceColors( Color( COL_BLACK ), Color( COL_WHITE ), 30 ); + } + + maOrigSize = i_rOrigSize; + maReplacementString = i_rReplacement; + maPageVDev.SetReferenceDevice( i_nDPIX, i_nDPIY ); + maPageVDev.EnableOutput( TRUE ); + Resize(); + Invalidate(); +} + +PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow( Window* i_pParent ) + : Window( i_pParent, WB_NOBORDER ) + , mnOrderMode( 0 ) + , mnRows( 1 ) + , mnColumns( 1 ) +{ + ImplInitSettings(); +} + +PrintDialog::ShowNupOrderWindow::~ShowNupOrderWindow() +{ +} + +void PrintDialog::ShowNupOrderWindow::ImplInitSettings() +{ + SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) ); +} + +void PrintDialog::ShowNupOrderWindow::Paint( const Rectangle& i_rRect ) +{ + Window::Paint( i_rRect ); + SetMapMode( MAP_PIXEL ); + SetTextColor( GetSettings().GetStyleSettings().GetFieldTextColor() ); + + int nPages = mnRows * mnColumns; + Font aFont( GetSettings().GetStyleSettings().GetFieldFont() ); + aFont.SetSize( Size( 0, 24 ) ); + SetFont( aFont ); + Size aSampleTextSize( GetTextWidth( rtl::OUString::valueOf( sal_Int32(nPages+1) ) ), GetTextHeight() ); + + Size aOutSize( GetOutputSizePixel() ); + Size aSubSize( aOutSize.Width() / mnColumns, aOutSize.Height() / mnRows ); + // calculate font size: shrink the sample text so it fits + double fX = double(aSubSize.Width())/double(aSampleTextSize.Width()); + double fY = double(aSubSize.Height())/double(aSampleTextSize.Height()); + double fScale = (fX < fY) ? fX : fY; + long nFontHeight = long(24.0*fScale) - 3; + if( nFontHeight < 5 ) + nFontHeight = 5; + aFont.SetSize( Size( 0, nFontHeight ) ); + SetFont( aFont ); + long nTextHeight = GetTextHeight(); + for( int i = 0; i < nPages; i++ ) + { + rtl::OUString aPageText( rtl::OUString::valueOf( sal_Int32(i+1) ) ); + int nX = 0, nY = 0; + switch( mnOrderMode ) + { + case SV_PRINT_PRT_NUP_ORDER_LRTD: + nX = (i % mnColumns); nY = (i / mnColumns); + break; + case SV_PRINT_PRT_NUP_ORDER_TDLR: + nX = (i / mnRows); nY = (i % mnRows); + break; + } + Size aTextSize( GetTextWidth( aPageText ), nTextHeight ); + int nDeltaX = (aSubSize.Width() - aTextSize.Width()) / 2; + int nDeltaY = (aSubSize.Height() - aTextSize.Height()) / 2; + DrawText( Point( nX * aSubSize.Width() + nDeltaX, + nY * aSubSize.Height() + nDeltaY ), + aPageText ); + } + DecorationView aVw( this ); + aVw.DrawFrame( Rectangle( Point( 0, 0), aOutSize ), FRAME_DRAW_GROUP ); +} + +PrintDialog::NUpTabPage::NUpTabPage( Window* i_pParent, const ResId& rResId ) + : TabPage( i_pParent, rResId ) + , maNupLine( this, VclResId( SV_PRINT_PRT_NUP_LAYOUT_FL ) ) + , maPagesBtn( this, VclResId( SV_PRINT_PRT_NUP_PAGES_BTN ) ) + , maBrochureBtn( this, VclResId( SV_PRINT_PRT_NUP_BROCHURE_BTN ) ) + , maPagesBoxTitleTxt( this, 0 ) + , maNupPagesBox( this, VclResId( SV_PRINT_PRT_NUP_PAGES_BOX ) ) + , maNupNumPagesTxt( this, VclResId( SV_PRINT_PRT_NUP_NUM_PAGES_TXT ) ) + , maNupColEdt( this, VclResId( SV_PRINT_PRT_NUP_COLS_EDT ) ) + , maNupTimesTxt( this, VclResId( SV_PRINT_PRT_NUP_TIMES_TXT ) ) + , maNupRowsEdt( this, VclResId( SV_PRINT_PRT_NUP_ROWS_EDT ) ) + , maPageMarginTxt1( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_1_TXT ) ) + , maPageMarginEdt( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_EDT ) ) + , maPageMarginTxt2( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_2_TXT ) ) + , maSheetMarginTxt1( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_1_TXT ) ) + , maSheetMarginEdt( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_EDT ) ) + , maSheetMarginTxt2( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_2_TXT ) ) + , maNupOrientationTxt( this, VclResId( SV_PRINT_PRT_NUP_ORIENTATION_TXT ) ) + , maNupOrientationBox( this, VclResId( SV_PRINT_PRT_NUP_ORIENTATION_BOX ) ) + , maNupOrderTxt( this, VclResId( SV_PRINT_PRT_NUP_ORDER_TXT ) ) + , maNupOrderBox( this, VclResId( SV_PRINT_PRT_NUP_ORDER_BOX ) ) + , maNupOrderWin( this ) + , maBorderCB( this, VclResId( SV_PRINT_PRT_NUP_BORDER_CB ) ) +{ + FreeResource(); + + maNupOrderWin.Show(); + maPagesBtn.Check( TRUE ); + maBrochureBtn.Show( FALSE ); + + // setup field units for metric fields + const LocaleDataWrapper& rLocWrap( maPageMarginEdt.GetLocaleDataWrapper() ); + FieldUnit eUnit = FUNIT_MM; + USHORT nDigits = 0; + if( rLocWrap.getMeasurementSystemEnum() == MEASURE_US ) + { + eUnit = FUNIT_INCH; + nDigits = 2; + } + // set units + maPageMarginEdt.SetUnit( eUnit ); + maSheetMarginEdt.SetUnit( eUnit ); + + // set precision + maPageMarginEdt.SetDecimalDigits( nDigits ); + maSheetMarginEdt.SetDecimalDigits( nDigits ); + + SMHID1( "NUpPage" ); + maNupLine.SMHID2("NUpPage", "Layout"); + maBrochureBtn.SMHID2("NUpPage", "Brochure" ); + maPagesBtn.SMHID2( "NUpPage", "PagesPerSheet" ); + maPagesBoxTitleTxt.SMHID2( "NUpPage", "PagesPerSheetLabel" ); + maNupPagesBox.SMHID2( "NUpPage", "PagesPerSheetBox" ); + maNupNumPagesTxt.SMHID2( "NUpPage", "Columns" ); + maNupColEdt.SMHID2( "NUpPage", "ColumnsBox" ); + maNupTimesTxt.SMHID2( "NUpPage", "Rows" ); + maNupRowsEdt.SMHID2( "NUpPage", "RowsBox" ); + maPageMarginTxt1.SMHID2( "NUpPage", "PageMargin" ); + maPageMarginEdt.SMHID2( "NUpPage", "PageMarginBox" ); + maPageMarginTxt2.SMHID2( "NUpPage", "PageMarginCont" ); + maSheetMarginTxt1.SMHID2( "NUpPage", "SheetMargin" ); + maSheetMarginEdt.SMHID2( "NUpPage", "SheetMarginBox" ); + maSheetMarginTxt2.SMHID2( "NUpPage", "SheetMarginCont" ); + maNupOrientationTxt.SMHID2( "NUpPage", "Orientation" ); + maNupOrientationBox.SMHID2( "NUpPage", "OrientationBox" ); + maNupOrderTxt.SMHID2( "NUpPage", "Order" ); + maNupOrderBox.SMHID2( "NUpPage", "OrderBox" ); + maBorderCB.SMHID2( "NUpPage", "BorderBox" ); + + setupLayout(); +} + +PrintDialog::NUpTabPage::~NUpTabPage() +{ +} + +void PrintDialog::NUpTabPage::enableNupControls( bool bEnable ) +{ + maNupPagesBox.Enable( TRUE ); + maNupNumPagesTxt.Enable( bEnable ); + maNupColEdt.Enable( bEnable ); + maNupTimesTxt.Enable( bEnable ); + maNupRowsEdt.Enable( bEnable ); + maPageMarginTxt1.Enable( bEnable ); + maPageMarginEdt.Enable( bEnable ); + maPageMarginTxt2.Enable( bEnable ); + maSheetMarginTxt1.Enable( bEnable ); + maSheetMarginEdt.Enable( bEnable ); + maSheetMarginTxt2.Enable( bEnable ); + maNupOrientationTxt.Enable( bEnable ); + maNupOrientationBox.Enable( bEnable ); + maNupOrderTxt.Enable( bEnable ); + maNupOrderBox.Enable( bEnable ); + maNupOrderWin.Enable( bEnable ); + maBorderCB.Enable( bEnable ); +} + +void PrintDialog::NUpTabPage::showAdvancedControls( bool i_bShow ) +{ + maNupNumPagesTxt.Show( i_bShow ); + maNupColEdt.Show( i_bShow ); + maNupTimesTxt.Show( i_bShow ); + maNupRowsEdt.Show( i_bShow ); + maPageMarginTxt1.Show( i_bShow ); + maPageMarginEdt.Show( i_bShow ); + maPageMarginTxt2.Show( i_bShow ); + maSheetMarginTxt1.Show( i_bShow ); + maSheetMarginEdt.Show( i_bShow ); + maSheetMarginTxt2.Show( i_bShow ); + maNupOrientationTxt.Show( i_bShow ); + maNupOrientationBox.Show( i_bShow ); + maLayout.resize(); +} + +void PrintDialog::NUpTabPage::setupLayout() +{ + Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); + long nIndent = 3*aBorder.Width(); + + maLayout.setParentWindow( this ); + maLayout.setOuterBorder( aBorder.Width() ); + + maLayout.addWindow( &maNupLine ); + boost::shared_ptr< vcl::RowOrColumn > xRow( new vcl::RowOrColumn( &maLayout, false ) ); + maLayout.addChild( xRow ); + boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( xRow.get() ) ); + xRow->addChild( xIndent ); + + boost::shared_ptr< vcl::RowOrColumn > xShowNupCol( new vcl::RowOrColumn( xRow.get() ) ); + xRow->addChild( xShowNupCol, -1 ); + xShowNupCol->setMinimumSize( xShowNupCol->addWindow( &maNupOrderWin ), Size( 70, 70 ) ); + boost::shared_ptr< vcl::Spacer > xSpacer( new vcl::Spacer( xShowNupCol.get() ) ); + xShowNupCol->addChild( xSpacer ); + + boost::shared_ptr< vcl::LabelColumn > xMainCol( new vcl::LabelColumn( xIndent.get() ) ); + xIndent->setChild( xMainCol ); + + size_t nPagesIndex = xMainCol->addRow( &maPagesBtn, &maNupPagesBox ); + mxPagesBtnLabel = boost::dynamic_pointer_cast<vcl::LabeledElement>( xMainCol->getChild( nPagesIndex ) ); + + xRow.reset( new vcl::RowOrColumn( xMainCol.get(), false ) ); + xMainCol->addRow( &maNupNumPagesTxt, xRow, nIndent ); + xRow->addWindow( &maNupColEdt ); + xRow->addWindow( &maNupTimesTxt ); + xRow->addWindow( &maNupRowsEdt ); + + boost::shared_ptr< vcl::LabeledElement > xLab( new vcl::LabeledElement( xMainCol.get(), 2 ) ); + xLab->setLabel( &maPageMarginEdt ); + xLab->setElement( &maPageMarginTxt2 ); + xMainCol->addRow( &maPageMarginTxt1, xLab, nIndent ); + + xLab.reset( new vcl::LabeledElement( xMainCol.get(), 2 ) ); + xLab->setLabel( &maSheetMarginEdt ); + xLab->setElement( &maSheetMarginTxt2 ); + xMainCol->addRow( &maSheetMarginTxt1, xLab, nIndent ); + + xMainCol->addRow( &maNupOrientationTxt, &maNupOrientationBox, nIndent ); + xMainCol->addRow( &maNupOrderTxt, &maNupOrderBox, nIndent ); + xMainCol->setBorders( xMainCol->addWindow( &maBorderCB ), nIndent, 0, 0, 0 ); + + xSpacer.reset( new vcl::Spacer( xMainCol.get(), 0, Size( 10, aBorder.Width() ) ) ); + xMainCol->addChild( xSpacer ); + + xRow.reset( new vcl::RowOrColumn( xMainCol.get(), false ) ); + xMainCol->addRow( &maBrochureBtn, xRow ); + // remember brochure row for dependencies + mxBrochureDep = xRow; + + // initially advanced controls are not shown, rows=columns=1 + showAdvancedControls( false ); +} + +void PrintDialog::NUpTabPage::Resize() +{ + maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetOutputSizePixel() ) ); +} + +void PrintDialog::NUpTabPage::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& i_rMPS ) +{ + maSheetMarginEdt.SetValue( maSheetMarginEdt.Normalize( i_rMPS.nLeftMargin ), FUNIT_100TH_MM ); + maPageMarginEdt.SetValue( maPageMarginEdt.Normalize( i_rMPS.nHorizontalSpacing ), FUNIT_100TH_MM ); + maBorderCB.Check( i_rMPS.bDrawBorder ); + maNupRowsEdt.SetValue( i_rMPS.nRows ); + maNupColEdt.SetValue( i_rMPS.nColumns ); +} + +void PrintDialog::NUpTabPage::readFromSettings() +{ +} + +void PrintDialog::NUpTabPage::storeToSettings() +{ +} + +PrintDialog::JobTabPage::JobTabPage( Window* i_pParent, const ResId& rResId ) + : TabPage( i_pParent, rResId ) + , maPrinterFL( this, VclResId( SV_PRINT_PRINTERS_FL ) ) + , maPrinters( this, VclResId( SV_PRINT_PRINTERS ) ) + , maDetailsBtn( this, VclResId( SV_PRINT_DETAILS_BTN ) ) + , maStatusLabel( this, VclResId( SV_PRINT_STATUS_TXT ) ) + , maStatusTxt( this, 0 ) + , maLocationLabel( this, VclResId( SV_PRINT_LOCATION_TXT ) ) + , maLocationTxt( this, 0 ) + , maCommentLabel( this, VclResId( SV_PRINT_COMMENT_TXT ) ) + , maCommentTxt( this, 0 ) + , maSetupButton( this, VclResId( SV_PRINT_PRT_SETUP ) ) + , maCopies( this, VclResId( SV_PRINT_COPIES ) ) + , maCopySpacer( this, WB_VERT ) + , maCopyCount( this, VclResId( SV_PRINT_COPYCOUNT ) ) + , maCopyCountField( this, VclResId( SV_PRINT_COPYCOUNT_FIELD ) ) + , maCollateBox( this, VclResId( SV_PRINT_COLLATE ) ) + , maCollateImage( this, VclResId( SV_PRINT_COLLATE_IMAGE ) ) + , maCollateImg( VclResId( SV_PRINT_COLLATE_IMG ) ) + , maCollateHCImg( VclResId( SV_PRINT_COLLATE_HC_IMG ) ) + , maNoCollateImg( VclResId( SV_PRINT_NOCOLLATE_IMG ) ) + , maNoCollateHCImg( VclResId( SV_PRINT_NOCOLLATE_HC_IMG ) ) + , mnCollateUIMode( 0 ) + , maLayout( NULL, true ) +{ + FreeResource(); + + SMHID1( "JobPage" ); + maPrinterFL.SMHID2( "JobPage", "Printer" ); + maPrinters.SMHID2( "JobPage", "PrinterList" ); + maDetailsBtn.SMHID2( "JobPage", "DetailsBtn" ); + maStatusLabel.SMHID2( "JobPage", "StatusLabel" ); + maStatusTxt.SMHID2( "JobPage", "StatusText" ); + maLocationLabel.SMHID2( "JobPage", "LocationLabel" ); + maLocationTxt.SMHID2( "JobPage", "LocationText" ); + maCommentLabel.SMHID2( "JobPage", "CommentLabel" ); + maCommentTxt.SMHID2( "JobPage", "CommentText" ); + maSetupButton.SMHID2( "JobPage", "Properties" ); + maCopies.SMHID2( "JobPage", "CopiesLine" ); + maCopySpacer.SMHID2( "JobPage", "CopySpacer" ); + maCopyCount.SMHID2( "JobPage", "CopiesText" ); + maCopyCountField.SMHID2( "JobPage", "Copies" ); + maCollateBox.SMHID2( "JobPage", "Collate" ); + maCollateImage.SMHID2( "JobPage", "CollateImage" ); + + maCopySpacer.Show(); + maStatusTxt.Show(); + maCommentTxt.Show(); + maLocationTxt.Show(); + + setupLayout(); +} + +PrintDialog::JobTabPage::~JobTabPage() +{ +} + +void PrintDialog::JobTabPage::setupLayout() +{ + // HACK: this is not a dropdown box, but the dropdown line count + // sets the results of GetOptimalSize in a normal ListBox + maPrinters.SetDropDownLineCount( 4 ); + + Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); + + maLayout.setParentWindow( this ); + maLayout.setOuterBorder( aBorder.Width() ); + + // add printer fixed line + maLayout.addWindow( &maPrinterFL ); + // add print LB + maLayout.addWindow( &maPrinters ); + + // create a row for details button/text and properties button + boost::shared_ptr< vcl::RowOrColumn > xDetRow( new vcl::RowOrColumn( &maLayout, false ) ); + maLayout.addChild( xDetRow ); + xDetRow->addWindow( &maDetailsBtn ); + xDetRow->addChild( new vcl::Spacer( xDetRow.get(), 2 ) ); + xDetRow->addWindow( &maSetupButton ); + + // create an indent for details + boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( &maLayout ) ); + maLayout.addChild( xIndent ); + // remember details controls + mxDetails = xIndent; + // create a column for the details + boost::shared_ptr< vcl::LabelColumn > xLabelCol( new vcl::LabelColumn( xIndent.get(), aBorder.Height() ) ); + xIndent->setChild( xLabelCol ); + xLabelCol->addRow( &maStatusLabel, &maStatusTxt ); + xLabelCol->addRow( &maLocationLabel, &maLocationTxt ); + xLabelCol->addRow( &maCommentLabel, &maCommentTxt ); + + // add print range and copies columns + maLayout.addWindow( &maCopies ); + boost::shared_ptr< vcl::RowOrColumn > xRangeRow( new vcl::RowOrColumn( &maLayout, false, aBorder.Width() ) ); + maLayout.addChild( xRangeRow ); + + // create print range and add to range row + mxPrintRange.reset( new vcl::RowOrColumn( xRangeRow.get() ) ); + xRangeRow->addChild( mxPrintRange ); + xRangeRow->addWindow( &maCopySpacer ); + + boost::shared_ptr< vcl::RowOrColumn > xCopyCollateCol( new vcl::RowOrColumn( xRangeRow.get() ) ); + xRangeRow->addChild( xCopyCollateCol ); + + // add copies row to copy/collate column + boost::shared_ptr< vcl::LabeledElement > xCopiesRow( new vcl::LabeledElement( xCopyCollateCol.get(), 2 ) ); + xCopyCollateCol->addChild( xCopiesRow ); + xCopiesRow->setLabel( &maCopyCount ); + xCopiesRow->setElement( &maCopyCountField ); + boost::shared_ptr< vcl::LabeledElement > xCollateRow( new vcl::LabeledElement( xCopyCollateCol.get(), 2 ) ); + xCopyCollateCol->addChild( xCollateRow ); + xCollateRow->setLabel( &maCollateBox ); + xCollateRow->setElement( &maCollateImage ); + + // maDetailsBtn.SetStyle( maDetailsBtn.GetStyle() | (WB_SMALLSTYLE | WB_BEVELBUTTON) ); + mxDetails->show( false, false ); +} + +void PrintDialog::JobTabPage::readFromSettings() +{ + SettingsConfigItem* pItem = SettingsConfigItem::get(); + rtl::OUString aValue; + + #if 0 + // do not actually make copy count persistent + // the assumption is that this would lead to a lot of unwanted copies + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) ); + sal_Int32 nVal = aValue.toInt32(); + maCopyCountField.SetValue( sal_Int64(nVal > 1 ? nVal : 1) ); + #endif + + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CollateBox" ) ) ); + if( aValue.equalsIgnoreAsciiCaseAscii( "alwaysoff" ) ) + { + mnCollateUIMode = 1; + maCollateBox.Check( FALSE ); + maCollateBox.Enable( FALSE ); + } + else + { + mnCollateUIMode = 0; + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ); + maCollateBox.Check( aValue.equalsIgnoreAsciiCaseAscii( "true" ) ); + } + Resize(); +} + +void PrintDialog::JobTabPage::storeToSettings() +{ + SettingsConfigItem* pItem = SettingsConfigItem::get(); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ), + maCopyCountField.GetText() ); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ), + rtl::OUString::createFromAscii( maCollateBox.IsChecked() ? "true" : "false" ) ); +} + +void PrintDialog::JobTabPage::Resize() +{ + maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); +} + +PrintDialog::OutputOptPage::OutputOptPage( Window* i_pParent, const ResId& i_rResId ) + : TabPage( i_pParent, i_rResId ) + , maOptionsLine( this, VclResId( SV_PRINT_OPT_PRINT_FL ) ) + , maToFileBox( this, VclResId( SV_PRINT_OPT_TOFILE ) ) + , maCollateSingleJobsBox( this, VclResId( SV_PRINT_OPT_SINGLEJOBS ) ) + , maReverseOrderBox( this, VclResId( SV_PRINT_OPT_REVERSE ) ) +{ + FreeResource(); + SMHID1( "OptPage" ); + maOptionsLine.SMHID2( "OptPage", "Options" ); + maToFileBox.SMHID2( "OptPage", "ToFile" ); + maCollateSingleJobsBox.SMHID2( "OptPage", "SingleJobs" ); + maReverseOrderBox.SMHID2( "OptPage", "Reverse" ); + + setupLayout(); +} + +PrintDialog::OutputOptPage::~OutputOptPage() +{ +} + +void PrintDialog::OutputOptPage::setupLayout() +{ + Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); + + maLayout.setParentWindow( this ); + maLayout.setOuterBorder( aBorder.Width() ); + + maLayout.addWindow( &maOptionsLine ); + boost::shared_ptr<vcl::Indenter> xIndent( new vcl::Indenter( &maLayout, aBorder.Width() ) ); + maLayout.addChild( xIndent ); + boost::shared_ptr<vcl::RowOrColumn> xCol( new vcl::RowOrColumn( xIndent.get(), aBorder.Height() ) ); + xIndent->setChild( xCol ); + mxOptGroup = xCol; + xCol->addWindow( &maToFileBox ); + xCol->addWindow( &maCollateSingleJobsBox ); + xCol->addWindow( &maReverseOrderBox ); +} + +void PrintDialog::OutputOptPage::readFromSettings() +{ + #if 0 + SettingsConfigItem* pItem = SettingsConfigItem::get(); + rtl::OUString aValue; + + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ToFile" ) ) ); + maToFileBox.Check( aValue.equalsIgnoreAsciiCaseAscii( "true" ) ); + #endif +} + +void PrintDialog::OutputOptPage::storeToSettings() +{ + SettingsConfigItem* pItem = SettingsConfigItem::get(); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ToFile" ) ), + rtl::OUString::createFromAscii( maToFileBox.IsChecked() ? "true" : "false" ) ); +} + +void PrintDialog::OutputOptPage::Resize() +{ + maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); +} + + +PrintDialog::PrintDialog( Window* i_pParent, const boost::shared_ptr<PrinterController>& i_rController ) + : ModalDialog( i_pParent, VclResId( SV_DLG_PRINT ) ) + , maOKButton( this, VclResId( SV_PRINT_OK ) ) + , maCancelButton( this, VclResId( SV_PRINT_CANCEL ) ) + , maHelpButton( this, VclResId( SV_PRINT_HELP ) ) + , maPreviewWindow( this, VclResId( SV_PRINT_PAGE_PREVIEW ) ) + , maPageEdit( this, VclResId( SV_PRINT_PAGE_EDIT ) ) + , maNumPagesText( this, VclResId( SV_PRINT_PAGE_TXT ) ) + , maBackwardBtn( this, VclResId( SV_PRINT_PAGE_BACKWARD ) ) + , maForwardBtn( this, VclResId( SV_PRINT_PAGE_FORWARD ) ) + , maTabCtrl( this, VclResId( SV_PRINT_TABCTRL ) ) + , maNUpPage( &maTabCtrl, VclResId( SV_PRINT_TAB_NUP ) ) + , maJobPage( &maTabCtrl, VclResId( SV_PRINT_TAB_JOB ) ) + , maOptionsPage( &maTabCtrl, VclResId( SV_PRINT_TAB_OPT ) ) + , maButtonLine( this, VclResId( SV_PRINT_BUTTONLINE ) ) + , maPController( i_rController ) + , maNoPageStr( String( VclResId( SV_PRINT_NOPAGES ) ) ) + , mnCurPage( 0 ) + , mnCachedPages( 0 ) + , maPrintToFileText( String( VclResId( SV_PRINT_TOFILE_TXT ) ) ) + , maDefPrtText( String( VclResId( SV_PRINT_DEFPRT_TXT ) ) ) + , mbShowLayoutPage( sal_True ) +{ + FreeResource(); + + // save printbutton text, gets exchanged occasionally with print to file + maPrintText = maOKButton.GetText(); + + // setup preview controls + maForwardBtn.SetStyle( maForwardBtn.GetStyle() | WB_BEVELBUTTON ); + maBackwardBtn.SetStyle( maBackwardBtn.GetStyle() | WB_BEVELBUTTON ); + + // insert the job (general) tab page first + maTabCtrl.InsertPage( SV_PRINT_TAB_JOB, maJobPage.GetText() ); + maTabCtrl.SetTabPage( SV_PRINT_TAB_JOB, &maJobPage ); + + // set symbols on forward and backward button + maBackwardBtn.SetSymbol( SYMBOL_PREV ); + maForwardBtn.SetSymbol( SYMBOL_NEXT ); + maBackwardBtn.ImplSetSmallSymbol( TRUE ); + maForwardBtn.ImplSetSmallSymbol( TRUE ); + + maPageStr = maNumPagesText.GetText(); + + // init reverse print + maOptionsPage.maReverseOrderBox.Check( maPController->getReversePrint() ); + + // get the first page + preparePreview( true, true ); + + // fill printer listbox + const std::vector< rtl::OUString >& rQueues( Printer::GetPrinterQueues() ); + for( std::vector< rtl::OUString >::const_iterator it = rQueues.begin(); + it != rQueues.end(); ++it ) + { + maJobPage.maPrinters.InsertEntry( *it ); + } + // select current printer + if( maJobPage.maPrinters.GetEntryPos( maPController->getPrinter()->GetName() ) != LISTBOX_ENTRY_NOTFOUND ) + { + maJobPage.maPrinters.SelectEntry( maPController->getPrinter()->GetName() ); + } + else + { + // fall back to last printer + SettingsConfigItem* pItem = SettingsConfigItem::get(); + String aValue( pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinter" ) ) ) ); + if( maJobPage.maPrinters.GetEntryPos( aValue ) != LISTBOX_ENTRY_NOTFOUND ) + { + maJobPage.maPrinters.SelectEntry( aValue ); + maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( aValue ) ) ); + } + else + { + // fall back to default printer + maJobPage.maPrinters.SelectEntry( Printer::GetDefaultPrinterName() ); + maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( Printer::GetDefaultPrinterName() ) ) ); + } + } + // update the text fields for the printer + updatePrinterText(); + + // set a select handler + maJobPage.maPrinters.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + + // setup sizes for N-Up + Size aNupSize( maPController->getPrinter()->PixelToLogic( + maPController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + if( maPController->getPrinter()->GetOrientation() == ORIENTATION_LANDSCAPE ) + { + maNupLandscapeSize = aNupSize; + maNupPortraitSize = Size( aNupSize.Height(), aNupSize.Width() ); + } + else + { + maNupPortraitSize = aNupSize; + maNupLandscapeSize = Size( aNupSize.Height(), aNupSize.Width() ); + } + maNUpPage.initFromMultiPageSetup( maPController->getMultipage() ); + + + // setup click handler on the various buttons + maOKButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + #if OSL_DEBUG_LEVEL > 1 + maCancelButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + #endif + maHelpButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maForwardBtn.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maBackwardBtn.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maJobPage.maCollateBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maJobPage.maSetupButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maJobPage.maDetailsBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maNUpPage.maBorderCB.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maOptionsPage.maToFileBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maOptionsPage.maReverseOrderBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maNUpPage.maPagesBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + + // setup modify hdl + maPageEdit.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maJobPage.maCopyCountField.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maNupRowsEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maNupColEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maPageMarginEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maSheetMarginEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + + // setup select hdl + maNUpPage.maNupPagesBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + maNUpPage.maNupOrientationBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + maNUpPage.maNupOrderBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + + // setup the layout + setupLayout(); + + // setup optional UI options set by application + setupOptionalUI(); + + // set change handler for UI options + maPController->setOptionChangeHdl( LINK( this, PrintDialog, UIOptionsChanged ) ); + + // set min size pixel to current size + Size aOutSize( GetOutputSizePixel() ); + SetMinOutputSizePixel( aOutSize ); + + // if there is space enough, enlarge the preview so it gets roughly as + // high as the tab control + if( aOutSize.Width() < 768 ) + { + Size aJobPageSize( getJobPageSize() ); + Size aTabSize( maTabCtrl.GetSizePixel() ); + if( aJobPageSize.Width() < 1 ) + aJobPageSize.Width() = aTabSize.Width(); + if( aJobPageSize.Height() < 1 ) + aJobPageSize.Height() = aTabSize.Height(); + long nOptPreviewWidth = aTabSize.Height() * aJobPageSize.Width() / aJobPageSize.Height(); + // add space for borders + nOptPreviewWidth += 15; + if( aOutSize.Width() - aTabSize.Width() < nOptPreviewWidth ) + { + aOutSize.Width() = aTabSize.Width() + nOptPreviewWidth; + if( aOutSize.Width() > 768 ) // don't enlarge the dialog too much + aOutSize.Width() = 768; + SetOutputSizePixel( aOutSize ); + } + } + + // set HelpIDs + SMHID1( "Dialog" ); + maOKButton.SMHID1( "OK" ); + maCancelButton.SMHID1( "Cancel" ); + maHelpButton.SMHID1( "Help" ); + maPreviewWindow.SMHID1( "Preview" ); + maNumPagesText.SMHID1( "NumPagesText" ); + maPageEdit.SMHID1( "PageEdit" ); + maForwardBtn.SMHID1( "ForwardBtn" ); + maBackwardBtn.SMHID1( "BackwardBtn" ); + maTabCtrl.SMHID1( "TabPages" ); + + // append further tab pages + if( mbShowLayoutPage ) + { + maTabCtrl.InsertPage( SV_PRINT_TAB_NUP, maNUpPage.GetText() ); + maTabCtrl.SetTabPage( SV_PRINT_TAB_NUP, &maNUpPage ); + } + maTabCtrl.InsertPage( SV_PRINT_TAB_OPT, maOptionsPage.GetText() ); + maTabCtrl.SetTabPage( SV_PRINT_TAB_OPT, &maOptionsPage ); + + // restore settings from last run + readFromSettings(); + + // setup dependencies + checkControlDependencies(); + +} + +PrintDialog::~PrintDialog() +{ + while( ! maControls.empty() ) + { + delete maControls.front(); + maControls.pop_front(); + } +} + +void PrintDialog::setupLayout() +{ + Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); + + maLayout.setParentWindow( this ); + + boost::shared_ptr< vcl::RowOrColumn > xPreviewAndTab( new vcl::RowOrColumn( &maLayout, false ) ); + size_t nIndex = maLayout.addChild( xPreviewAndTab, 5 ); + maLayout.setBorders( nIndex, aBorder.Width(), aBorder.Width(), aBorder.Width(), 0 ); + + // setup column for preview and sub controls + boost::shared_ptr< vcl::RowOrColumn > xPreview( new vcl::RowOrColumn( xPreviewAndTab.get() ) ); + xPreviewAndTab->addChild( xPreview, 5 ); + xPreview->addWindow( &maPreviewWindow, 5 ); + // get a row for the preview controls + mxPreviewCtrls.reset( new vcl::RowOrColumn( xPreview.get(), false ) ); + nIndex = xPreview->addChild( mxPreviewCtrls ); + boost::shared_ptr< vcl::Spacer > xSpacer( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) ); + mxPreviewCtrls->addChild( xSpacer ); + mxPreviewCtrls->addWindow( &maPageEdit ); + mxPreviewCtrls->addWindow( &maNumPagesText ); + xSpacer.reset( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) ); + mxPreviewCtrls->addChild( xSpacer ); + mxPreviewCtrls->addWindow( &maBackwardBtn ); + mxPreviewCtrls->addWindow( &maForwardBtn ); + xSpacer.reset( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) ); + mxPreviewCtrls->addChild( xSpacer ); + + // continue with the tab ctrl + xPreviewAndTab->addWindow( &maTabCtrl ); + + // add the button line + maLayout.addWindow( &maButtonLine ); + + // add the row for the buttons + boost::shared_ptr< vcl::RowOrColumn > xButtons( new vcl::RowOrColumn( &maLayout, false ) ); + nIndex = maLayout.addChild( xButtons ); + maLayout.setBorders( nIndex, aBorder.Width(), 0, aBorder.Width(), aBorder.Width() ); + + Size aMinSize( maCancelButton.GetSizePixel() ); + // insert help button + xButtons->setMinimumSize( xButtons->addWindow( &maHelpButton ), aMinSize ); + // insert a spacer, cancel and OK buttons are right aligned + xSpacer.reset( new vcl::Spacer( xButtons.get(), 2 ) ); + xButtons->addChild( xSpacer ); + xButtons->setMinimumSize( xButtons->addWindow( &maOKButton ), aMinSize ); + xButtons->setMinimumSize( xButtons->addWindow( &maCancelButton ), aMinSize ); +} + +void PrintDialog::readFromSettings() +{ + maJobPage.readFromSettings(); + maNUpPage.readFromSettings(); + maOptionsPage.readFromSettings(); + + // read last selected tab page; if it exists, actiavte it + SettingsConfigItem* pItem = SettingsConfigItem::get(); + rtl::OUString aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPage" ) ) ); + USHORT nCount = maTabCtrl.GetPageCount(); + for( USHORT i = 0; i < nCount; i++ ) + { + USHORT nPageId = maTabCtrl.GetPageId( i ); + if( aValue.equals( maTabCtrl.GetPageText( nPageId ) ) ) + { + maTabCtrl.SelectTabPage( nPageId ); + break; + } + } + maOKButton.SetText( maOptionsPage.maToFileBox.IsChecked() ? maPrintToFileText : maPrintText ); +} + +void PrintDialog::storeToSettings() +{ + maJobPage.storeToSettings(); + maNUpPage.storeToSettings(); + maOptionsPage.storeToSettings(); + + // store last selected printer + SettingsConfigItem* pItem = SettingsConfigItem::get(); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinter" ) ), + maJobPage.maPrinters.GetSelectEntry() ); + + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPage" ) ), + maTabCtrl.GetPageText( maTabCtrl.GetCurPageId() ) ); + pItem->Commit(); +} + +bool PrintDialog::isPrintToFile() +{ + return maOptionsPage.maToFileBox.IsChecked(); +} + +int PrintDialog::getCopyCount() +{ + return static_cast<int>(maJobPage.maCopyCountField.GetValue()); +} + +bool PrintDialog::isCollate() +{ + return maJobPage.maCopyCountField.GetValue() > 1 ? maJobPage.maCollateBox.IsChecked() : FALSE; +} + +static void setSmartId( Window* i_pWindow, const char* i_pType, sal_Int32 i_nId = -1, const rtl::OUString& i_rPropName = rtl::OUString() ) +{ + rtl::OUStringBuffer aBuf( 256 ); + aBuf.appendAscii( HELPID_PREFIX ); + if( i_rPropName.getLength() ) + { + aBuf.append( sal_Unicode( ':' ) ); + aBuf.append( i_rPropName ); + } + if( i_pType ) + { + aBuf.append( sal_Unicode( ':' ) ); + aBuf.appendAscii( i_pType ); + } + if( i_nId >= 0 ) + { + aBuf.append( sal_Unicode( ':' ) ); + aBuf.append( i_nId ); + } + i_pWindow->SetSmartHelpId( SmartId( aBuf.makeStringAndClear(), HID_PRINTDLG ) ); +} + +static void setHelpText( Window* i_pWindow, const Sequence< rtl::OUString >& i_rHelpTexts, sal_Int32 i_nIndex ) +{ + if( i_nIndex >= 0 && i_nIndex < i_rHelpTexts.getLength() ) + i_pWindow->SetHelpText( i_rHelpTexts.getConstArray()[i_nIndex] ); +} + +void updateMaxSize( const Size& i_rCheckSize, Size& o_rMaxSize ) +{ + if( i_rCheckSize.Width() > o_rMaxSize.Width() ) + o_rMaxSize.Width() = i_rCheckSize.Width(); + if( i_rCheckSize.Height() > o_rMaxSize.Height() ) + o_rMaxSize.Height() = i_rCheckSize.Height(); +} + +void PrintDialog::setupOptionalUI() +{ + Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); + + std::vector<vcl::RowOrColumn*> aDynamicColumns; + vcl::RowOrColumn* pCurColumn = 0; + + Window* pCurParent = 0, *pDynamicPageParent = 0; + USHORT nOptPageId = 9, nCurSubGroup = 0; + bool bOnStaticPage = false; + bool bSubgroupOnStaticPage = false; + + std::multimap< rtl::OUString, vcl::RowOrColumn* > aPropertyToDependencyRowMap; + + const Sequence< PropertyValue >& rOptions( maPController->getUIOptions() ); + 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; + Sequence< rtl::OUString > aChoices; + Sequence< rtl::OUString > aHelpTexts; + sal_Int64 nMinValue = 0, nMaxValue = 0; + sal_Int32 nCurHelpText = 0; + rtl::OUString aGroupingHint; + rtl::OUString aDependsOnName; + sal_Int32 nDependsOnValue = 0; + sal_Bool bUseDependencyRow = sal_False; + + for( int n = 0; n < aOptProp.getLength(); n++ ) + { + const beans::PropertyValue& rEntry( aOptProp[ n ] ); + if( rEntry.Name.equalsAscii( "Text" ) ) + { + rEntry.Value >>= 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( "GroupingHint" ) ) + { + rEntry.Value >>= aGroupingHint; + } + else if( rEntry.Name.equalsAscii( "DependsOnName" ) ) + { + rEntry.Value >>= aDependsOnName; + } + else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) ) + { + rEntry.Value >>= nDependsOnValue; + } + else if( rEntry.Name.equalsAscii( "AttachToDependency" ) ) + { + rEntry.Value >>= bUseDependencyRow; + } + else if( rEntry.Name.equalsAscii( "MinValue" ) ) + { + rEntry.Value >>= nMinValue; + } + else if( rEntry.Name.equalsAscii( "MaxValue" ) ) + { + rEntry.Value >>= nMaxValue; + } + else if( rEntry.Name.equalsAscii( "HelpText" ) ) + { + if( ! (rEntry.Value >>= aHelpTexts) ) + { + rtl::OUString aHelpText; + if( (rEntry.Value >>= aHelpText) ) + { + aHelpTexts.realloc( 1 ); + *aHelpTexts.getArray() = aHelpText; + } + } + } + else if( rEntry.Name.equalsAscii( "HintNoLayoutPage" ) ) + { + sal_Bool bNoLayoutPage = sal_False; + rEntry.Value >>= bNoLayoutPage; + mbShowLayoutPage = ! bNoLayoutPage; + } + } + + // bUseDependencyRow should only be true if a dependency exists + bUseDependencyRow = bUseDependencyRow && (aDependsOnName.getLength() != 0); + + // is it necessary to switch between static and dynamic pages ? + bool bSwitchPage = false; + if( aGroupingHint.getLength() ) + bSwitchPage = true; + else if( aCtrlType.equalsAscii( "Subgroup" ) || (bOnStaticPage && ! bSubgroupOnStaticPage ) ) + bSwitchPage = true; + if( bSwitchPage ) + { + // restore to dynamic + pCurParent = pDynamicPageParent; + pCurColumn = aDynamicColumns.empty() ? NULL : aDynamicColumns.back(); + bOnStaticPage = false; + bSubgroupOnStaticPage = false; + + if( aGroupingHint.equalsAscii( "PrintRange" ) ) + { + pCurColumn = maJobPage.mxPrintRange.get(); + pCurParent = &maJobPage; // set job page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.equalsAscii( "OptionsPage" ) ) + { + pCurColumn = &maOptionsPage.maLayout; + pCurParent = &maOptionsPage; // set options page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.equalsAscii( "OptionsPageOptGroup" ) ) + { + pCurColumn = maOptionsPage.mxOptGroup.get(); + pCurParent = &maOptionsPage; // set options page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.equalsAscii( "LayoutPage" ) ) + { + pCurColumn = &maNUpPage.maLayout; + pCurParent = &maNUpPage; // set layout page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.getLength() ) + { + pCurColumn = &maJobPage.maLayout; + pCurParent = &maJobPage; // set job page as current parent + bOnStaticPage = true; + } + } + + if( aCtrlType.equalsAscii( "Group" ) || + ( ! pCurParent && ! (bOnStaticPage || aGroupingHint.getLength() ) ) ) + { + // add new tab page + TabPage* pNewGroup = new TabPage( &maTabCtrl ); + maControls.push_front( pNewGroup ); + pDynamicPageParent = pCurParent = pNewGroup; + pNewGroup->SetText( aText ); + maTabCtrl.InsertPage( ++nOptPageId, aText ); + maTabCtrl.SetTabPage( nOptPageId, pNewGroup ); + + // set help id + setSmartId( pNewGroup, "TabPage", nOptPageId ); + // set help text + setHelpText( pNewGroup, aHelpTexts, 0 ); + + // reset subgroup counter + nCurSubGroup = 0; + + aDynamicColumns.push_back( new vcl::RowOrColumn( NULL, true, aBorder.Width() ) ); + pCurColumn = aDynamicColumns.back(); + pCurColumn->setParentWindow( pNewGroup ); + pCurColumn->setOuterBorder( aBorder.Width() ); + bSubgroupOnStaticPage = false; + bOnStaticPage = false; + } + else if( aCtrlType.equalsAscii( "Subgroup" ) && (pCurParent || aGroupingHint.getLength() ) ) + { + bSubgroupOnStaticPage = (aGroupingHint.getLength() != 0); + // create group FixedLine + if( ! aGroupingHint.equalsAscii( "PrintRange" ) || + ! pCurColumn->countElements() == 0 + ) + { + Window* pNewSub = NULL; + if( aGroupingHint.equalsAscii( "PrintRange" ) ) + pNewSub = new FixedText( pCurParent, WB_VCENTER ); + else + pNewSub = new FixedLine( pCurParent ); + maControls.push_front( pNewSub ); + pNewSub->SetText( aText ); + pNewSub->Show(); + + // set help id + setSmartId( pNewSub, "FixedLine", sal_Int32( nCurSubGroup++ ) ); + // set help text + setHelpText( pNewSub, aHelpTexts, 0 ); + // add group to current column + pCurColumn->addWindow( pNewSub ); + } + + // add an indent to the current column + vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn, aBorder.Width() ); + pCurColumn->addChild( pIndent ); + // and create a column inside the indent + pCurColumn = new vcl::RowOrColumn( pIndent ); + pIndent->setChild( pCurColumn ); + } + // EVIL + else if( aCtrlType.equalsAscii( "Bool" ) && + aGroupingHint.equalsAscii( "LayoutPage" ) && + aPropertyName.equalsAscii( "PrintProspect" ) + ) + { + maNUpPage.maBrochureBtn.SetText( aText ); + maNUpPage.maBrochureBtn.Show(); + setHelpText( &maNUpPage.maBrochureBtn, aHelpTexts, 0 ); + + sal_Bool bVal = sal_False; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal ) + pVal->Value >>= bVal; + maNUpPage.maBrochureBtn.Check( bVal ); + maNUpPage.maBrochureBtn.Enable( maPController->isUIOptionEnabled( aPropertyName ) && pVal != NULL ); + maNUpPage.maBrochureBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + + maPropertyToWindowMap[ aPropertyName ].push_back( &maNUpPage.maBrochureBtn ); + maControlToPropertyMap[&maNUpPage.maBrochureBtn] = aPropertyName; + + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, maNUpPage.mxBrochureDep.get() ) ); + } + else + { + vcl::RowOrColumn* pSaveCurColumn = pCurColumn; + + if( bUseDependencyRow ) + { + // find the correct dependency row (if any) + std::pair< std::multimap< rtl::OUString, vcl::RowOrColumn* >::iterator, + std::multimap< rtl::OUString, vcl::RowOrColumn* >::iterator > aDepRange; + aDepRange = aPropertyToDependencyRowMap.equal_range( aDependsOnName ); + if( aDepRange.first != aDepRange.second ) + { + while( nDependsOnValue && aDepRange.first != aDepRange.second ) + { + nDependsOnValue--; + ++aDepRange.first; + } + if( aDepRange.first != aPropertyToDependencyRowMap.end() ) + { + pCurColumn = aDepRange.first->second; + maReverseDependencySet.insert( aPropertyName ); + } + } + } + if( aCtrlType.equalsAscii( "Bool" ) && pCurParent ) + { + // add a check box + CheckBox* pNewBox = new CheckBox( pCurParent ); + maControls.push_front( pNewBox ); + pNewBox->SetText( aText ); + pNewBox->Show(); + + sal_Bool bVal = sal_False; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal ) + pVal->Value >>= bVal; + pNewBox->Check( bVal ); + pNewBox->SetToggleHdl( LINK( this, PrintDialog, UIOption_CheckHdl ) ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pNewBox ); + maControlToPropertyMap[pNewBox] = aPropertyName; + + // set help id + setSmartId( pNewBox, "CheckBox", -1, aPropertyName ); + // set help text + setHelpText( pNewBox, aHelpTexts, 0 ); + + vcl::RowOrColumn* pDependencyRow = new vcl::RowOrColumn( pCurColumn, false ); + pCurColumn->addChild( pDependencyRow ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pDependencyRow ) ); + + // add checkbox to current column + pDependencyRow->addWindow( pNewBox ); + } + else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent ) + { + vcl::RowOrColumn* pRadioColumn = pCurColumn; + if( aText.getLength() ) + { + // add a FixedText: + FixedText* pHeading = new FixedText( pCurParent ); + maControls.push_front( pHeading ); + pHeading->SetText( aText ); + pHeading->Show(); + + // set help id + setSmartId( pHeading, "FixedText", -1, aPropertyName ); + // set help text + setHelpText( pHeading, aHelpTexts, nCurHelpText++ ); + // add fixed text to current column + pCurColumn->addWindow( pHeading ); + // add an indent to the current column + vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn, 15 ); + pCurColumn->addChild( pIndent ); + // and create a column inside the indent + pRadioColumn = new vcl::RowOrColumn( pIndent ); + pIndent->setChild( pRadioColumn ); + } + // iterate options + sal_Int32 nSelectVal = 0; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nSelectVal; + for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) + { + boost::shared_ptr<vcl::LabeledElement> pLabel( new vcl::LabeledElement( pRadioColumn, 1 ) ); + pRadioColumn->addChild( pLabel ); + boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pLabel.get(), false ) ); + pLabel->setElement( pDependencyRow ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pDependencyRow.get() ) ); + + RadioButton* pBtn = new RadioButton( pCurParent, m == 0 ? WB_GROUP : 0 ); + maControls.push_front( pBtn ); + pBtn->SetText( aChoices[m] ); + pBtn->Check( m == nSelectVal ); + pBtn->SetToggleHdl( LINK( this, PrintDialog, UIOption_RadioHdl ) ); + pBtn->Show(); + maPropertyToWindowMap[ aPropertyName ].push_back( pBtn ); + maControlToPropertyMap[pBtn] = aPropertyName; + maControlToNumValMap[pBtn] = m; + + // set help id + setSmartId( pBtn, "RadioButton", m, aPropertyName ); + // set help text + setHelpText( pBtn, aHelpTexts, nCurHelpText++ ); + // add the radio button to the column + pLabel->setLabel( pBtn ); + } + } + else if( ( aCtrlType.equalsAscii( "List" ) || + aCtrlType.equalsAscii( "Range" ) || + aCtrlType.equalsAscii( "Edit" ) + ) && pCurParent ) + { + // create a row in the current column + vcl::RowOrColumn* pFieldColumn = new vcl::RowOrColumn( pCurColumn, false ); + pCurColumn->addChild( pFieldColumn ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pFieldColumn ) ); + + vcl::LabeledElement* pLabel = NULL; + if( aText.getLength() ) + { + // add a FixedText: + FixedText* pHeading = new FixedText( pCurParent, WB_VCENTER ); + maControls.push_front( pHeading ); + pHeading->SetText( aText ); + pHeading->Show(); + + // set help id + setSmartId( pHeading, "FixedText", -1, aPropertyName ); + + // add to row + pLabel = new vcl::LabeledElement( pFieldColumn, 2 ); + pFieldColumn->addChild( pLabel ); + pLabel->setLabel( pHeading ); + } + + if( aCtrlType.equalsAscii( "List" ) ) + { + ListBox* pList = new ListBox( pCurParent, WB_DROPDOWN | WB_BORDER ); + maControls.push_front( pList ); + + // iterate options + for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) + { + pList->InsertEntry( aChoices[m] ); + } + sal_Int32 nSelectVal = 0; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nSelectVal; + pList->SelectEntryPos( static_cast<USHORT>(nSelectVal) ); + pList->SetSelectHdl( LINK( this, PrintDialog, UIOption_SelectHdl ) ); + pList->SetDropDownLineCount( static_cast<USHORT>(aChoices.getLength()) ); + pList->Show(); + + // set help id + setSmartId( pList, "ListBox", -1, aPropertyName ); + // set help text + setHelpText( pList, aHelpTexts, 0 ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pList ); + maControlToPropertyMap[pList] = aPropertyName; + + // finish the pair + if( pLabel ) + pLabel->setElement( pList ); + else + pFieldColumn->addWindow( pList ); + } + else if( aCtrlType.equalsAscii( "Range" ) ) + { + NumericField* pField = new NumericField( pCurParent, WB_BORDER | WB_SPIN ); + maControls.push_front( pField ); + + // set min/max and current value + if( nMinValue != nMaxValue ) + { + pField->SetMin( nMinValue ); + pField->SetMax( nMaxValue ); + } + sal_Int64 nCurVal = 0; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nCurVal; + pField->SetValue( nCurVal ); + pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) ); + pField->Show(); + + // set help id + setSmartId( pField, "NumericField", -1, aPropertyName ); + // set help text + setHelpText( pField, aHelpTexts, 0 ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pField ); + maControlToPropertyMap[pField] = aPropertyName; + + // add to row + if( pLabel ) + pLabel->setElement( pField ); + else + pFieldColumn->addWindow( pField ); + } + else if( aCtrlType.equalsAscii( "Edit" ) ) + { + Edit* pField = new Edit( pCurParent, WB_BORDER ); + maControls.push_front( pField ); + + rtl::OUString aCurVal; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= aCurVal; + pField->SetText( aCurVal ); + pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) ); + pField->Show(); + + // set help id + setSmartId( pField, "Edit", -1, aPropertyName ); + // set help text + setHelpText( pField, aHelpTexts, 0 ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pField ); + maControlToPropertyMap[pField] = aPropertyName; + + // add to row + if( pLabel ) + pLabel->setElement( pField ); + else + pFieldColumn->addWindow( pField, 2 ); + } + } + else + { + DBG_ERROR( "Unsupported UI option" ); + } + + pCurColumn = pSaveCurColumn; + } + } + + // #i106506# if no brochure button, then the singular Pages radio button + // makes no sense, so replace it by a FixedText label + if( ! maNUpPage.maBrochureBtn.IsVisible() ) + { + if( maNUpPage.mxPagesBtnLabel.get() ) + { + maNUpPage.maPagesBoxTitleTxt.SetText( maNUpPage.maPagesBtn.GetText() ); + maNUpPage.maPagesBoxTitleTxt.Show( TRUE ); + maNUpPage.mxPagesBtnLabel->setLabel( &maNUpPage.maPagesBoxTitleTxt ); + maNUpPage.maPagesBtn.Show( FALSE ); + } + } + + // update enable states + checkOptionalControlDependencies(); + + // print range empty (currently math only) -> hide print range and spacer line + if( maJobPage.mxPrintRange->countElements() == 0 ) + { + maJobPage.mxPrintRange->show( false, false ); + maJobPage.maCopySpacer.Show( FALSE ); + } + +#ifdef WNT + // FIXME: the GetNativeControlRegion call on Windows has some issues + // (which skew the results of GetOptimalSize()) + // however fixing this thoroughly needs to take interaction with paint into + // acoount, making the right fix less simple. Fix this the right way + // at some point. For now simply add some space at the lowest element + size_t nIndex = maJobPage.maLayout.countElements(); + if( nIndex > 0 ) // sanity check + maJobPage.maLayout.setBorders( nIndex-1, 0, 0, 0, aBorder.Width() ); +#endif + + // calculate job page + Size aMaxSize = maJobPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ); + // and layout page + updateMaxSize( maNUpPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); + // and options page + updateMaxSize( maOptionsPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); + + for( std::vector< vcl::RowOrColumn* >::iterator it = aDynamicColumns.begin(); + it != aDynamicColumns.end(); ++it ) + { + Size aPageSize( (*it)->getOptimalSize( WINDOWSIZE_PREFERRED ) ); + updateMaxSize( aPageSize, aMaxSize ); + } + + // resize dialog if necessary + Size aTabSize = maTabCtrl.GetTabPageSizePixel(); + maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() ); + if( aMaxSize.Height() > aTabSize.Height() || aMaxSize.Width() > aTabSize.Width() ) + { + Size aCurSize( GetOutputSizePixel() ); + if( aMaxSize.Height() > aTabSize.Height() ) + { + aCurSize.Height() += aMaxSize.Height() - aTabSize.Height(); + aTabSize.Height() = aMaxSize.Height(); + } + if( aMaxSize.Width() > aTabSize.Width() ) + { + aCurSize.Width() += aMaxSize.Width() - aTabSize.Width(); + // and the tab ctrl needs more space, too + aTabSize.Width() = aMaxSize.Width(); + } + maTabCtrl.SetTabPageSizePixel( aTabSize ); + maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() ); + } + + // and finally arrange controls + for( std::vector< vcl::RowOrColumn* >::iterator it = aDynamicColumns.begin(); + it != aDynamicColumns.end(); ++it ) + { + (*it)->setManagedArea( Rectangle( Point(), aTabSize ) ); + delete *it; + *it = NULL; + } + maJobPage.Resize(); + maNUpPage.Resize(); + maOptionsPage.Resize(); + + Size aSz = maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ); + SetOutputSizePixel( aSz ); +} + +void PrintDialog::DataChanged( const DataChangedEvent& i_rDCEvt ) +{ + // react on settings changed + if( i_rDCEvt.GetType() == DATACHANGED_SETTINGS ) + checkControlDependencies(); + ModalDialog::DataChanged( i_rDCEvt ); +} + +void PrintDialog::checkControlDependencies() +{ + if( maJobPage.maCopyCountField.GetValue() > 1 ) + maJobPage.maCollateBox.Enable( maJobPage.mnCollateUIMode == 0 ); + else + maJobPage.maCollateBox.Enable( FALSE ); + + Image aImg( maJobPage.maCollateBox.IsChecked() ? maJobPage.maCollateImg : maJobPage.maNoCollateImg ); + Image aHCImg( maJobPage.maCollateBox.IsChecked() ? maJobPage.maCollateHCImg : maJobPage.maNoCollateHCImg ); + bool bHC = GetSettings().GetStyleSettings().GetHighContrastMode(); + + Size aImgSize( aImg.GetSizePixel() ); + Size aHCImgSize( aHCImg.GetSizePixel() ); + + if( aHCImgSize.Width() > aImgSize.Width() ) + aImgSize.Width() = aHCImgSize.Width(); + if( aHCImgSize.Height() > aImgSize.Height() ) + aImgSize.Height() = aHCImgSize.Height(); + + // adjust size of image + maJobPage.maCollateImage.SetSizePixel( aImgSize ); + maJobPage.maCollateImage.SetImage( bHC ? aHCImg : aImg ); + maJobPage.maCollateImage.SetModeImage( aHCImg, BMP_COLOR_HIGHCONTRAST ); + + // enable setup button only for printers that can be setup + bool bHaveSetup = maPController->getPrinter()->HasSupport( SUPPORT_SETUPDIALOG ); + maJobPage.maSetupButton.Enable( bHaveSetup ); + if( bHaveSetup ) + { + if( ! maJobPage.maSetupButton.IsVisible() ) + { + Point aPrinterPos( maJobPage.maPrinters.GetPosPixel() ); + Point aSetupPos( maJobPage.maSetupButton.GetPosPixel() ); + Size aPrinterSize( maJobPage.maPrinters.GetSizePixel() ); + aPrinterSize.Width() = aSetupPos.X() - aPrinterPos.X() - LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ).Width(); + maJobPage.maPrinters.SetSizePixel( aPrinterSize ); + maJobPage.maSetupButton.Show(); + maLayout.resize(); + } + } + else + { + if( maJobPage.maSetupButton.IsVisible() ) + { + Point aPrinterPos( maJobPage.maPrinters.GetPosPixel() ); + Point aSetupPos( maJobPage.maSetupButton.GetPosPixel() ); + Size aPrinterSize( maJobPage.maPrinters.GetSizePixel() ); + Size aSetupSize( maJobPage.maSetupButton.GetSizePixel() ); + aPrinterSize.Width() = aSetupPos.X() + aSetupSize.Width() - aPrinterPos.X(); + maJobPage.maPrinters.SetSizePixel( aPrinterSize ); + maJobPage.maSetupButton.Hide(); + maLayout.resize(); + } + } +} + +void PrintDialog::checkOptionalControlDependencies() +{ + for( std::map< Window*, rtl::OUString >::iterator it = maControlToPropertyMap.begin(); + it != maControlToPropertyMap.end(); ++it ) + { + bool bShouldbeEnabled = maPController->isUIOptionEnabled( it->second ); + if( ! bShouldbeEnabled ) + { + // enable controls that are directly attached to a dependency anyway + // if the normally disabled controls get modified, change the dependency + // so the control would be enabled + // example: in print range "Print All" is selected, "Page Range" is then of course + // not selected and the Edit for the Page Range would be disabled + // as a convenience we should enable the Edit anyway and automatically select + // "Page Range" instead of "Print All" if the Edit gets modified + if( maReverseDependencySet.find( it->second ) != maReverseDependencySet.end() ) + { + rtl::OUString aDep( maPController->getDependency( it->second ) ); + // if the dependency is at least enabled, then enable this control anyway + if( aDep.getLength() && maPController->isUIOptionEnabled( aDep ) ) + bShouldbeEnabled = true; + } + } + + bool bIsEnabled = it->first->IsEnabled(); + // Enable does not do a change check first, so can be less cheap than expected + if( bShouldbeEnabled != bIsEnabled ) + it->first->Enable( bShouldbeEnabled ); + } +} + +static rtl::OUString searchAndReplace( const rtl::OUString& i_rOrig, const char* i_pRepl, sal_Int32 i_nReplLen, const rtl::OUString& i_rRepl ) +{ + sal_Int32 nPos = i_rOrig.indexOfAsciiL( i_pRepl, i_nReplLen ); + if( nPos != -1 ) + { + rtl::OUStringBuffer aBuf( i_rOrig.getLength() ); + aBuf.append( i_rOrig.getStr(), nPos ); + aBuf.append( i_rRepl ); + if( nPos + i_nReplLen < i_rOrig.getLength() ) + aBuf.append( i_rOrig.getStr() + nPos + i_nReplLen ); + return aBuf.makeStringAndClear(); + } + return i_rOrig; +} + +void PrintDialog::updatePrinterText() +{ + String aDefPrt( Printer::GetDefaultPrinterName() ); + const QueueInfo* pInfo = Printer::GetQueueInfo( maJobPage.maPrinters.GetSelectEntry(), true ); + if( pInfo ) + { + maJobPage.maLocationTxt.SetText( pInfo->GetLocation() ); + maJobPage.maCommentTxt.SetText( pInfo->GetComment() ); + // FIXME: status text + rtl::OUString aStatus; + if( aDefPrt == pInfo->GetPrinterName() ) + aStatus = maDefPrtText; + maJobPage.maStatusTxt.SetText( aStatus ); + } + else + { + maJobPage.maLocationTxt.SetText( String() ); + maJobPage.maCommentTxt.SetText( String() ); + maJobPage.maStatusTxt.SetText( String() ); + } +} + +void PrintDialog::setPreviewText( sal_Int32 ) +{ + rtl::OUString aNewText( searchAndReplace( maPageStr, "%n", 2, rtl::OUString::valueOf( mnCachedPages ) ) ); + maNumPagesText.SetText( aNewText ); + + // if layout is already established the refresh layout of + // preview controls since text length may have changes + if( mxPreviewCtrls.get() ) + mxPreviewCtrls->setManagedArea( mxPreviewCtrls->getManagedArea() ); +} + +void PrintDialog::preparePreview( bool i_bNewPage, bool i_bMayUseCache ) +{ + // page range may have changed depending on options + sal_Int32 nPages = maPController->getFilteredPageCount(); + mnCachedPages = nPages; + + if( mnCurPage >= nPages ) + mnCurPage = nPages-1; + if( mnCurPage < 0 ) + mnCurPage = 0; + + setPreviewText( mnCurPage ); + + maPageEdit.SetMin( 1 ); + maPageEdit.SetMax( nPages ); + + if( i_bNewPage ) + { + const MapMode aMapMode( MAP_100TH_MM ); + GDIMetaFile aMtf; + boost::shared_ptr<Printer> aPrt( maPController->getPrinter() ); + if( nPages > 0 ) + { + PrinterController::PageSize aPageSize = + maPController->getFilteredPageFile( mnCurPage, aMtf, i_bMayUseCache ); + if( ! aPageSize.bFullPaper ) + { + Point aOff( aPrt->PixelToLogic( aPrt->GetPageOffsetPixel(), aMapMode ) ); + aMtf.Move( aOff.X(), aOff.Y() ); + } + } + + Size aCurPageSize = aPrt->PixelToLogic( aPrt->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ); + maPreviewWindow.setPreview( aMtf, aCurPageSize, nPages > 0 ? rtl::OUString() : maNoPageStr, + aPrt->ImplGetDPIX(), aPrt->ImplGetDPIY() + ); + + maForwardBtn.Enable( mnCurPage < nPages-1 ); + maBackwardBtn.Enable( mnCurPage != 0 ); + maPageEdit.Enable( nPages > 1 ); + } +} + +Size PrintDialog::getJobPageSize() +{ + if( maFirstPageSize.Width() == 0 && maFirstPageSize.Height() == 0) + { + maFirstPageSize = maNupPortraitSize; + GDIMetaFile aMtf; + if( maPController->getPageCountProtected() > 0 ) + { + PrinterController::PageSize aPageSize = maPController->getPageFile( 0, aMtf, true ); + maFirstPageSize = aPageSize.aSize; + } + } + return maFirstPageSize; +} + +void PrintDialog::updateNupFromPages() +{ + long nPages = long(maNUpPage.maNupPagesBox.GetEntryData(maNUpPage.maNupPagesBox.GetSelectEntryPos())); + int nRows = int(maNUpPage.maNupRowsEdt.GetValue()); + int nCols = int(maNUpPage.maNupColEdt.GetValue()); + long nPageMargin = long(maNUpPage.maPageMarginEdt.Denormalize(maNUpPage.maPageMarginEdt.GetValue( FUNIT_100TH_MM ))); + long nSheetMargin = long(maNUpPage.maSheetMarginEdt.Denormalize(maNUpPage.maSheetMarginEdt.GetValue( FUNIT_100TH_MM ))); + bool bCustom = false; + + if( nPages == 1 ) + { + nRows = nCols = 1; + nSheetMargin = 0; + nPageMargin = 0; + } + else if( nPages == 2 || nPages == 4 || nPages == 6 || nPages == 9 || nPages == 16 ) + { + Size aJobPageSize( getJobPageSize() ); + bool bPortrait = aJobPageSize.Width() < aJobPageSize.Height(); + if( nPages == 2 ) + { + if( bPortrait ) + nRows = 1, nCols = 2; + else + nRows = 2, nCols = 1; + } + else if( nPages == 4 ) + nRows = nCols = 2; + else if( nPages == 6 ) + { + if( bPortrait ) + nRows = 2, nCols = 3; + else + nRows = 3, nCols = 2; + } + else if( nPages == 9 ) + nRows = nCols = 3; + else if( nPages == 16 ) + nRows = nCols = 4; + nPageMargin = 0; + nSheetMargin = 0; + } + else + bCustom = true; + + if( nPages > 1 ) + { + // set upper limits for margins based on job page size and rows/columns + Size aSize( getJobPageSize() ); + + // maximum sheet distance: 1/2 sheet + long nHorzMax = aSize.Width()/2; + long nVertMax = aSize.Height()/2; + if( nSheetMargin > nHorzMax ) + nSheetMargin = nHorzMax; + if( nSheetMargin > nVertMax ) + nSheetMargin = nVertMax; + + maNUpPage.maSheetMarginEdt.SetMax( + maNUpPage.maSheetMarginEdt.Normalize( + nHorzMax > nVertMax ? nVertMax : nHorzMax ), FUNIT_100TH_MM ); + + // maximum page distance + nHorzMax = (aSize.Width() - 2*nSheetMargin); + if( nCols > 1 ) + nHorzMax /= (nCols-1); + nVertMax = (aSize.Height() - 2*nSheetMargin); + if( nRows > 1 ) + nHorzMax /= (nRows-1); + + if( nPageMargin > nHorzMax ) + nPageMargin = nHorzMax; + if( nPageMargin > nVertMax ) + nPageMargin = nVertMax; + + maNUpPage.maPageMarginEdt.SetMax( + maNUpPage.maSheetMarginEdt.Normalize( + nHorzMax > nVertMax ? nVertMax : nHorzMax ), FUNIT_100TH_MM ); + } + + maNUpPage.maNupRowsEdt.SetValue( nRows ); + maNUpPage.maNupColEdt.SetValue( nCols ); + maNUpPage.maPageMarginEdt.SetValue( maNUpPage.maPageMarginEdt.Normalize( nPageMargin ), FUNIT_100TH_MM ); + maNUpPage.maSheetMarginEdt.SetValue( maNUpPage.maSheetMarginEdt.Normalize( nSheetMargin ), FUNIT_100TH_MM ); + + maNUpPage.showAdvancedControls( bCustom ); + if( bCustom ) + { + // see if we have to enlarge the dialog to make the tab page fit + Size aCurSize( maNUpPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ) ); + Size aTabSize( maTabCtrl.GetTabPageSizePixel() ); + if( aTabSize.Height() < aCurSize.Height() ) + { + Size aDlgSize( GetSizePixel() ); + aDlgSize.Height() += aCurSize.Height() - aTabSize.Height(); + SetSizePixel( aDlgSize ); + } + } + + updateNup(); +} + +void PrintDialog::updateNup() +{ + int nRows = int(maNUpPage.maNupRowsEdt.GetValue()); + int nCols = int(maNUpPage.maNupColEdt.GetValue()); + long nPageMargin = long(maNUpPage.maPageMarginEdt.Denormalize(maNUpPage.maPageMarginEdt.GetValue( FUNIT_100TH_MM ))); + long nSheetMargin = long(maNUpPage.maSheetMarginEdt.Denormalize(maNUpPage.maSheetMarginEdt.GetValue( FUNIT_100TH_MM ))); + + PrinterController::MultiPageSetup aMPS; + aMPS.nRows = nRows; + aMPS.nColumns = nCols; + aMPS.nRepeat = 1; + aMPS.nLeftMargin = + aMPS.nTopMargin = + aMPS.nRightMargin = + aMPS.nBottomMargin = nSheetMargin; + + aMPS.nHorizontalSpacing = + aMPS.nVerticalSpacing = nPageMargin; + + aMPS.bDrawBorder = maNUpPage.maBorderCB.IsChecked(); + + int nOrderMode = int(sal_IntPtr(maNUpPage.maNupOrderBox.GetEntryData( + maNUpPage.maNupOrderBox.GetSelectEntryPos() ))); + if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_LRTD ) + aMPS.nOrder = PrinterController::LRTB; + else if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_TDLR ) + aMPS.nOrder = PrinterController::TBLR; + + int nOrientationMode = int(sal_IntPtr(maNUpPage.maNupOrientationBox.GetEntryData( + maNUpPage.maNupOrientationBox.GetSelectEntryPos() ))); + if( nOrientationMode == SV_PRINT_PRT_NUP_ORIENTATION_LANDSCAPE ) + aMPS.aPaperSize = maNupLandscapeSize; + else if( nOrientationMode == SV_PRINT_PRT_NUP_ORIENTATION_PORTRAIT ) + aMPS.aPaperSize = maNupPortraitSize; + else // automatic mode + { + // get size of first real page to see if it is portrait or landscape + // we assume same page sizes for all the pages for this + Size aPageSize = getJobPageSize(); + + Size aMultiSize( aPageSize.Width() * nCols, aPageSize.Height() * nRows ); + if( aMultiSize.Width() > aMultiSize.Height() ) // fits better on landscape + aMPS.aPaperSize = maNupLandscapeSize; + else + aMPS.aPaperSize = maNupPortraitSize; + } + + maPController->setMultipage( aMPS ); + + maNUpPage.maNupOrderWin.setValues( nOrderMode, nCols, nRows ); + + preparePreview( true, true ); +} + +IMPL_LINK( PrintDialog, SelectHdl, ListBox*, pBox ) +{ + if( pBox == &maJobPage.maPrinters ) + { + String aNewPrinter( pBox->GetSelectEntry() ); + // set new printer + maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( aNewPrinter ) ) ); + // update text fields + updatePrinterText(); + } + else if( pBox == &maNUpPage.maNupOrientationBox || pBox == &maNUpPage.maNupOrderBox ) + { + updateNup(); + } + else if( pBox == &maNUpPage.maNupPagesBox ) + { + if( !maNUpPage.maPagesBtn.IsChecked() ) + maNUpPage.maPagesBtn.Check(); + updateNupFromPages(); + } + + return 0; +} + +IMPL_LINK( PrintDialog, ClickHdl, Button*, pButton ) +{ + if( pButton == &maOKButton || pButton == &maCancelButton ) + { + storeToSettings(); + EndDialog( pButton == &maOKButton ); + } + else if( pButton == &maHelpButton ) + { + // start help system + Help* pHelp = Application::GetHelp(); + if( pHelp ) + { + // FIXME: find out proper help URL and use here + pHelp->Start( HID_PRINTDLG, GetParent() ); + } + } + else if( pButton == &maForwardBtn ) + { + previewForward(); + } + else if( pButton == &maBackwardBtn ) + { + previewBackward(); + } + else if( pButton == &maOptionsPage.maToFileBox ) + { + maOKButton.SetText( maOptionsPage.maToFileBox.IsChecked() ? maPrintToFileText : maPrintText ); + maLayout.resize(); + } + else if( pButton == &maNUpPage.maBrochureBtn ) + { + PropertyValue* pVal = getValueForWindow( pButton ); + if( pVal ) + { + sal_Bool bVal = maNUpPage.maBrochureBtn.IsChecked(); + pVal->Value <<= bVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + if( maNUpPage.maBrochureBtn.IsChecked() ) + { + maNUpPage.maNupPagesBox.SelectEntryPos( 0 ); + updateNupFromPages(); + maNUpPage.showAdvancedControls( false ); + maNUpPage.enableNupControls( false ); + } + } + else if( pButton == &maNUpPage.maPagesBtn ) + { + maNUpPage.enableNupControls( true ); + updateNupFromPages(); + } + else if( pButton == &maJobPage.maDetailsBtn ) + { + bool bShow = maJobPage.maDetailsBtn.IsChecked(); + maJobPage.mxDetails->show( bShow ); + if( bShow ) + { + maDetailsCollapsedSize = GetOutputSizePixel(); + // enlarge dialog if necessary + Size aMinSize( maJobPage.maLayout.getOptimalSize( WINDOWSIZE_MINIMUM ) ); + Size aCurSize( maJobPage.GetSizePixel() ); + if( aCurSize.Height() < aMinSize.Height() ) + { + Size aDlgSize( GetOutputSizePixel() ); + aDlgSize.Height() += aMinSize.Height() - aCurSize.Height(); + SetOutputSizePixel( aDlgSize ); + } + maDetailsExpandedSize = GetOutputSizePixel(); + } + else if( maDetailsCollapsedSize.Width() > 0 && + maDetailsCollapsedSize.Height() > 0 ) + { + // if the user did not resize the dialog + // make it smaller again on collapsing the details + Size aDlgSize( GetOutputSizePixel() ); + if( aDlgSize == maDetailsExpandedSize && + aDlgSize.Height() > maDetailsCollapsedSize.Height() ) + { + SetOutputSizePixel( maDetailsCollapsedSize ); + } + } + } + else if( pButton == &maJobPage.maCollateBox ) + { + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ), + makeAny( sal_Bool(isCollate()) ) ); + checkControlDependencies(); + } + else if( pButton == &maOptionsPage.maReverseOrderBox ) + { + sal_Bool bChecked = maOptionsPage.maReverseOrderBox.IsChecked(); + maPController->setReversePrint( bChecked ); + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintReverse" ) ), + makeAny( bChecked ) ); + preparePreview( true, true ); + } + else if( pButton == &maNUpPage.maBorderCB ) + { + updateNup(); + } + else + { + if( pButton == &maJobPage.maSetupButton ) + { + maPController->setupPrinter( this ); + preparePreview( true, true ); + } + checkControlDependencies(); + } + return 0; +} + +IMPL_LINK( PrintDialog, ModifyHdl, Edit*, pEdit ) +{ + checkControlDependencies(); + if( pEdit == &maNUpPage.maNupRowsEdt || pEdit == &maNUpPage.maNupColEdt || + pEdit == &maNUpPage.maSheetMarginEdt || pEdit == &maNUpPage.maPageMarginEdt + ) + { + updateNupFromPages(); + } + else if( pEdit == &maPageEdit ) + { + mnCurPage = sal_Int32( maPageEdit.GetValue() - 1 ); + preparePreview( true, true ); + } + else if( pEdit == &maJobPage.maCopyCountField ) + { + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ), + makeAny( sal_Int32(maJobPage.maCopyCountField.GetValue()) ) ); + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ), + makeAny( sal_Bool(isCollate()) ) ); + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOptionsChanged, void*, EMPTYARG ) +{ + checkOptionalControlDependencies(); + return 0; +} + +PropertyValue* PrintDialog::getValueForWindow( Window* i_pWindow ) const +{ + PropertyValue* pVal = NULL; + std::map< Window*, rtl::OUString >::const_iterator it = maControlToPropertyMap.find( i_pWindow ); + if( it != maControlToPropertyMap.end() ) + { + pVal = maPController->getValue( it->second ); + DBG_ASSERT( pVal, "property value not found" ); + } + else + { + DBG_ERROR( "changed control not in property map" ); + } + return pVal; +} + +void PrintDialog::updateWindowFromProperty( const rtl::OUString& i_rProperty ) +{ + beans::PropertyValue* pValue = maPController->getValue( i_rProperty ); + std::map< rtl::OUString, std::vector< Window* > >::const_iterator it = maPropertyToWindowMap.find( i_rProperty ); + if( pValue && it != maPropertyToWindowMap.end() ) + { + const std::vector< Window* >& rWindows( it->second ); + if( ! rWindows.empty() ) + { + sal_Bool bVal = sal_False; + sal_Int32 nVal = -1; + if( pValue->Value >>= bVal ) + { + // we should have a CheckBox for this one + CheckBox* pBox = dynamic_cast< CheckBox* >( rWindows.front() ); + if( pBox ) + { + pBox->Check( bVal ); + } + else if( i_rProperty.equalsAscii( "PrintProspect" ) ) + { + // EVIL special case + if( bVal ) + maNUpPage.maBrochureBtn.Check(); + else + maNUpPage.maPagesBtn.Check(); + } + else + { + DBG_ASSERT( 0, "missing a checkbox" ); + } + } + else if( pValue->Value >>= nVal ) + { + // this could be a ListBox or a RadioButtonGroup + ListBox* pList = dynamic_cast< ListBox* >( rWindows.front() ); + if( pList ) + { + pList->SelectEntryPos( static_cast< USHORT >(nVal) ); + } + else if( nVal >= 0 && nVal < sal_Int32(rWindows.size() ) ) + { + RadioButton* pBtn = dynamic_cast< RadioButton* >( rWindows[nVal] ); + DBG_ASSERT( pBtn, "unexpected control for property" ); + if( pBtn ) + pBtn->Check(); + } + } + } + } +} + +void PrintDialog::makeEnabled( Window* i_pWindow ) +{ + std::map< Window*, rtl::OUString >::const_iterator it = maControlToPropertyMap.find( i_pWindow ); + if( it != maControlToPropertyMap.end() ) + { + rtl::OUString aDependency( maPController->makeEnabled( it->second ) ); + if( aDependency.getLength() ) + updateWindowFromProperty( aDependency ); + } +} + +IMPL_LINK( PrintDialog, UIOption_CheckHdl, CheckBox*, i_pBox ) +{ + PropertyValue* pVal = getValueForWindow( i_pBox ); + if( pVal ) + { + makeEnabled( i_pBox ); + + sal_Bool bVal = i_pBox->IsChecked(); + pVal->Value <<= bVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOption_RadioHdl, RadioButton*, i_pBtn ) +{ + // this handler gets called for all radiobuttons that get unchecked, too + // however we only want one notificaction for the new value (that is for + // the button that gets checked) + if( i_pBtn->IsChecked() ) + { + PropertyValue* pVal = getValueForWindow( i_pBtn ); + std::map< Window*, sal_Int32 >::const_iterator it = maControlToNumValMap.find( i_pBtn ); + if( pVal && it != maControlToNumValMap.end() ) + { + makeEnabled( i_pBtn ); + + sal_Int32 nVal = it->second; + pVal->Value <<= nVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOption_SelectHdl, ListBox*, i_pBox ) +{ + PropertyValue* pVal = getValueForWindow( i_pBox ); + if( pVal ) + { + makeEnabled( i_pBox ); + + sal_Int32 nVal( i_pBox->GetSelectEntryPos() ); + pVal->Value <<= nVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOption_ModifyHdl, Edit*, i_pBox ) +{ + PropertyValue* pVal = getValueForWindow( i_pBox ); + if( pVal ) + { + makeEnabled( i_pBox ); + + NumericField* pNum = dynamic_cast<NumericField*>(i_pBox); + MetricField* pMetric = dynamic_cast<MetricField*>(i_pBox); + if( pNum ) + { + sal_Int64 nVal = pNum->GetValue(); + pVal->Value <<= nVal; + } + else if( pMetric ) + { + sal_Int64 nVal = pMetric->GetValue(); + pVal->Value <<= nVal; + } + else + { + rtl::OUString aVal( i_pBox->GetText() ); + pVal->Value <<= aVal; + } + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + return 0; +} + +void PrintDialog::Command( const CommandEvent& rEvt ) +{ + if( rEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pWheelData = rEvt.GetWheelData(); + if( pWheelData->GetDelta() > 0 ) + previewForward(); + else if( pWheelData->GetDelta() < 0 ) + previewBackward(); + /* + else + huh ? + */ + } +} + +void PrintDialog::Resize() +{ + maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); + // and do the preview; however the metafile does not need to be gotten anew + preparePreview( false ); + + // do an invalidate for the benefit of the grouping elements + Invalidate(); +} + +void PrintDialog::previewForward() +{ + maPageEdit.Up(); +} + +void PrintDialog::previewBackward() +{ + maPageEdit.Down(); +} + +// ----------------------------------------------------------------------------- +// +// PrintProgressDialog +// +// ----------------------------------------------------------------------------- + +PrintProgressDialog::PrintProgressDialog( Window* i_pParent, int i_nMax ) : + ModelessDialog( i_pParent, VclResId( SV_DLG_PRINT_PROGRESS ) ), + maText( this, VclResId( SV_PRINT_PROGRESS_TEXT ) ), + maButton( this, VclResId( SV_PRINT_PROGRESS_CANCEL ) ), + mbCanceled( false ), + mnCur( 0 ), + mnMax( i_nMax ), + mnProgressHeight( 15 ), + mbNativeProgress( false ) +{ + FreeResource(); + + if( mnMax < 1 ) + mnMax = 1; + + maStr = maText.GetText(); + + maButton.SetClickHdl( LINK( this, PrintProgressDialog, ClickHdl ) ); + +} + +PrintProgressDialog::~PrintProgressDialog() +{ +} + +IMPL_LINK( PrintProgressDialog, ClickHdl, Button*, pButton ) +{ + if( pButton == &maButton ) + mbCanceled = true; + + return 0; +} + +void PrintProgressDialog::implCalcProgressRect() +{ + if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + ImplControlValue aValue; + Region aControlRegion( Rectangle( Point(), Size( 100, mnProgressHeight ) ) ); + Region aNativeControlRegion, aNativeContentRegion; + if( GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion, + CTRL_STATE_ENABLED, aValue, rtl::OUString(), + aNativeControlRegion, aNativeContentRegion ) ) + { + mnProgressHeight = aNativeControlRegion.GetBoundRect().GetHeight(); + } + mbNativeProgress = true; + } + maProgressRect = Rectangle( Point( 10, maText.GetPosPixel().Y() + maText.GetSizePixel().Height() + 8 ), + Size( GetSizePixel().Width() - 20, mnProgressHeight ) ); +} + +void PrintProgressDialog::setProgress( int i_nCurrent, int i_nMax ) +{ + if( maProgressRect.IsEmpty() ) + implCalcProgressRect(); + + mnCur = i_nCurrent; + if( i_nMax != -1 ) + mnMax = i_nMax; + + if( mnMax < 1 ) + mnMax = 1; + + rtl::OUString aNewText( searchAndReplace( maStr, "%p", 2, rtl::OUString::valueOf( mnCur ) ) ); + aNewText = searchAndReplace( aNewText, "%n", 2, rtl::OUString::valueOf( mnMax ) ); + maText.SetText( aNewText ); + + // update progress + Invalidate( maProgressRect, INVALIDATE_UPDATE ); +} + +void PrintProgressDialog::tick() +{ + if( mnCur < mnMax ) + setProgress( ++mnCur ); +} + +void PrintProgressDialog::Paint( const Rectangle& ) +{ + if( maProgressRect.IsEmpty() ) + implCalcProgressRect(); + + Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Color aPrgsColor = rStyleSettings.GetHighlightColor(); + if ( aPrgsColor == rStyleSettings.GetFaceColor() ) + aPrgsColor = rStyleSettings.GetDarkShadowColor(); + SetLineColor(); + SetFillColor( aPrgsColor ); + + const long nOffset = 3; + const long nWidth = 3*mnProgressHeight/2; + const long nFullWidth = nWidth + nOffset; + const long nMaxCount = maProgressRect.GetWidth() / nFullWidth; + DrawProgress( this, maProgressRect.TopLeft(), + nOffset, + nWidth, + mnProgressHeight, + static_cast<USHORT>(0), + static_cast<USHORT>(10000*mnCur/mnMax), + static_cast<USHORT>(10000/nMaxCount), + maProgressRect + ); + Pop(); + + if( ! mbNativeProgress ) + { + DecorationView aDecoView( this ); + Rectangle aFrameRect( maProgressRect ); + aFrameRect.Left() -= nOffset; + aFrameRect.Right() += nOffset; + aFrameRect.Top() -= nOffset; + aFrameRect.Bottom() += nOffset; + aDecoView.DrawFrame( aFrameRect ); + } +} + diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index bcf86c749673..ca0ebb10a4e9 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -698,6 +698,7 @@ void Window::ImplInitWindowData( WindowType nType ) mpWindowImpl->mbCallHandlersDuringInputDisabled = FALSE; // TRUE: call event handlers even if input is disabled mpWindowImpl->mbDisableAccessibleLabelForRelation = FALSE; // TRUE: do not set LabelFor relation on accessible objects mpWindowImpl->mbDisableAccessibleLabeledByRelation = FALSE; // TRUE: do not set LabeledBy relation on accessible objects + mpWindowImpl->mbHelpTextDynamic = FALSE; // TRUE: append help id in HELP_DEBUG case mbEnableRTL = Application::GetSettings().GetLayoutRTL(); // TRUE: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active } @@ -1279,7 +1280,10 @@ void Window::ImplLoadRes( const ResId& rResId ) if ( nObjMask & WINDOW_TEXT ) SetText( ReadStringRes() ); if ( nObjMask & WINDOW_HELPTEXT ) + { SetHelpText( ReadStringRes() ); + mpWindowImpl->mbHelpTextDynamic = TRUE; + } if ( nObjMask & WINDOW_QUICKTEXT ) SetQuickHelpText( ReadStringRes() ); if ( nObjMask & WINDOW_EXTRALONG ) @@ -8109,9 +8113,26 @@ const XubString& Window::GetHelpText() const ((Window*)this)->mpWindowImpl->maHelpText = pHelp->GetHelpText( aStrHelpId, this ); else ((Window*)this)->mpWindowImpl->maHelpText = pHelp->GetHelpText( nNumHelpId, this ); + mpWindowImpl->mbHelpTextDynamic = FALSE; } } } + else if( mpWindowImpl->mbHelpTextDynamic && (nNumHelpId || bStrHelpId) ) + { + static const char* pEnv = getenv( "HELP_DEBUG" ); + if( pEnv && *pEnv ) + { + rtl::OUStringBuffer aTxt( 64+mpWindowImpl->maHelpText.Len() ); + aTxt.append( mpWindowImpl->maHelpText ); + aTxt.appendAscii( "\n+++++++++++++++\n" ); + if( bStrHelpId ) + aTxt.append( rtl::OUString( aStrHelpId ) ); + else + aTxt.append( sal_Int32( nNumHelpId ) ); + mpWindowImpl->maHelpText = aTxt.makeStringAndClear(); + } + mpWindowImpl->mbHelpTextDynamic = FALSE; + } return mpWindowImpl->maHelpText; } diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx index d70f607a6cc6..a9bc93863829 100644 --- a/vcl/source/window/window2.cxx +++ b/vcl/source/window/window2.cxx @@ -1459,7 +1459,6 @@ ULONG Window::GetHelpId() const void Window::SetSmartHelpId( const SmartId& aId, SmartIdUpdateMode aMode ) { - mpWindowImpl->maHelpText = String(); // create SmartId if required if ( (aMode == SMART_SET_STR) || (aMode == SMART_SET_ALL) || ( (aMode == SMART_SET_SMART) && aId.HasString() ) ) { @@ -2000,6 +1999,7 @@ BOOL Window::IsZoom() const void Window::SetHelpText( const XubString& rHelpText ) { mpWindowImpl->maHelpText = rHelpText; + mpWindowImpl->mbHelpTextDynamic = TRUE; } void Window::SetQuickHelpText( const XubString& rHelpText ) diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx index f922552ce923..654f39c51a92 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -1091,6 +1091,19 @@ BOOL GtkSalGraphics::getNativeControlRegion( ControlType nType, rNativeContentRegion = Region( aIndicatorRect ); returnVal = TRUE; } + if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL ) + { + NWEnsureGTKEditBox( m_nScreen ); + GtkWidget* widget = gWidgetData[m_nScreen].gEditBoxWidget; + GtkRequisition aReq; + gtk_widget_size_request( widget, &aReq ); + Rectangle aEditRect = rControlRegion.GetBoundRect(); + aEditRect = Rectangle( aEditRect.TopLeft(), + Size( aEditRect.GetWidth(), aReq.height+1 ) ); + rNativeBoundingRegion = Region( aEditRect ); + rNativeContentRegion = rNativeBoundingRegion; + returnVal = TRUE; + } return( returnVal ); } diff --git a/vcl/unx/headless/svpprn.cxx b/vcl/unx/headless/svpprn.cxx index 1882b50e6ad7..75d86959b2b5 100644 --- a/vcl/unx/headless/svpprn.cxx +++ b/vcl/unx/headless/svpprn.cxx @@ -123,6 +123,32 @@ static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) pJobSetup->mnPaperBin = 0xffff; } + // copy duplex + pKey = NULL; + pValue = NULL; + + pJobSetup->meDuplexMode = DUPLEX_UNKNOWN; + if( rData.m_pParser ) + pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); + if( pKey ) + pValue = rData.m_aContext.getValue( pKey ); + if( pKey && pValue ) + { + if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) || + pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) + ) + { + pJobSetup->meDuplexMode = DUPLEX_OFF; + } + else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) ) + { + pJobSetup->meDuplexMode = DUPLEX_LONGEDGE; + } + else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) ) + { + pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE; + } + } // copy the whole context if( pJobSetup->mpDriverData ) @@ -455,34 +481,6 @@ void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) // ----------------------------------------------------------------------- -DuplexMode PspSalInfoPrinter::GetDuplexMode( const ImplJobSetup* pJobSetup ) -{ - DuplexMode aRet = DUPLEX_UNKNOWN; - PrinterInfo aInfo( PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName ) ); - if ( pJobSetup->mpDriverData ) - JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); - if( aInfo.m_pParser ) - { - const PPDKey * pKey = aInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); - if( pKey ) - { - const PPDValue* pVal = aInfo.m_aContext.getValue( pKey ); - if( pVal && ( - pVal->m_aOption.EqualsIgnoreCaseAscii( "None" ) || - pVal->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) - ) ) - { - aRet = DUPLEX_OFF; - } - else - aRet = DUPLEX_ON; - } - } - return aRet; -} - -// ----------------------------------------------------------------------- - int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* ) { return 900; @@ -624,6 +622,37 @@ BOOL PspSalInfoPrinter::SetData( if( nSetDataFlags & SAL_JOBSET_ORIENTATION ) aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait; + // merge duplex if necessary + if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE ) + { + pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); + if( pKey ) + { + pValue = NULL; + switch( pJobSetup->meDuplexMode ) + { + case DUPLEX_OFF: + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); + if( pValue == NULL ) + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) ); + break; + case DUPLEX_SHORTEDGE: + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) ); + break; + case DUPLEX_LONGEDGE: + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) ); + break; + case DUPLEX_UNKNOWN: + default: + pValue = 0; + break; + } + if( ! pValue ) + pValue = pKey->getDefaultValue(); + aData.m_aContext.setValue( pKey, pValue ); + } + } + m_aJobData = aData; copyJobDataToJobSetup( pJobSetup, aData ); return TRUE; @@ -725,9 +754,22 @@ ULONG PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, USHORT case PRINTER_CAPABILITIES_COPIES: return 0xffff; case PRINTER_CAPABILITIES_COLLATECOPIES: - return 0; + { + // see if the PPD contains a value to set Collate to True + JobData aData; + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); + + const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL; + const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL; + + // PPDs don't mention the number of possible collated copies. + // so let's guess as many as we want ? + return pVal ? 0xffff : 0; + } case PRINTER_CAPABILITIES_SETORIENTATION: return 1; + case PRINTER_CAPABILITIES_SETDUPLEX: + return 1; case PRINTER_CAPABILITIES_SETPAPERBIN: return 1; case PRINTER_CAPABILITIES_SETPAPERSIZE: @@ -777,6 +819,7 @@ PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter ) m_bSwallowFaxNo( false ), m_pGraphics( NULL ), m_nCopies( 1 ), + m_bCollate( false ), m_pInfoPrinter( pInfoPrinter ) { } @@ -802,7 +845,9 @@ BOOL PspSalPrinter::StartJob( const XubString* pFileName, const XubString& rJobName, const XubString& rAppName, - ULONG nCopies, BOOL /*bCollate*/, + ULONG nCopies, + bool bCollate, + bool /*bDirect*/, ImplJobSetup* pJobSetup ) { vcl_sal::PrinterUpdate::jobStarted(); @@ -811,13 +856,17 @@ BOOL PspSalPrinter::StartJob( m_bPdf = false; m_aFileName = pFileName ? *pFileName : String(); m_aTmpFile = String(); - m_nCopies = nCopies; + m_nCopies = nCopies; + m_bCollate = bCollate; JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); if( m_nCopies > 1 ) + { // in case user did not do anything (m_nCopies=1) // take the default from jobsetup m_aJobData.m_nCopies = m_nCopies; + m_aJobData.setCollate( bCollate ); + } // check wether this printer is configured as fax int nMode = 0; @@ -917,9 +966,12 @@ SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, BOOL ) m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter ); m_pGraphics->SetLayout( 0 ); if( m_nCopies > 1 ) + { // in case user did not do anything (m_nCopies=1) // take the default from jobsetup m_aJobData.m_nCopies = m_nCopies; + m_aJobData.setCollate( m_nCopies > 1 && m_bCollate ); + } m_aPrintJob.StartPage( m_aJobData ); m_aPrinterGfx.Init( m_aPrintJob ); diff --git a/vcl/unx/headless/svpprn.hxx b/vcl/unx/headless/svpprn.hxx index c2d85c054fce..8f5a47fed118 100644 --- a/vcl/unx/headless/svpprn.hxx +++ b/vcl/unx/headless/svpprn.hxx @@ -63,7 +63,6 @@ public: virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin ); virtual void InitPaperFormats( const ImplJobSetup* pSetupData ); virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ); - virtual DuplexMode GetDuplexMode( const ImplJobSetup* pSetupData ); }; class PspSalPrinter : public SalPrinter @@ -80,6 +79,7 @@ public: psp::JobData m_aJobData; psp::PrinterGfx m_aPrinterGfx; ULONG m_nCopies; + bool m_bCollate; SalInfoPrinter* m_pInfoPrinter; PspSalPrinter( SalInfoPrinter* ); @@ -90,7 +90,9 @@ public: virtual BOOL StartJob( const XubString* pFileName, const XubString& rJobName, const XubString& rAppName, - ULONG nCopies, BOOL bCollate, + ULONG nCopies, + bool bCollate, + bool bDirect, ImplJobSetup* pSetupData ); virtual BOOL EndJob(); virtual BOOL AbortJob(); diff --git a/vcl/unx/inc/salprn.h b/vcl/unx/inc/salprn.h index 452fa5a89387..59a5c3eef56a 100644 --- a/vcl/unx/inc/salprn.h +++ b/vcl/unx/inc/salprn.h @@ -63,7 +63,6 @@ public: virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin ); virtual void InitPaperFormats( const ImplJobSetup* pSetupData ); virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ); - virtual DuplexMode GetDuplexMode( const ImplJobSetup* pSetupData ); }; class PspSalPrinter : public SalPrinter @@ -80,6 +79,7 @@ public: psp::JobData m_aJobData; psp::PrinterGfx m_aPrinterGfx; ULONG m_nCopies; + bool m_bCollate; SalInfoPrinter* m_pInfoPrinter; PspSalPrinter( SalInfoPrinter* ); @@ -90,7 +90,9 @@ public: virtual BOOL StartJob( const XubString* pFileName, const XubString& rJobName, const XubString& rAppName, - ULONG nCopies, BOOL bCollate, + ULONG nCopies, + bool bCollate, + bool bDirect, ImplJobSetup* pSetupData ); virtual BOOL EndJob(); virtual BOOL AbortJob(); diff --git a/vcl/unx/source/gdi/salprnpsp.cxx b/vcl/unx/source/gdi/salprnpsp.cxx index 2cf4e3baedd3..d47e30a89633 100644 --- a/vcl/unx/source/gdi/salprnpsp.cxx +++ b/vcl/unx/source/gdi/salprnpsp.cxx @@ -177,6 +177,32 @@ static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) pJobSetup->mnPaperBin = 0; } + // copy duplex + pKey = NULL; + pValue = NULL; + + pJobSetup->meDuplexMode = DUPLEX_UNKNOWN; + if( rData.m_pParser ) + pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); + if( pKey ) + pValue = rData.m_aContext.getValue( pKey ); + if( pKey && pValue ) + { + if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) || + pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) + ) + { + pJobSetup->meDuplexMode = DUPLEX_OFF; + } + else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) ) + { + pJobSetup->meDuplexMode = DUPLEX_LONGEDGE; + } + else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) ) + { + pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE; + } + } // copy the whole context if( pJobSetup->mpDriverData ) @@ -525,34 +551,6 @@ void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) // ----------------------------------------------------------------------- -DuplexMode PspSalInfoPrinter::GetDuplexMode( const ImplJobSetup* pJobSetup ) -{ - DuplexMode aRet = DUPLEX_UNKNOWN; - PrinterInfo aInfo( PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName ) ); - if ( pJobSetup->mpDriverData ) - JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); - if( aInfo.m_pParser ) - { - const PPDKey * pKey = aInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); - if( pKey ) - { - const PPDValue* pVal = aInfo.m_aContext.getValue( pKey ); - if( pVal && ( - pVal->m_aOption.EqualsIgnoreCaseAscii( "None" ) || - pVal->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) - ) ) - { - aRet = DUPLEX_OFF; - } - else - aRet = DUPLEX_ON; - } - } - return aRet; -} - -// ----------------------------------------------------------------------- - int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* ) { return 900; @@ -727,6 +725,37 @@ BOOL PspSalInfoPrinter::SetData( if( nSetDataFlags & SAL_JOBSET_ORIENTATION ) aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait; + // merge duplex if necessary + if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE ) + { + pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); + if( pKey ) + { + pValue = NULL; + switch( pJobSetup->meDuplexMode ) + { + case DUPLEX_OFF: + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); + if( pValue == NULL ) + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) ); + break; + case DUPLEX_SHORTEDGE: + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) ); + break; + case DUPLEX_LONGEDGE: + pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) ); + break; + case DUPLEX_UNKNOWN: + default: + pValue = 0; + break; + } + if( ! pValue ) + pValue = pKey->getDefaultValue(); + aData.m_aContext.setValue( pKey, pValue ); + } + } + m_aJobData = aData; copyJobDataToJobSetup( pJobSetup, aData ); return TRUE; @@ -828,9 +857,22 @@ ULONG PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, USHORT case PRINTER_CAPABILITIES_COPIES: return 0xffff; case PRINTER_CAPABILITIES_COLLATECOPIES: - return 0; + { + // see if the PPD contains a value to set Collate to True + JobData aData; + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); + + const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL; + const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL; + + // PPDs don't mention the number of possible collated copies. + // so let's guess as many as we want ? + return pVal ? 0xffff : 0; + } case PRINTER_CAPABILITIES_SETORIENTATION: return 1; + case PRINTER_CAPABILITIES_SETDUPLEX: + return 1; case PRINTER_CAPABILITIES_SETPAPERBIN: return 1; case PRINTER_CAPABILITIES_SETPAPERSIZE: @@ -860,6 +902,7 @@ ULONG PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, USHORT m_bSwallowFaxNo( false ), m_pGraphics( NULL ), m_nCopies( 1 ), + m_bCollate( false ), m_pInfoPrinter( pInfoPrinter ) { } @@ -885,7 +928,9 @@ BOOL PspSalPrinter::StartJob( const XubString* pFileName, const XubString& rJobName, const XubString& rAppName, - ULONG nCopies, BOOL /*bCollate*/, + ULONG nCopies, + bool bCollate, + bool bDirect, ImplJobSetup* pJobSetup ) { vcl_sal::PrinterUpdate::jobStarted(); @@ -894,13 +939,17 @@ BOOL PspSalPrinter::StartJob( m_bPdf = false; m_aFileName = pFileName ? *pFileName : String(); m_aTmpFile = String(); - m_nCopies = nCopies; + m_nCopies = nCopies; + m_bCollate = bCollate; JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); if( m_nCopies > 1 ) + { // in case user did not do anything (m_nCopies=1) // take the default from jobsetup m_aJobData.m_nCopies = m_nCopies; + m_aJobData.setCollate( bCollate ); + } // check wether this printer is configured as fax int nMode = 0; @@ -943,15 +992,6 @@ BOOL PspSalPrinter::StartJob( } m_aPrinterGfx.Init( m_aJobData ); - bool bIsQuickJob = false; - std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator quick_it = - pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ) ); - if( quick_it != pJobSetup->maValueMap.end() ) - { - if( quick_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) - bIsQuickJob = true; - } - // set/clear backwards compatibility flag bool bStrictSO52Compatibility = false; std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = @@ -964,7 +1004,7 @@ BOOL PspSalPrinter::StartJob( } m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); - return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bIsQuickJob ) ? TRUE : FALSE; + return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? TRUE : FALSE; } // ----------------------------------------------------------------------- @@ -1010,9 +1050,12 @@ SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, BOOL ) m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter ); m_pGraphics->SetLayout( 0 ); if( m_nCopies > 1 ) + { // in case user did not do anything (m_nCopies=1) // take the default from jobsetup m_aJobData.m_nCopies = m_nCopies; + m_aJobData.setCollate( m_nCopies > 1 && m_bCollate ); + } m_aPrintJob.StartPage( m_aJobData ); m_aPrinterGfx.Init( m_aPrintJob ); diff --git a/vcl/unx/source/printer/jobdata.cxx b/vcl/unx/source/printer/jobdata.cxx index 51e171d578d9..0410b349c93b 100644 --- a/vcl/unx/source/printer/jobdata.cxx +++ b/vcl/unx/source/printer/jobdata.cxx @@ -64,6 +64,28 @@ JobData& JobData::operator=(const JobData& rRight) return *this; } +void JobData::setCollate( bool bCollate ) +{ + const PPDParser* pParser = m_aContext.getParser(); + if( pParser ) + { + const PPDKey* pKey = pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ); + if( pKey ) + { + const PPDValue* pVal = NULL; + if( bCollate ) + pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ); + else + { + pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) ); + if( ! pVal ) + pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); + } + m_aContext.setValue( pKey, pVal ); + } + } +} + bool JobData::getStreamBuffer( void*& pData, int& bytes ) { // consistency checks diff --git a/vcl/unx/source/printergfx/printerjob.cxx b/vcl/unx/source/printergfx/printerjob.cxx index 783dd5ff2b47..1c42cafa4cb9 100644 --- a/vcl/unx/source/printergfx/printerjob.cxx +++ b/vcl/unx/source/printergfx/printerjob.cxx @@ -681,14 +681,6 @@ PrinterJob::StartPage (const JobData& rJobSetup) if( ! (pPageHeader && pPageBody) ) return sal_False; - /* #i7262# write setup only before first page - * don't do this in StartJob since the jobsetup there may be - * different. - */ - bool bSuccess = true; - if( 1 == maPageList.size() ) - m_aDocumentJobData = rJobSetup; - // write page header according to Document Structuring Conventions (DSC) WritePS (pPageHeader, "%%Page: "); WritePS (pPageHeader, aPageNo); @@ -722,13 +714,25 @@ PrinterJob::StartPage (const JobData& rJobSetup) WritePS (pPageHeader, pBBox); - if (bSuccess) - bSuccess = writePageSetup ( pPageHeader, rJobSetup ); - if(bSuccess) - m_aLastJobData = rJobSetup; + /* #i7262# #i65491# write setup only before first page + * (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup) + * don't do this in StartJob since the jobsetup there may be + * different. + */ + bool bWriteFeatures = true; + if( 1 == maPageList.size() ) + { + m_aDocumentJobData = rJobSetup; + bWriteFeatures = false; + } + if ( writePageSetup( pPageHeader, rJobSetup, bWriteFeatures ) ) + { + m_aLastJobData = rJobSetup; + return true; + } - return bSuccess; + return false; } sal_Bool @@ -828,12 +832,9 @@ bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool b if( pKey->getSetupType() == PPDKey::DocumentSetup ) bEmit = true; } - else - { - if( pKey->getSetupType() == PPDKey::PageSetup || - pKey->getSetupType() == PPDKey::AnySetup ) - bEmit = true; - } + if( pKey->getSetupType() == PPDKey::PageSetup || + pKey->getSetupType() == PPDKey::AnySetup ) + bEmit = true; if( bEmit ) { const PPDValue* pValue = rJob.m_aContext.getValue( pKey ); @@ -866,13 +867,13 @@ bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool b return bSuccess; } -bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob ) +bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob, bool bWriteFeatures ) { bool bSuccess = true; WritePS (pFile, "%%BeginPageSetup\n%\n"); - - bSuccess = writeFeatureList( pFile, rJob, false ); + if ( bWriteFeatures ) + bSuccess = writeFeatureList( pFile, rJob, false ); WritePS (pFile, "%%EndPageSetup\n"); sal_Char pTranslate [128]; diff --git a/vcl/util/hidother.src b/vcl/util/hidother.src new file mode 100644 index 000000000000..ab10a1e4c4ea --- /dev/null +++ b/vcl/util/hidother.src @@ -0,0 +1,34 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: hidother.src,v $ + * $Revision: 1.20 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "vcl/svids.hrc" + +hidspecial HID_PRINTDLG { HelpID = HID_PRINTDLG; }; + diff --git a/vcl/util/makefile.mk b/vcl/util/makefile.mk index ef4f13301ecd..c5a99d47c709 100644 --- a/vcl/util/makefile.mk +++ b/vcl/util/makefile.mk @@ -31,6 +31,7 @@ PRJNAME=vcl TARGET=vcl TARGETTYPE=GUI USE_DEFFILE=TRUE +GEN_HID_OTHER=TRUE .IF "$(SNDFILE_LIBS)"!="" SNDFILELIB=$(SNDFILE_LIBS) diff --git a/vcl/win/inc/salprn.h b/vcl/win/inc/salprn.h index 58d721fd043a..890ff70bc3d6 100644 --- a/vcl/win/inc/salprn.h +++ b/vcl/win/inc/salprn.h @@ -88,7 +88,6 @@ public: virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin ); virtual void InitPaperFormats( const ImplJobSetup* pSetupData ); virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ); - virtual DuplexMode GetDuplexMode( const ImplJobSetup* pSetupData ); }; // ----------------- @@ -117,7 +116,9 @@ public: virtual BOOL StartJob( const XubString* pFileName, const XubString& rJobName, const XubString& rAppName, - ULONG nCopies, BOOL bCollate, + ULONG nCopies, + bool bCollate, + bool bDirect, ImplJobSetup* pSetupData ); virtual BOOL EndJob(); virtual BOOL AbortJob(); diff --git a/vcl/win/source/gdi/salnativewidgets-luna.cxx b/vcl/win/source/gdi/salnativewidgets-luna.cxx index 5a5703e10944..5c85d5d67144 100644 --- a/vcl/win/source/gdi/salnativewidgets-luna.cxx +++ b/vcl/win/source/gdi/salnativewidgets-luna.cxx @@ -337,7 +337,7 @@ BOOL ImplDrawTheme( HTHEME hTheme, HDC hDC, int iPart, int iState, RECT rc, cons } -Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const Rectangle& aRect ) +Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const Rectangle& aRect, THEMESIZE eTS = TS_TRUE ) { SIZE aSz; RECT rc; @@ -345,7 +345,7 @@ Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const rc.right = aRect.nRight; rc.top = aRect.nTop; rc.bottom = aRect.nBottom; - HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, NULL, TS_TRUE, &aSz ); // TS_TRUE returns optimal size + HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, NULL, eTS, &aSz ); // TS_TRUE returns optimal size if( hr == S_OK ) return Rectangle( 0, 0, aSz.cx, aSz.cy ); else @@ -1109,6 +1109,63 @@ BOOL WinSalGraphics::getNativeControlRegion( ControlType nType, bRet = TRUE; } } + + if( (nType == CTRL_LISTBOX || nType == CTRL_COMBOBOX ) && nPart == PART_ENTIRE_CONTROL ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Combobox"); + if( hTheme ) + { + Rectangle aBoxRect( rControlRegion.GetBoundRect() ); + Rectangle aRect( ImplGetThemeRect( hTheme, hDC, CP_DROPDOWNBUTTON, + CBXS_NORMAL, aBoxRect ) ); + Rectangle aBrdRect( ImplGetThemeRect( hTheme, hDC, CP_BORDER, + CBB_HOT, aBoxRect ) ); + aRect.Top() -= aBrdRect.GetHeight(); + if( aRect.GetHeight() > aBoxRect.GetHeight() ) + aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight(); + if( aRect.GetWidth() > aBoxRect.GetWidth() ) + aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth(); + rNativeContentRegion = aBoxRect; + rNativeBoundingRegion = rNativeContentRegion; + if( !aRect.IsEmpty() ) + bRet = TRUE; + } + } + + if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Edit"); + if( hTheme ) + { + // get borderr size + Rectangle aBoxRect( rControlRegion.GetBoundRect() ); + Rectangle aRect( ImplGetThemeRect( hTheme, hDC, EP_BACKGROUNDWITHBORDER, + EBWBS_HOT, aBoxRect ) ); + // ad app font height + NONCLIENTMETRICSW aNonClientMetrics; + aNonClientMetrics.cbSize = sizeof( aNonClientMetrics ); + if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) ) + { + long nFontHeight = aNonClientMetrics.lfMessageFont.lfHeight; + if( nFontHeight < 0 ) + nFontHeight = -nFontHeight; + + if( aRect.GetHeight() && nFontHeight ) + { + aRect.Bottom() += aRect.GetHeight(); + aRect.Bottom() += nFontHeight; + if( aRect.GetHeight() > aBoxRect.GetHeight() ) + aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight(); + if( aRect.GetWidth() > aBoxRect.GetWidth() ) + aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth(); + rNativeContentRegion = aBoxRect; + rNativeBoundingRegion = rNativeContentRegion; + bRet = TRUE; + } + } + } + } + ReleaseDC( mhWnd, hDC ); return( bRet ); } diff --git a/vcl/win/source/gdi/salprn.cxx b/vcl/win/source/gdi/salprn.cxx index ecf91aea7c1b..f4f55dd0adbf 100644 --- a/vcl/win/source/gdi/salprn.cxx +++ b/vcl/win/source/gdi/salprn.cxx @@ -1059,6 +1059,21 @@ static void ImplDevModeToJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pS break; } } + + if( nFlags & SAL_JOBSET_DUPLEXMODE ) + { + DuplexMode eDuplex = DUPLEX_UNKNOWN; + if( (CHOOSE_DEVMODE(dmFields) & DM_DUPLEX) ) + { + if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_SIMPLEX ) + eDuplex = DUPLEX_OFF; + else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_VERTICAL ) + eDuplex = DUPLEX_LONGEDGE; + else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_HORIZONTAL ) + eDuplex = DUPLEX_SHORTEDGE; + } + pSetupData->meDuplexMode = eDuplex; + } } // ----------------------------------------------------------------------- @@ -1326,6 +1341,26 @@ static void ImplJobSetupToDevMode( WinSalInfoPrinter* pPrinter, ImplJobSetup* pS } } } + if( (nFlags & SAL_JOBSET_DUPLEXMODE) ) + { + switch( pSetupData->meDuplexMode ) + { + case DUPLEX_OFF: + CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX; + CHOOSE_DEVMODE(dmDuplex) = DMDUP_SIMPLEX; + break; + case DUPLEX_SHORTEDGE: + CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX; + CHOOSE_DEVMODE(dmDuplex) = DMDUP_HORIZONTAL; + break; + case DUPLEX_LONGEDGE: + CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX; + CHOOSE_DEVMODE(dmDuplex) = DMDUP_VERTICAL; + break; + case DUPLEX_UNKNOWN: + break; + } + } } // ----------------------------------------------------------------------- @@ -1559,39 +1594,6 @@ void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData ) // ----------------------------------------------------------------------- -DuplexMode WinSalInfoPrinter::GetDuplexMode( const ImplJobSetup* pSetupData ) -{ - DuplexMode nRet = DUPLEX_UNKNOWN; - if ( pSetupData &&pSetupData->mpDriverData ) - { - if( aSalShlData.mbWPrinter ) - { - DEVMODEW* pDevMode = SAL_DEVMODE_W( pSetupData ); - if ( pDevMode && (pDevMode->dmFields & DM_DUPLEX )) - { - if ( pDevMode->dmDuplex == DMDUP_SIMPLEX ) - nRet = DUPLEX_OFF; - else - nRet = DUPLEX_ON; - } - } - else - { - DEVMODEA* pDevMode = SAL_DEVMODE_A( pSetupData ); - if ( pDevMode && (pDevMode->dmFields & DM_DUPLEX )) - { - if ( pDevMode->dmDuplex == DMDUP_SIMPLEX ) - nRet = DUPLEX_OFF; - else - nRet = DUPLEX_ON; - } - } - } - return nRet; -} - -// ----------------------------------------------------------------------- - int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData ) { int nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData ); @@ -1964,7 +1966,9 @@ static int lcl_StartDocA( HDC hDC, DOCINFOA* pInfo, WinSalPrinter* pPrt ) BOOL WinSalPrinter::StartJob( const XubString* pFileName, const XubString& rJobName, const XubString&, - ULONG nCopies, BOOL bCollate, + ULONG nCopies, + bool bCollate, + bool /*bDirect*/, ImplJobSetup* pSetupData ) { mnError = 0; |