diff options
183 files changed, 12452 insertions, 2508 deletions
diff --git a/basegfx/inc/basegfx/matrix/b2dhommatrix.hxx b/basegfx/inc/basegfx/matrix/b2dhommatrix.hxx index c7c79d0cd6e9..10b023c5f68c 100644 --- a/basegfx/inc/basegfx/matrix/b2dhommatrix.hxx +++ b/basegfx/inc/basegfx/matrix/b2dhommatrix.hxx @@ -52,12 +52,22 @@ namespace basegfx B2DHomMatrix(const B2DHomMatrix& rMat); ~B2DHomMatrix(); + /** constructor to allow setting all needed values for a 3x2 matrix at once. The + parameter f_0x1 e.g. is the same as using set(0, 1, f) + */ + B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2); + /// unshare this matrix with all internally shared instances void makeUnique(); double get(sal_uInt16 nRow, sal_uInt16 nColumn) const; void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue); + /** allow setting all needed values for a 3x2 matrix in one call. The + parameter f_0x1 e.g. is the same as using set(0, 1, f) + */ + void set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2); + // test if last line is default to see if last line needs to be // involved in calculations bool isLastLineDefault() const; diff --git a/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx b/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx index 0b200b812bed..c90f673a8194 100644 --- a/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx +++ b/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx @@ -40,45 +40,190 @@ namespace basegfx { - class DecomposedB2DHomMatrixContainer + namespace tools { - private: - B2DHomMatrix maB2DHomMatrix; - B2DVector maScale; - B2DVector maTranslate; - double mfRotate; - double mfShearX; + /** If the rotation angle is an approximate multiple of pi/2, + force fSin/fCos to -1/0/1, to maintain orthogonality (which + might also be advantageous for the other cases, but: for + multiples of pi/2, the exact values _can_ be attained. It + would be largely unintuitive, if a 180 degrees rotation + would introduce slight roundoff errors, instead of exactly + mirroring the coordinate system) + */ + void createSinCosOrthogonal(double& o_rSin, double& rCos, double fRadiant); - // bitfield - unsigned mbDecomposed : 1; + /** Tooling methods for on-the-fly matrix generation e.g. for inline + multiplications + */ + B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY); + B2DHomMatrix createShearXB2DHomMatrix(double fShearX); + B2DHomMatrix createShearYB2DHomMatrix(double fShearY); + B2DHomMatrix createRotateB2DHomMatrix(double fRadiant); + B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY); - void impCheckDecompose() + /// inline versions for parameters as tuples + inline B2DHomMatrix createScaleB2DHomMatrix(const B2DTuple& rScale) { - if(!mbDecomposed) - { - maB2DHomMatrix.decompose(maScale, maTranslate, mfRotate, mfShearX); - mbDecomposed = true; - } + return createScaleB2DHomMatrix(rScale.getX(), rScale.getY()); + } + + inline B2DHomMatrix createTranslateB2DHomMatrix(const B2DTuple& rTranslate) + { + return createTranslateB2DHomMatrix(rTranslate.getX(), rTranslate.getY()); + } + + /** Tooling methods for faster completely combined matrix creation + when scale, shearX, rotation and translation needs to be done in + exactly that order. It's faster since it direcly calculates + each matrix value based on a symbolic calculation of the three + matrix multiplications. + Inline versions for parameters as tuples added, too. + */ + B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix( + double fScaleX, double fScaleY, + double fShearX, + double fRadiant, + double fTranslateX, double fTranslateY); + inline B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix( + const B2DTuple& rScale, + double fShearX, + double fRadiant, + const B2DTuple& rTranslate) + { + return createScaleShearXRotateTranslateB2DHomMatrix( + rScale.getX(), rScale.getY(), + fShearX, + fRadiant, + rTranslate.getX(), rTranslate.getY()); + } + + B2DHomMatrix createShearXRotateTranslateB2DHomMatrix( + double fShearX, + double fRadiant, + double fTranslateX, double fTranslateY); + inline B2DHomMatrix createShearXRotateTranslateB2DHomMatrix( + double fShearX, + double fRadiant, + const B2DTuple& rTranslate) + { + return createShearXRotateTranslateB2DHomMatrix( + fShearX, + fRadiant, + rTranslate.getX(), rTranslate.getY()); } - public: - DecomposedB2DHomMatrixContainer(const B2DHomMatrix& rB2DHomMatrix) - : maB2DHomMatrix(rB2DHomMatrix), - maScale(), - maTranslate(), - mfRotate(0.0), - mfShearX(0.0), - mbDecomposed(false) + B2DHomMatrix createScaleTranslateB2DHomMatrix( + double fScaleX, double fScaleY, + double fTranslateX, double fTranslateY); + inline B2DHomMatrix createScaleTranslateB2DHomMatrix( + const B2DTuple& rScale, + const B2DTuple& rTranslate) { + return createScaleTranslateB2DHomMatrix( + rScale.getX(), rScale.getY(), + rTranslate.getX(), rTranslate.getY()); } - // data access - const B2DHomMatrix& getB2DHomMatrix() const { return maB2DHomMatrix; } - const B2DVector& getScale() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return maScale; } - const B2DVector& getTranslate() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return maTranslate; } - double getRotate() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfRotate; } - double getShearX() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfShearX; } - }; + /// special for the often used case of rotation around a point + B2DHomMatrix createRotateAroundPoint( + double fPointX, double fPointY, + double fRadiant); + inline B2DHomMatrix createRotateAroundPoint( + const B2DTuple& rPoint, + double fRadiant) + { + return createRotateAroundPoint( + rPoint.getX(), rPoint.getY(), + fRadiant); + } + } // end of namespace tools +} // end of namespace basegfx + +/////////////////////////////////////////////////////////////////////////////// + +namespace basegfx +{ + namespace tools + { + class B2DHomMatrixBufferedDecompose + { + private: + B2DVector maScale; + B2DVector maTranslate; + double mfRotate; + double mfShearX; + + public: + B2DHomMatrixBufferedDecompose(const B2DHomMatrix& rB2DHomMatrix) + : maScale(), + maTranslate(), + mfRotate(0.0), + mfShearX(0.0) + { + rB2DHomMatrix.decompose(maScale, maTranslate, mfRotate, mfShearX); + } + + // data access + B2DHomMatrix getB2DHomMatrix() const + { + return createScaleShearXRotateTranslateB2DHomMatrix( + maScale, mfShearX, mfRotate, maTranslate); + } + + const B2DVector& getScale() const { return maScale; } + const B2DVector& getTranslate() const { return maTranslate; } + double getRotate() const { return mfRotate; } + double getShearX() const { return mfShearX; } + }; + } // end of namespace tools +} // end of namespace basegfx + +/////////////////////////////////////////////////////////////////////////////// + +namespace basegfx +{ + namespace tools + { + class B2DHomMatrixBufferedOnDemandDecompose + { + private: + B2DHomMatrix maB2DHomMatrix; + B2DVector maScale; + B2DVector maTranslate; + double mfRotate; + double mfShearX; + + // bitfield + unsigned mbDecomposed : 1; + + void impCheckDecompose() + { + if(!mbDecomposed) + { + maB2DHomMatrix.decompose(maScale, maTranslate, mfRotate, mfShearX); + mbDecomposed = true; + } + } + + public: + B2DHomMatrixBufferedOnDemandDecompose(const B2DHomMatrix& rB2DHomMatrix) + : maB2DHomMatrix(rB2DHomMatrix), + maScale(), + maTranslate(), + mfRotate(0.0), + mfShearX(0.0), + mbDecomposed(false) + { + } + + // data access + const B2DHomMatrix& getB2DHomMatrix() const { return maB2DHomMatrix; } + const B2DVector& getScale() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maScale; } + const B2DVector& getTranslate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maTranslate; } + double getRotate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfRotate; } + double getShearX() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfShearX; } + }; + } // end of namespace tools } // end of namespace basegfx /////////////////////////////////////////////////////////////////////////////// diff --git a/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx b/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx index 5eff6b0b9cc1..47ff41b75e70 100644 --- a/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx +++ b/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx @@ -288,14 +288,6 @@ namespace basegfx */ B2DPolygon createPolygonFromCircle( const B2DPoint& rCenter, double fRadius ); - /** append a unit circle with one point and the control vectors to the given polygon - */ - void appendUnitCircleQuadrant(B2DPolygon& rPolygon, sal_uInt32 nQuadrant, bool bEndPoint); - - /** append a segment of unit circle with one point and the control vectors to the given polygon - */ - void appendUnitCircleQuadrantSegment(B2DPolygon& rPolygon, sal_uInt32 nQuadrant, double fStart, double fEnd, bool bEndPoint); - /** create a polygon which describes the unit circle and close it @param nStartQuadrant @@ -325,59 +317,6 @@ namespace basegfx */ B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY ); - /** append a unit circle with one point and the control vectors to the given polygon - */ - void appendUnitCircleQuadrant(B2DPolygon& rPolygon, sal_uInt32 nQuadrant); - - /** append a segment of unit circle with start point, the control vectors and end point to the given polygon - */ - void appendUnitCircleQuadrantSegment(B2DPolygon& rPolygon, sal_uInt32 nQuadrant, double fStart, double fEnd); - - /** Create an ellipse polygon with given radii. - - This method creates an ellipse approximation consisting of - four cubic bezier segments, which approximate the given - ellipse with an error of less than 0.5 percent. - - @param rCenter - Center point of the circle - - @param fRadiusX - Radius of the ellipse in X direction - - @param fRadiusY - Radius of the ellipse in Y direction - - @param fStart - Start angle where the ellipe segment starts in the range [0.0 .. 2PI[ - - @param fEnd - End angle where the ellipe segment ends in the range [0.0 .. 2PI[ - */ - B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY ); - - /** Create an ellipse polygon with given radii and the given angles, from start to end - - This method creates an ellipse approximation consisting of - four cubic bezier segments, which approximate the given - ellipse with an error of less than 0.5 percent. - - @param rCenter - Center point of the circle - - @param fRadiusX - Radius of the ellipse in X direction - - @param fRadiusY - Radius of the ellipse in Y direction - - @param fStart - Start angle where the ellipe segment starts in the range [0.0 .. 2PI[ - - @param fEnd - End angle where the ellipe segment ends in the range [0.0 .. 2PI[ - */ - /** Create an unit ellipse polygon with the given angles, from start to end */ B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd ); diff --git a/basegfx/source/matrix/b2dhommatrix.cxx b/basegfx/source/matrix/b2dhommatrix.cxx index 352113fa8ed3..a7777352effb 100644 --- a/basegfx/source/matrix/b2dhommatrix.cxx +++ b/basegfx/source/matrix/b2dhommatrix.cxx @@ -36,6 +36,9 @@ #include <hommatrixtemplate.hxx> #include <basegfx/tuple/b2dtuple.hxx> #include <basegfx/vector/b2dvector.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +/////////////////////////////////////////////////////////////////////////////// namespace basegfx { @@ -60,6 +63,17 @@ namespace basegfx { } + B2DHomMatrix::B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2) + : mpImpl( IdentityMatrix::get() ) // use common identity matrix, will be made unique with 1st set-call + { + mpImpl->set(0, 0, f_0x0); + mpImpl->set(0, 1, f_0x1); + mpImpl->set(0, 2, f_0x2); + mpImpl->set(1, 0, f_1x0); + mpImpl->set(1, 1, f_1x1); + mpImpl->set(1, 2, f_1x2); + } + B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix& rMat) { mpImpl = rMat.mpImpl; @@ -81,6 +95,16 @@ namespace basegfx mpImpl->set(nRow, nColumn, fValue); } + void B2DHomMatrix::set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2) + { + mpImpl->set(0, 0, f_0x0); + mpImpl->set(0, 1, f_0x1); + mpImpl->set(0, 2, f_0x2); + mpImpl->set(1, 0, f_1x0); + mpImpl->set(1, 1, f_1x1); + mpImpl->set(1, 2, f_1x2); + } + bool B2DHomMatrix::isLastLineDefault() const { return mpImpl->isLastLineDefault(); @@ -206,56 +230,9 @@ namespace basegfx if(!fTools::equalZero(fRadiant)) { double fSin(0.0); - double fCos(0.0); - - // is the rotation angle an approximate multiple of pi/2? - // If yes, force fSin/fCos to -1/0/1, to maintain - // orthogonality (which might also be advantageous for the - // other cases, but: for multiples of pi/2, the exact - // values _can_ be attained. It would be largely - // unintuitive, if a 180 degrees rotation would introduce - // slight roundoff errors, instead of exactly mirroring - // the coordinate system). - if( fTools::equalZero( fmod( fRadiant, F_PI2 ) ) ) - { - // determine quadrant - const sal_Int32 nQuad( - (4 + fround( 4/F_2PI*fmod( fRadiant, F_2PI ) )) % 4 ); - switch( nQuad ) - { - case 0: // -2pi,0,2pi - fSin = 0.0; - fCos = 1.0; - break; - - case 1: // -3/2pi,1/2pi - fSin = 1.0; - fCos = 0.0; - break; - - case 2: // -pi,pi - fSin = 0.0; - fCos = -1.0; - break; - - case 3: // -1/2pi,3/2pi - fSin = -1.0; - fCos = 0.0; - break; - - default: - OSL_ENSURE( false, - "B2DHomMatrix::rotate(): Impossible case reached" ); - } - } - else - { - // TODO(P1): Maybe use glibc's sincos here (though - // that's kinda non-portable...) - fSin = sin(fRadiant); - fCos = cos(fRadiant); - } + double fCos(1.0); + tools::createSinCosOrthogonal(fSin, fCos, fRadiant); Impl2DHomMatrix aRotMat; aRotMat.set(0, 0, fCos); @@ -474,104 +451,7 @@ namespace basegfx return true; } - -/* Old version: Used 3D decompose when shaer was involved and also a determinant test - (but only in that case). Keeping as comment since it also worked and to allow a - fallback in case the new version makes trouble somehow. Definitely missing in the 2nd - case is the sign correction for Y-Scale, this would need to be added following the above - pattern - - bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const - { - // when perspective is used, decompose is not made here - if(!mpImpl->isLastLineDefault()) - return false; - - // test for rotation and shear - if(fTools::equalZero(get(0, 1)) - && fTools::equalZero(get(1, 0))) - { - // no rotation and shear, direct value extraction - rRotate = rShearX = 0.0; - - // copy scale values - rScale.setX(get(0, 0)); - rScale.setY(get(1, 1)); - - // copy translation values - rTranslate.setX(get(0, 2)); - rTranslate.setY(get(1, 2)); - - return true; - } - else - { - // test if shear is zero. That's the case, if the unit vectors in the matrix - // are perpendicular -> scalar is zero - const ::basegfx::B2DVector aUnitVecX(get(0, 0), get(1, 0)); - const ::basegfx::B2DVector aUnitVecY(get(0, 1), get(1, 1)); - - if(fTools::equalZero(aUnitVecX.scalar(aUnitVecY))) - { - // no shear, direct value extraction - rShearX = 0.0; - - // calculate rotation - rShearX = 0.0; - rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX()); - - // calculate scale values - rScale.setX(aUnitVecX.getLength()); - rScale.setY(aUnitVecY.getLength()); - - // copy translation values - rTranslate.setX(get(0, 2)); - rTranslate.setY(get(1, 2)); - - return true; - } - else - { - // If determinant is zero, decomposition is not possible - if(0.0 == determinant()) - return false; - - // copy 2x2 matrix and translate vector to 3x3 matrix - ::basegfx::B3DHomMatrix a3DHomMat; - - a3DHomMat.set(0, 0, get(0, 0)); - a3DHomMat.set(0, 1, get(0, 1)); - a3DHomMat.set(1, 0, get(1, 0)); - a3DHomMat.set(1, 1, get(1, 1)); - a3DHomMat.set(0, 3, get(0, 2)); - a3DHomMat.set(1, 3, get(1, 2)); - - ::basegfx::B3DTuple r3DScale, r3DTranslate, r3DRotate, r3DShear; - - if(a3DHomMat.decompose(r3DScale, r3DTranslate, r3DRotate, r3DShear)) - { - // copy scale values - rScale.setX(r3DScale.getX()); - rScale.setY(r3DScale.getY()); - - // copy shear - rShearX = r3DShear.getX(); - - // copy rotate - rRotate = r3DRotate.getZ(); - - // copy translate - rTranslate.setX(r3DTranslate.getX()); - rTranslate.setY(r3DTranslate.getY()); - - return true; - } - } - } - - return false; - } */ - } // end of namespace basegfx +/////////////////////////////////////////////////////////////////////////////// // eof diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx index 59a1ff432fc7..2c71193f6352 100644 --- a/basegfx/source/matrix/b2dhommatrixtools.cxx +++ b/basegfx/source/matrix/b2dhommatrixtools.cxx @@ -38,6 +38,339 @@ namespace basegfx { + namespace tools + { + void createSinCosOrthogonal(double& o_rSin, double& o_rCos, double fRadiant) + { + if( fTools::equalZero( fmod( fRadiant, F_PI2 ) ) ) + { + // determine quadrant + const sal_Int32 nQuad( + (4 + fround( 4/F_2PI*fmod( fRadiant, F_2PI ) )) % 4 ); + switch( nQuad ) + { + case 0: // -2pi,0,2pi + o_rSin = 0.0; + o_rCos = 1.0; + break; + + case 1: // -3/2pi,1/2pi + o_rSin = 1.0; + o_rCos = 0.0; + break; + + case 2: // -pi,pi + o_rSin = 0.0; + o_rCos = -1.0; + break; + + case 3: // -1/2pi,3/2pi + o_rSin = -1.0; + o_rCos = 0.0; + break; + + default: + OSL_ENSURE( false, "createSinCos: Impossible case reached" ); + } + } + else + { + // TODO(P1): Maybe use glibc's sincos here (though + // that's kinda non-portable...) + o_rSin = sin(fRadiant); + o_rCos = cos(fRadiant); + } + } + + B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY) + { + B2DHomMatrix aRetval; + const double fOne(1.0); + + if(!fTools::equal(fScaleX, fOne)) + { + aRetval.set(0, 0, fScaleX); + } + + if(!fTools::equal(fScaleY, fOne)) + { + aRetval.set(1, 1, fScaleY); + } + + return aRetval; + } + + B2DHomMatrix createShearXB2DHomMatrix(double fShearX) + { + B2DHomMatrix aRetval; + + if(!fTools::equalZero(fShearX)) + { + aRetval.set(0, 1, fShearX); + } + + return aRetval; + } + + B2DHomMatrix createShearYB2DHomMatrix(double fShearY) + { + B2DHomMatrix aRetval; + + if(!fTools::equalZero(fShearY)) + { + aRetval.set(1, 0, fShearY); + } + + return aRetval; + } + + B2DHomMatrix createRotateB2DHomMatrix(double fRadiant) + { + B2DHomMatrix aRetval; + + if(!fTools::equalZero(fRadiant)) + { + double fSin(0.0); + double fCos(1.0); + + createSinCosOrthogonal(fSin, fCos, fRadiant); + aRetval.set(0, 0, fCos); + aRetval.set(1, 1, fCos); + aRetval.set(1, 0, fSin); + aRetval.set(0, 1, -fSin); + } + + return aRetval; + } + + B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY) + { + B2DHomMatrix aRetval; + + if(!(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY))) + { + aRetval.set(0, 2, fTranslateX); + aRetval.set(1, 2, fTranslateY); + } + + return aRetval; + } + + B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix( + double fScaleX, double fScaleY, + double fShearX, + double fRadiant, + double fTranslateX, double fTranslateY) + { + const double fOne(1.0); + + if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne)) + { + /// no scale, take shortcut + return createShearXRotateTranslateB2DHomMatrix(fShearX, fRadiant, fTranslateX, fTranslateY); + } + else + { + /// scale used + if(fTools::equalZero(fShearX)) + { + /// no shear + if(fTools::equalZero(fRadiant)) + { + /// no rotate, take shortcut + return createScaleTranslateB2DHomMatrix(fScaleX, fScaleY, fTranslateX, fTranslateY); + } + else + { + /// rotate and scale used, no shear + double fSin(0.0); + double fCos(1.0); + + createSinCosOrthogonal(fSin, fCos, fRadiant); + + B2DHomMatrix aRetval( + /* Row 0, Column 0 */ fCos * fScaleX, + /* Row 0, Column 1 */ fScaleY * -fSin, + /* Row 0, Column 2 */ fTranslateX, + /* Row 1, Column 0 */ fSin * fScaleX, + /* Row 1, Column 1 */ fScaleY * fCos, + /* Row 1, Column 2 */ fTranslateY); + + return aRetval; + } + } + else + { + /// scale and shear used + if(fTools::equalZero(fRadiant)) + { + /// scale and shear, but no rotate + B2DHomMatrix aRetval( + /* Row 0, Column 0 */ fScaleX, + /* Row 0, Column 1 */ fScaleY * fShearX, + /* Row 0, Column 2 */ fTranslateX, + /* Row 1, Column 0 */ 0.0, + /* Row 1, Column 1 */ fScaleY, + /* Row 1, Column 2 */ fTranslateY); + + return aRetval; + } + else + { + /// scale, shear and rotate used + double fSin(0.0); + double fCos(1.0); + + createSinCosOrthogonal(fSin, fCos, fRadiant); + + B2DHomMatrix aRetval( + /* Row 0, Column 0 */ fCos * fScaleX, + /* Row 0, Column 1 */ fScaleY * ((fCos * fShearX) - fSin), + /* Row 0, Column 2 */ fTranslateX, + /* Row 1, Column 0 */ fSin * fScaleX, + /* Row 1, Column 1 */ fScaleY * ((fSin * fShearX) + fCos), + /* Row 1, Column 2 */ fTranslateY); + + return aRetval; + } + } + } + } + + B2DHomMatrix createShearXRotateTranslateB2DHomMatrix( + double fShearX, + double fRadiant, + double fTranslateX, double fTranslateY) + { + if(fTools::equalZero(fShearX)) + { + /// no shear + if(fTools::equalZero(fRadiant)) + { + /// no shear, no rotate, take shortcut + return createTranslateB2DHomMatrix(fTranslateX, fTranslateY); + } + else + { + /// no shear, but rotate used + double fSin(0.0); + double fCos(1.0); + + createSinCosOrthogonal(fSin, fCos, fRadiant); + + B2DHomMatrix aRetval( + /* Row 0, Column 0 */ fCos, + /* Row 0, Column 1 */ -fSin, + /* Row 0, Column 2 */ fTranslateX, + /* Row 1, Column 0 */ fSin, + /* Row 1, Column 1 */ fCos, + /* Row 1, Column 2 */ fTranslateY); + + return aRetval; + } + } + else + { + /// shear used + if(fTools::equalZero(fRadiant)) + { + /// no rotate, but shear used + B2DHomMatrix aRetval( + /* Row 0, Column 0 */ 1.0, + /* Row 0, Column 1 */ fShearX, + /* Row 0, Column 2 */ fTranslateX, + /* Row 1, Column 0 */ 0.0, + /* Row 1, Column 1 */ 1.0, + /* Row 1, Column 2 */ fTranslateY); + + return aRetval; + } + else + { + /// shear and rotate used + double fSin(0.0); + double fCos(1.0); + + createSinCosOrthogonal(fSin, fCos, fRadiant); + + B2DHomMatrix aRetval( + /* Row 0, Column 0 */ fCos, + /* Row 0, Column 1 */ (fCos * fShearX) - fSin, + /* Row 0, Column 2 */ fTranslateX, + /* Row 1, Column 0 */ fSin, + /* Row 1, Column 1 */ (fSin * fShearX) + fCos, + /* Row 1, Column 2 */ fTranslateY); + + return aRetval; + } + } + } + + B2DHomMatrix createScaleTranslateB2DHomMatrix( + double fScaleX, double fScaleY, + double fTranslateX, double fTranslateY) + { + const double fOne(1.0); + + if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne)) + { + /// no scale, take shortcut + return createTranslateB2DHomMatrix(fTranslateX, fTranslateY); + } + else + { + /// scale used + if(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY)) + { + /// no translate, but scale. + B2DHomMatrix aRetval; + + aRetval.set(0, 0, fScaleX); + aRetval.set(1, 1, fScaleY); + + return aRetval; + } + else + { + /// translate and scale + B2DHomMatrix aRetval( + /* Row 0, Column 0 */ fScaleX, + /* Row 0, Column 1 */ 0.0, + /* Row 0, Column 2 */ fTranslateX, + /* Row 1, Column 0 */ 0.0, + /* Row 1, Column 1 */ fScaleY, + /* Row 1, Column 2 */ fTranslateY); + + return aRetval; + } + } + } + + B2DHomMatrix createRotateAroundPoint( + double fPointX, double fPointY, + double fRadiant) + { + B2DHomMatrix aRetval; + + if(!fTools::equalZero(fRadiant)) + { + double fSin(0.0); + double fCos(1.0); + + createSinCosOrthogonal(fSin, fCos, fRadiant); + + aRetval.set3x2( + /* Row 0, Column 0 */ fCos, + /* Row 0, Column 1 */ -fSin, + /* Row 0, Column 2 */ (fPointX * (1.0 - fCos)) + (fSin * fPointY), + /* Row 1, Column 0 */ fSin, + /* Row 1, Column 1 */ fCos, + /* Row 1, Column 2 */ (fPointY * (1.0 - fCos)) - (fSin * fPointX)); + } + + return aRetval; + } + } // end of namespace tools } // end of namespace basegfx /////////////////////////////////////////////////////////////////////////////// diff --git a/basegfx/source/polygon/b2dlinegeometry.cxx b/basegfx/source/polygon/b2dlinegeometry.cxx index 1a9264ab769e..c22b5ea94011 100644 --- a/basegfx/source/polygon/b2dlinegeometry.cxx +++ b/basegfx/source/polygon/b2dlinegeometry.cxx @@ -40,6 +40,7 @@ #include <basegfx/range/b2drange.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/curve/b2dcubicbezier.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -85,11 +86,9 @@ namespace basegfx // get size of the arrow const B2DRange aArrowSize(getRange(rArrow)); - // build ArrowTransform - B2DHomMatrix aArrowTransform; - - // center in X, align with axis in Y - aArrowTransform.translate(-aArrowSize.getCenter().getX(), -aArrowSize.getMinimum().getY()); + // build ArrowTransform; center in X, align with axis in Y + B2DHomMatrix aArrowTransform(basegfx::tools::createTranslateB2DHomMatrix( + -aArrowSize.getCenter().getX(), -aArrowSize.getMinimum().getY())); // scale to target size const double fArrowScale(fWidth / (aArrowSize.getRange().getX())); diff --git a/basegfx/source/polygon/b2dpolygonclipper.cxx b/basegfx/source/polygon/b2dpolygonclipper.cxx index f0d325942c07..87e44ed3d063 100644 --- a/basegfx/source/polygon/b2dpolygonclipper.cxx +++ b/basegfx/source/polygon/b2dpolygonclipper.cxx @@ -40,6 +40,7 @@ #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/curve/b2dcubicbezier.hxx> #include <basegfx/tools/rectcliptools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -361,11 +362,10 @@ namespace basegfx else if(rCandidate.count()) { const B2DVector aEdge(rPointB - rPointA); - B2DHomMatrix aMatrixTransform; B2DPolygon aCandidate(rCandidate); // translate and rotate polygon so that given edge is on x axis - aMatrixTransform.translate(-rPointA.getX(), -rPointA.getY()); + B2DHomMatrix aMatrixTransform(basegfx::tools::createTranslateB2DHomMatrix(-rPointA.getX(), -rPointA.getY())); aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX())); aCandidate.transform(aMatrixTransform); @@ -395,11 +395,10 @@ namespace basegfx else if(rCandidate.count()) { const B2DVector aEdge(rPointB - rPointA); - B2DHomMatrix aMatrixTransform; B2DPolyPolygon aCandidate(rCandidate); // translate and rotate polygon so that given edge is on x axis - aMatrixTransform.translate(-rPointA.getX(), -rPointA.getY()); + B2DHomMatrix aMatrixTransform(basegfx::tools::createTranslateB2DHomMatrix(-rPointA.getX(), -rPointA.getY())); aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX())); aCandidate.transform(aMatrixTransform); diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx index 7485387c6cb9..d62462b8c097 100644 --- a/basegfx/source/polygon/b2dpolygontools.cxx +++ b/basegfx/source/polygon/b2dpolygontools.cxx @@ -33,7 +33,6 @@ #include <basegfx/polygon/b2dpolygontools.hxx> #include <osl/diagnose.h> #include <rtl/math.hxx> - #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/range/b2drange.hxx> @@ -43,6 +42,8 @@ #include <basegfx/matrix/b3dhommatrix.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/curve/b2dbeziertools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <osl/mutex.hxx> #include <numeric> #include <limits> @@ -54,6 +55,7 @@ #ifdef DBG_UTIL static double fAngleBoundStartValue = ANGLE_BOUND_START_VALUE; #endif +#define STEPSPERQUARTER (3) ////////////////////////////////////////////////////////////////////////////// @@ -1840,145 +1842,106 @@ namespace basegfx return createPolygonFromEllipse( rCenter, fRadius, fRadius ); } - void appendUnitCircleQuadrant(B2DPolygon& rPolygon, sal_uInt32 nQuadrant) + B2DPolygon impCreateUnitCircle(sal_uInt32 nStartQuadrant) { - const double fZero(0.0); - const double fOne(1.0); + B2DPolygon aUnitCircle; const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0); + const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER)); + const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER)); + + B2DPoint aPoint(1.0, 0.0); + B2DPoint aForward(1.0, fScaledKappa); + B2DPoint aBackward(1.0, -fScaledKappa); - // create closed unit-circle with 4 segments - switch(nQuadrant) + if(0 != nStartQuadrant) { - case 0 : // first quadrant - { - rPolygon.append(B2DPoint(fOne, fZero)); - rPolygon.appendBezierSegment(B2DPoint(fOne, fKappa), B2DPoint(fKappa, fOne), B2DPoint(fZero, fOne)); - break; - } - case 1 : // second quadrant - { - rPolygon.append(B2DPoint(fZero, fOne)); - rPolygon.appendBezierSegment(B2DPoint(-fKappa, fOne), B2DPoint(-fOne, fKappa), B2DPoint(-fOne, fZero)); - break; - } - case 2 : // third quadrant - { - rPolygon.append(B2DPoint(-fOne, fZero)); - rPolygon.appendBezierSegment(B2DPoint(-fOne, -fKappa), B2DPoint(-fKappa, -fOne), B2DPoint(fZero, -fOne)); - break; - } - default : // last quadrant - { - rPolygon.append(B2DPoint(fZero, -fOne)); - rPolygon.appendBezierSegment(B2DPoint(fKappa, -fOne), B2DPoint(fOne, -fKappa), B2DPoint(fOne, fZero)); - break; - } + const B2DHomMatrix aQuadrantMatrix(createRotateB2DHomMatrix(F_PI2 * (nStartQuadrant % 4))); + aPoint *= aQuadrantMatrix; + aBackward *= aQuadrantMatrix; + aForward *= aQuadrantMatrix; } - } - B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant) - { - B2DPolygon aRetval; + aUnitCircle.append(aPoint); - // create unit-circle with all 4 segments, close it - appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++; - appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++; - appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++; - appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++; - aRetval.setClosed(true); + for(sal_uInt32 a(0); a < STEPSPERQUARTER * 4; a++) + { + aPoint *= aRotateMatrix; + aBackward *= aRotateMatrix; + aUnitCircle.appendBezierSegment(aForward, aBackward, aPoint); + aForward *= aRotateMatrix; + } - // remove double points between segments created by segmented creation - aRetval.removeDoublePoints(); + aUnitCircle.setClosed(true); + aUnitCircle.removeDoublePoints(); - return aRetval; + return aUnitCircle; } - B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY ) + B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant) { - const double fOne(1.0); - B2DPolygon aRetval(createPolygonFromUnitCircle()); - - // transformation necessary? - const sal_Bool bScale(!fTools::equal(fRadiusX, fOne) || !fTools::equal(fRadiusY, fOne)); - const sal_Bool bTranslate(!rCenter.equalZero()); - - if(bScale || bTranslate) + switch(nStartQuadrant % 4) { - B2DHomMatrix aMatrix; - - if(bScale) - { - aMatrix.scale(fRadiusX, fRadiusY); - } - - if(bTranslate) + case 1 : { - aMatrix.translate(rCenter.getX(), rCenter.getY()); - } - - aRetval.transform(aMatrix); - } - - return aRetval; - } - - void appendUnitCircleQuadrantSegment(B2DPolygon& rPolygon, sal_uInt32 nQuadrant, double fStart, double fEnd) - { - OSL_ENSURE(fStart >= 0.0 && fStart <= 1.0, "appendUnitCircleQuadrantSegment: Access out of range (!)"); - OSL_ENSURE(fEnd >= 0.0 && fEnd <= 1.0, "appendUnitCircleQuadrantSegment: Access out of range (!)"); - OSL_ENSURE(fEnd >= fStart, "appendUnitCircleQuadrantSegment: Access out of range (!)"); - const double fOne(1.0); - const bool bStartIsZero(fTools::equalZero(fStart)); - const bool bEndIsOne(fTools::equal(fEnd, fOne)); + static B2DPolygon aUnitCircleStartQuadrantOne; - if(bStartIsZero && bEndIsOne) - { - // add completely - appendUnitCircleQuadrant(rPolygon, nQuadrant); - } - else - { - // split and add - B2DPolygon aQuadrant; - appendUnitCircleQuadrant(aQuadrant, nQuadrant); - const bool bStartEndEqual(fTools::equal(fStart, fEnd)); + if(!aUnitCircleStartQuadrantOne.count()) + { + ::osl::Mutex m_mutex; + aUnitCircleStartQuadrantOne = impCreateUnitCircle(1); + } - if(bStartEndEqual) + return aUnitCircleStartQuadrantOne; + } + case 2 : { - if(bStartIsZero) + static B2DPolygon aUnitCircleStartQuadrantTwo; + + if(!aUnitCircleStartQuadrantTwo.count()) { - // both zero, add start point - rPolygon.append(aQuadrant.getB2DPoint(0L)); + ::osl::Mutex m_mutex; + aUnitCircleStartQuadrantTwo = impCreateUnitCircle(2); } - else if(bEndIsOne) + + return aUnitCircleStartQuadrantTwo; + } + case 3 : + { + static B2DPolygon aUnitCircleStartQuadrantThree; + + if(!aUnitCircleStartQuadrantThree.count()) { - // both one, add end point - rPolygon.append(aQuadrant.getB2DPoint(1L)); + ::osl::Mutex m_mutex; + aUnitCircleStartQuadrantThree = impCreateUnitCircle(3); } - else - { - // both equal but not zero, add split point - B2DCubicBezier aCubicBezier( - aQuadrant.getB2DPoint(0L), aQuadrant.getNextControlPoint(0L), - aQuadrant.getPrevControlPoint(1L), aQuadrant.getB2DPoint(1L)); - aCubicBezier.split(fStart, &aCubicBezier, 0); - rPolygon.append(aCubicBezier.getEndPoint()); - } + return aUnitCircleStartQuadrantThree; } - else + default : // case 0 : { - B2DCubicBezier aCubicBezier( - aQuadrant.getB2DPoint(0L), aQuadrant.getNextControlPoint(0L), - aQuadrant.getPrevControlPoint(1L), aQuadrant.getB2DPoint(1L)); + static B2DPolygon aUnitCircleStartQuadrantZero; + + if(!aUnitCircleStartQuadrantZero.count()) + { + ::osl::Mutex m_mutex; + aUnitCircleStartQuadrantZero = impCreateUnitCircle(0); + } - aCubicBezier = aCubicBezier.snippet(fStart, fEnd); - rPolygon.append(aCubicBezier.getStartPoint()); - rPolygon.appendBezierSegment(aCubicBezier.getControlPointA(), aCubicBezier.getControlPointB(), aCubicBezier.getEndPoint()); + return aUnitCircleStartQuadrantZero; } } } + B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY ) + { + B2DPolygon aRetval(createPolygonFromUnitCircle()); + const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY())); + + aRetval.transform(aMatrix); + + return aRetval; + } + B2DPolygon createPolygonFromUnitEllipseSegment( double fStart, double fEnd ) { B2DPolygon aRetval; @@ -2005,49 +1968,74 @@ namespace basegfx fEnd = 0.0; } - const sal_uInt32 nQuadrantStart(sal_uInt32(fStart / F_PI2) % 4L); - const sal_uInt32 nQuadrantEnd(sal_uInt32(fEnd / F_PI2) % 4L); - sal_uInt32 nCurrentQuadrant(nQuadrantStart); - bool bStartDone(false); - bool bEndDone(false); - - do + if(fTools::equal(fStart, fEnd)) { - if(!bStartDone && nQuadrantStart == nCurrentQuadrant) - { - if(nQuadrantStart == nQuadrantEnd && fTools::moreOrEqual(fEnd, fStart)) - { - // both in one quadrant and defining the complete segment, create start to end - double fSplitOffsetStart((fStart - (nCurrentQuadrant * F_PI2)) / F_PI2); - double fSplitOffsetEnd((fEnd - (nCurrentQuadrant * F_PI2)) / F_PI2); - appendUnitCircleQuadrantSegment(aRetval, nCurrentQuadrant, fSplitOffsetStart, fSplitOffsetEnd); - bStartDone = bEndDone = true; - } - else - { - // create start to quadrant end - const double fSplitOffsetStart((fStart - (nCurrentQuadrant * F_PI2)) / F_PI2); - appendUnitCircleQuadrantSegment(aRetval, nCurrentQuadrant, fSplitOffsetStart, 1.0); - bStartDone = true; - } - } - else if(!bEndDone && nQuadrantEnd == nCurrentQuadrant) + // same start and end angle, add single point + aRetval.append(B2DPoint(cos(fStart), sin(fStart))); + } + else + { + const sal_uInt32 nSegments(STEPSPERQUARTER * 4); + const double fAnglePerSegment(F_PI2 / STEPSPERQUARTER); + const sal_uInt32 nStartSegment(sal_uInt32(fStart / fAnglePerSegment) % nSegments); + const sal_uInt32 nEndSegment(sal_uInt32(fEnd / fAnglePerSegment) % nSegments); + const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0); + const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER)); + + B2DPoint aSegStart(cos(fStart), sin(fStart)); + aRetval.append(aSegStart); + + if(nStartSegment == nEndSegment && fTools::more(fEnd, fStart)) { - // create quadrant start to end - const double fSplitOffsetEnd((fEnd - (nCurrentQuadrant * F_PI2)) / F_PI2); - appendUnitCircleQuadrantSegment(aRetval, nCurrentQuadrant, 0.0, fSplitOffsetEnd); - bEndDone = true; + // start and end in one sector and in the right order, create in one segment + const B2DPoint aSegEnd(cos(fEnd), sin(fEnd)); + const double fFactor(fScaledKappa * ((fEnd - fStart) / fAnglePerSegment)); + + aRetval.appendBezierSegment( + aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor), + aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor), + aSegEnd); } else { - // add quadrant completely - appendUnitCircleQuadrant(aRetval, nCurrentQuadrant); - } + double fSegEndRad((nStartSegment + 1) * fAnglePerSegment); + double fFactor(fScaledKappa * ((fSegEndRad - fStart) / fAnglePerSegment)); + B2DPoint aSegEnd(cos(fSegEndRad), sin(fSegEndRad)); - // next step - nCurrentQuadrant = (nCurrentQuadrant + 1L) % 4L; + aRetval.appendBezierSegment( + aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor), + aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor), + aSegEnd); + + sal_uInt32 nSegment((nStartSegment + 1) % nSegments); + aSegStart = aSegEnd; + + while(nSegment != nEndSegment) + { + // No end in this sector, add full sector. + fSegEndRad = (nSegment + 1) * fAnglePerSegment; + aSegEnd = B2DPoint(cos(fSegEndRad), sin(fSegEndRad)); + + aRetval.appendBezierSegment( + aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fScaledKappa), + aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fScaledKappa), + aSegEnd); + + nSegment = (nSegment + 1) % nSegments; + aSegStart = aSegEnd; + } + + // End in this sector + const double fSegStartRad(nSegment * fAnglePerSegment); + fFactor = fScaledKappa * ((fEnd - fSegStartRad) / fAnglePerSegment); + aSegEnd = B2DPoint(cos(fEnd), sin(fEnd)); + + aRetval.appendBezierSegment( + aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor), + aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor), + aSegEnd); + } } - while(!(bStartDone && bEndDone)); // remove double points between segments created by segmented creation aRetval.removeDoublePoints(); @@ -2058,28 +2046,9 @@ namespace basegfx B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd ) { B2DPolygon aRetval(createPolygonFromUnitEllipseSegment(fStart, fEnd)); + const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY())); - // transformation necessary? - const double fOne(1.0); - const sal_Bool bScale(!fTools::equal(fRadiusX, fOne) || !fTools::equal(fRadiusY, fOne)); - const sal_Bool bTranslate(!rCenter.equalZero()); - - if(bScale || bTranslate) - { - B2DHomMatrix aMatrix; - - if(bScale) - { - aMatrix.scale(fRadiusX, fRadiusY); - } - - if(bTranslate) - { - aMatrix.translate(rCenter.getX(), rCenter.getY()); - } - - aRetval.transform(aMatrix); - } + aRetval.transform(aMatrix); return aRetval; } @@ -2709,11 +2678,7 @@ namespace basegfx if(nPointCount) { - B2DHomMatrix aMatrix; - - aMatrix.translate(-rCenter.getX(), -rCenter.getY()); - aMatrix.rotate(fAngle); - aMatrix.translate(rCenter.getX(), rCenter.getY()); + const B2DHomMatrix aMatrix(basegfx::tools::createRotateAroundPoint(rCenter, fAngle)); aRetval.transform(aMatrix); } diff --git a/basegfx/source/polygon/b2dsvgpolypolygon.cxx b/basegfx/source/polygon/b2dsvgpolypolygon.cxx index 2247c237d90f..e38ec3809fb1 100644 --- a/basegfx/source/polygon/b2dsvgpolypolygon.cxx +++ b/basegfx/source/polygon/b2dsvgpolypolygon.cxx @@ -36,6 +36,7 @@ #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <rtl/ustring.hxx> #include <rtl/math.hxx> @@ -705,7 +706,7 @@ namespace basegfx // |y1'| = |-sin phi cos phi| |(y1 - y2)/2| const B2DPoint p1(nLastX, nLastY); const B2DPoint p2(nX, nY); - B2DHomMatrix aTransform; aTransform.rotate(-fPhi*M_PI/180); + B2DHomMatrix aTransform(basegfx::tools::createRotateB2DHomMatrix(-fPhi*M_PI/180)); const B2DPoint p1_prime( aTransform * B2DPoint(((p1-p2)/2.0)) ); @@ -797,8 +798,7 @@ namespace basegfx fTheta1, fTheta2 )); // transform ellipse by rotation & move to final center - aTransform.identity(); - aTransform.scale(fRX,fRY); + aTransform = basegfx::tools::createScaleB2DHomMatrix(fRX, fRY); aTransform.translate(aCenter_prime.getX(), aCenter_prime.getY()); aTransform.rotate(fPhi*M_PI/180); diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx index 9e78039cd590..51989899ebf4 100644 --- a/basegfx/source/tools/gradienttools.cxx +++ b/basegfx/source/tools/gradienttools.cxx @@ -32,9 +32,9 @@ #include "precompiled_basegfx.hxx" #include <basegfx/tools/gradienttools.hxx> - #include <basegfx/point/b2dpoint.hxx> #include <basegfx/range/b2drange.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> namespace basegfx { @@ -79,9 +79,8 @@ namespace basegfx B2DPoint aCenter(0.5, 0.5); aCenter *= o_rGradientInfo.maTextureTransform; - o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY()); - o_rGradientInfo.maTextureTransform.rotate(fAngle); - o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY()); + o_rGradientInfo.maTextureTransform = basegfx::tools::createRotateAroundPoint(aCenter, fAngle) + * o_rGradientInfo.maTextureTransform; } // add object translate @@ -158,9 +157,8 @@ namespace basegfx B2DPoint aCenter(0.5, 0.5); aCenter *= o_rGradientInfo.maTextureTransform; - o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY()); - o_rGradientInfo.maTextureTransform.rotate(fAngle); - o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY()); + o_rGradientInfo.maTextureTransform = basegfx::tools::createRotateAroundPoint(aCenter, fAngle) + * o_rGradientInfo.maTextureTransform; } } @@ -232,9 +230,8 @@ namespace basegfx B2DPoint aCenter(0.5, 0.5); aCenter *= o_rGradientInfo.maTextureTransform; - o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY()); - o_rGradientInfo.maTextureTransform.rotate(fAngle); - o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY()); + o_rGradientInfo.maTextureTransform = basegfx::tools::createRotateAroundPoint(aCenter, fAngle) + * o_rGradientInfo.maTextureTransform; } // add defined offsets after rotation diff --git a/basegfx/source/tools/unopolypolygon.cxx b/basegfx/source/tools/unopolypolygon.cxx index 6d8fcd83edb0..05dbe5b1c823 100755 --- a/basegfx/source/tools/unopolypolygon.cxx +++ b/basegfx/source/tools/unopolypolygon.cxx @@ -44,8 +44,8 @@ #include <basegfx/tools/canvastools.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> - #include <basegfx/tools/unopolypolygon.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> using namespace ::com::sun::star; @@ -138,9 +138,7 @@ namespace unotools if( !aOffset.equalZero() ) { - B2DHomMatrix aTranslate; - aTranslate.translate( aOffset.getX(), aOffset.getY() ); - + const B2DHomMatrix aTranslate(tools::createTranslateB2DHomMatrix(aOffset)); aSrcPoly.transform( aTranslate ); } diff --git a/basegfx/test/basegfx2d.cxx b/basegfx/test/basegfx2d.cxx index ab6715467dba..1bd15702e143 100644 --- a/basegfx/test/basegfx2d.cxx +++ b/basegfx/test/basegfx2d.cxx @@ -484,8 +484,13 @@ public: } while ( nIndex >= 0 ); + // Adapted number of spaces to 50 and 67 because of the new circle construction + // methods which produce more points and thus more spaces, too. Use both since + // depending on float precision and the getContinuity() implemetation using + // fTools::equal, linux and mac produce more 'C' than 'S' statements, while WIN32 + // uses more 'S' statements (as it should be for circles) CPPUNIT_ASSERT_MESSAGE("exporting to circle does not produce the expected number of coordinates", - nCount==18); + nCount==67 || nCount==50); const B2DPolygon aRect( tools::createPolygonFromRect( B2DRange(0.0,0.0,4000.0,4000.0) )); diff --git a/canvas/source/cairo/cairo_canvashelper.cxx b/canvas/source/cairo/cairo_canvashelper.cxx index 9cf2dd978759..7a5e81a5512a 100644 --- a/canvas/source/cairo/cairo_canvashelper.cxx +++ b/canvas/source/cairo/cairo_canvashelper.cxx @@ -958,6 +958,7 @@ namespace cairocanvas void CanvasHelper::doPolyPolygonPath( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, Operation aOperation, + bool bNoLineJoin, const uno::Sequence< rendering::Texture >* pTextures, Cairo* pCairo ) const { @@ -967,10 +968,47 @@ namespace cairocanvas if( !pCairo ) pCairo = mpCairo.get(); - doPolyPolygonImplementation( rPolyPoly, aOperation, - pCairo, pTextures, - mpSurfaceProvider, - xPolyPolygon->getFillRule() ); + if(bNoLineJoin && Stroke == aOperation) + { + // emulate rendering::PathJoinType::NONE by painting single edges + for(sal_uInt32 a(0); a < rPolyPoly.count(); a++) + { + const basegfx::B2DPolygon aCandidate(rPolyPoly.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aCandidate.count()); + + if(nPointCount) + { + const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount + 1: nPointCount); + basegfx::B2DPolygon aEdge; + aEdge.append(aCandidate.getB2DPoint(0)); + aEdge.append(basegfx::B2DPoint(0.0, 0.0)); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + aEdge.setB2DPoint(1, aCandidate.getB2DPoint(nNextIndex)); + aEdge.setNextControlPoint(0, aCandidate.getNextControlPoint(a)); + aEdge.setPrevControlPoint(1, aCandidate.getPrevControlPoint(nNextIndex)); + + doPolyPolygonImplementation( basegfx::B2DPolyPolygon(aEdge), + aOperation, + pCairo, pTextures, + mpSurfaceProvider, + xPolyPolygon->getFillRule() ); + + // prepare next step + aEdge.setB2DPoint(0, aEdge.getB2DPoint(1)); + } + } + } + } + else + { + doPolyPolygonImplementation( rPolyPoly, aOperation, + pCairo, pTextures, + mpSurfaceProvider, + xPolyPolygon->getFillRule() ); + } } uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* , @@ -1039,9 +1077,12 @@ namespace cairocanvas break; } + bool bNoLineJoin(false); + switch( strokeAttributes.JoinType ) { // cairo doesn't have join type NONE so we use MITER as it's pretty close case rendering::PathJoinType::NONE: + bNoLineJoin = true; case rendering::PathJoinType::MITER: cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_MITER ); break; @@ -1063,7 +1104,7 @@ namespace cairocanvas // TODO(rodo) use LineArray of strokeAttributes - doPolyPolygonPath( xPolyPolygon, Stroke ); + doPolyPolygonPath( xPolyPolygon, Stroke, bNoLineJoin ); cairo_restore( mpCairo.get() ); } else @@ -1147,7 +1188,7 @@ namespace cairocanvas cairo_save( mpCairo.get() ); useStates( viewState, renderState, true ); - doPolyPolygonPath( xPolyPolygon, Fill, &textures ); + doPolyPolygonPath( xPolyPolygon, Fill, false, &textures ); cairo_restore( mpCairo.get() ); } diff --git a/canvas/source/cairo/cairo_canvashelper.hxx b/canvas/source/cairo/cairo_canvashelper.hxx index 1e69a9f41e5b..90d365d63b3c 100644 --- a/canvas/source/cairo/cairo_canvashelper.hxx +++ b/canvas/source/cairo/cairo_canvashelper.hxx @@ -276,6 +276,7 @@ namespace cairocanvas void doPolyPolygonPath( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, Operation aOperation, + bool bNoLineJoin = false, const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::Texture >* pTextures=NULL, ::cairo::Cairo* pCairo=NULL ) const; diff --git a/canvas/source/directx/dx_canvashelper.cxx b/canvas/source/directx/dx_canvashelper.cxx index 0642b6c50efb..607f7c076e21 100755 --- a/canvas/source/directx/dx_canvashelper.cxx +++ b/canvas/source/directx/dx_canvashelper.cxx @@ -46,6 +46,7 @@ #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/point/b2dpoint.hxx> #include <basegfx/tools/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <comphelper/sequence.hxx> #include <canvas/canvastools.hxx> @@ -367,7 +368,11 @@ namespace dxcanvas pGraphics->GetPixelOffsetMode() ); pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); - aPen.SetMiterLimit( static_cast< Gdiplus::REAL >(strokeAttributes.MiterLimit) ); + const bool bIsMiter(rendering::PathJoinType::MITER == strokeAttributes.JoinType); + const bool bIsNone(rendering::PathJoinType::NONE == strokeAttributes.JoinType); + + if(bIsMiter) + aPen.SetMiterLimit( static_cast< Gdiplus::REAL >(strokeAttributes.MiterLimit) ); const ::std::vector< Gdiplus::REAL >& rDashArray( ::comphelper::sequenceToContainer< ::std::vector< Gdiplus::REAL > >( @@ -380,9 +385,10 @@ namespace dxcanvas aPen.SetLineCap( gdiCapFromCap(strokeAttributes.StartCapType), gdiCapFromCap(strokeAttributes.EndCapType), Gdiplus::DashCapFlat ); - aPen.SetLineJoin( gdiJoinFromJoin(strokeAttributes.JoinType) ); + if(!bIsNone) + aPen.SetLineJoin( gdiJoinFromJoin(strokeAttributes.JoinType) ); - GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); + GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon, bIsNone ) ); // TODO(E1): Return value Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() ); @@ -733,10 +739,8 @@ namespace dxcanvas // add output offset if( !maOutputOffset.equalZero() ) { - ::basegfx::B2DHomMatrix aOutputOffset; - aOutputOffset.translate( maOutputOffset.getX(), - maOutputOffset.getY() ); - + const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix( + maOutputOffset.getX(), maOutputOffset.getY())); aTransform = aOutputOffset * aTransform; } @@ -774,10 +778,8 @@ namespace dxcanvas // add output offset if( !maOutputOffset.equalZero() ) { - ::basegfx::B2DHomMatrix aOutputOffset; - aOutputOffset.translate( maOutputOffset.getX(), - maOutputOffset.getY() ); - + const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix( + maOutputOffset.getX(), maOutputOffset.getY())); aTransform = aOutputOffset * aTransform; } diff --git a/canvas/source/directx/dx_canvashelper_texturefill.cxx b/canvas/source/directx/dx_canvashelper_texturefill.cxx index f291d197c4de..73a2d49bfb62 100755 --- a/canvas/source/directx/dx_canvashelper_texturefill.cxx +++ b/canvas/source/directx/dx_canvashelper_texturefill.cxx @@ -43,6 +43,7 @@ #include <basegfx/numeric/ftools.hxx> #include <basegfx/tools/tools.hxx> #include <basegfx/tools/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <canvas/parametricpolypolygon.hxx> @@ -452,8 +453,7 @@ namespace dxcanvas aFillBrush.SetColor( aFillColor ); const double nCurrScale( (nStepCount-i)/(double)nStepCount ); - aScaleMatrix.identity(); - aScaleMatrix.translate( -0.5, -0.5 ); + aScaleMatrix = basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5); // handle anisotrophic polygon scaling if( rValues.mnAspectRatio < 1.0 ) diff --git a/canvas/source/directx/dx_impltools.cxx b/canvas/source/directx/dx_impltools.cxx index 40164c9a1d87..4f5b92d6bcb5 100755 --- a/canvas/source/directx/dx_impltools.cxx +++ b/canvas/source/directx/dx_impltools.cxx @@ -194,7 +194,8 @@ namespace dxcanvas void graphicsPathFromB2DPolygon( GraphicsPathSharedPtr& rOutput, ::std::vector< Gdiplus::PointF >& rPoints, - const ::basegfx::B2DPolygon& rPoly ) + const ::basegfx::B2DPolygon& rPoly, + bool bNoLineJoin) { const sal_uInt32 nPoints( rPoly.count() ); @@ -241,7 +242,18 @@ namespace dxcanvas rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), static_cast<Gdiplus::REAL>(rPoint.getY()) ); - rOutput->AddBeziers( &rPoints[0], nCurrOutput ); + if(bNoLineJoin && nCurrOutput > 7) + { + for(sal_uInt32 a(3); a < nCurrOutput; a+=3) + { + rOutput->StartFigure(); + rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); + } + } + else + { + rOutput->AddBeziers( &rPoints[0], nCurrOutput ); + } } else { @@ -251,7 +263,20 @@ namespace dxcanvas // Therefore, simply don't pass the last two // points here. if( nCurrOutput > 3 ) - rOutput->AddBeziers( &rPoints[0], nCurrOutput-2 ); + { + if(bNoLineJoin && nCurrOutput > 7) + { + for(sal_uInt32 a(3); a < nCurrOutput; a+=3) + { + rOutput->StartFigure(); + rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); + } + } + else + { + rOutput->AddBeziers( &rPoints[0], nCurrOutput-2 ); + } + } } } else @@ -267,10 +292,27 @@ namespace dxcanvas static_cast<Gdiplus::REAL>(rPoint.getY()) ); } - rOutput->AddLines( &rPoints[0], nPoints ); + if(bNoLineJoin && nPoints > 2) + { + for(sal_uInt32 a(1); a < nPoints; a++) + { + rOutput->StartFigure(); + rOutput->AddLine(rPoints[a - 1], rPoints[a]); + } + + if(bClosedPolygon) + { + rOutput->StartFigure(); + rOutput->AddLine(rPoints[nPoints - 1], rPoints[0]); + } + } + else + { + rOutput->AddLines( &rPoints[0], nPoints ); + } } - if( bClosedPolygon ) + if( bClosedPolygon && !bNoLineJoin ) rOutput->CloseFigure(); } } @@ -426,17 +468,17 @@ namespace dxcanvas return pRes; } - GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly ) + GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly, bool bNoLineJoin ) { GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); ::std::vector< Gdiplus::PointF > aPoints; - graphicsPathFromB2DPolygon( pRes, aPoints, rPoly ); + graphicsPathFromB2DPolygon( pRes, aPoints, rPoly, bNoLineJoin ); return pRes; } - GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ) + GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, bool bNoLineJoin ) { GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); ::std::vector< Gdiplus::PointF > aPoints; @@ -446,24 +488,25 @@ namespace dxcanvas { graphicsPathFromB2DPolygon( pRes, aPoints, - rPoly.getB2DPolygon( nCurrPoly ) ); + rPoly.getB2DPolygon( nCurrPoly ), + bNoLineJoin); } return pRes; } - GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) + GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly, bool bNoLineJoin ) { LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); if( pPolyImpl ) { - return pPolyImpl->getGraphicsPath(); + return pPolyImpl->getGraphicsPath( bNoLineJoin ); } else { return tools::graphicsPathFromB2DPolyPolygon( - polyPolygonFromXPolyPolygon2D( xPoly ) ); + polyPolygonFromXPolyPolygon2D( xPoly ), bNoLineJoin ); } } diff --git a/canvas/source/directx/dx_impltools.hxx b/canvas/source/directx/dx_impltools.hxx index 072d1063235d..222b1a927305 100755 --- a/canvas/source/directx/dx_impltools.hxx +++ b/canvas/source/directx/dx_impltools.hxx @@ -107,11 +107,18 @@ namespace dxcanvas GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > >& ); - GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly ); - GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ); + GraphicsPathSharedPtr graphicsPathFromB2DPolygon( + const ::basegfx::B2DPolygon& rPoly, + bool bNoLineJoin = false); + + GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( + const ::basegfx::B2DPolyPolygon& rPoly, + bool bNoLineJoin = false); + + GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >&, + bool bNoLineJoin = false ); - GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const ::com::sun::star::uno::Reference< - ::com::sun::star::rendering::XPolyPolygon2D >& ); bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, const BitmapSharedPtr& rBitmap ); bool drawDIBits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, diff --git a/canvas/source/directx/dx_linepolypolygon.cxx b/canvas/source/directx/dx_linepolypolygon.cxx index e63adc3dc613..9a5569384eae 100755 --- a/canvas/source/directx/dx_linepolypolygon.cxx +++ b/canvas/source/directx/dx_linepolypolygon.cxx @@ -46,14 +46,14 @@ namespace dxcanvas { } - GraphicsPathSharedPtr LinePolyPolygon::getGraphicsPath() const + GraphicsPathSharedPtr LinePolyPolygon::getGraphicsPath( bool bNoLineJoin ) const { // generate GraphicsPath only on demand (gets deleted as soon // as any of the modifying methods above touches the // B2DPolyPolygon). if( !mpPath ) { - mpPath = tools::graphicsPathFromB2DPolyPolygon( getPolyPolygonUnsafe() ); + mpPath = tools::graphicsPathFromB2DPolyPolygon( getPolyPolygonUnsafe(), bNoLineJoin ); mpPath->SetFillMode( const_cast<LinePolyPolygon*>(this)->getFillRule() == rendering::FillRule_EVEN_ODD ? Gdiplus::FillModeAlternate : Gdiplus::FillModeWinding ); } diff --git a/canvas/source/directx/dx_linepolypolygon.hxx b/canvas/source/directx/dx_linepolypolygon.hxx index 431cd1b87b4f..3e061d76e768 100755 --- a/canvas/source/directx/dx_linepolypolygon.hxx +++ b/canvas/source/directx/dx_linepolypolygon.hxx @@ -45,7 +45,7 @@ namespace dxcanvas public: explicit LinePolyPolygon( const ::basegfx::B2DPolyPolygon& ); - GraphicsPathSharedPtr getGraphicsPath() const; + GraphicsPathSharedPtr getGraphicsPath( bool bNoLineJoin = false) const; private: // overridden, to clear mpPath diff --git a/canvas/source/simplecanvas/simplecanvasimpl.cxx b/canvas/source/simplecanvas/simplecanvasimpl.cxx index 185979b0220e..7ca251458d22 100644 --- a/canvas/source/simplecanvas/simplecanvasimpl.cxx +++ b/canvas/source/simplecanvas/simplecanvasimpl.cxx @@ -46,6 +46,7 @@ #include <comphelper/servicedecl.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include "canvas/canvastools.hxx" @@ -287,10 +288,7 @@ namespace ::sal_Int8 nTextDirection ) throw (uno::RuntimeException) { ::osl::MutexGuard aGuard( m_aMutex ); - - basegfx::B2DHomMatrix offsetTransform; - offsetTransform.translate(aOutPos.X,aOutPos.Y); - + const basegfx::B2DHomMatrix offsetTransform(basegfx::tools::createTranslateB2DHomMatrix(aOutPos.X,aOutPos.Y)); rendering::RenderState aRenderState( createStrokingRenderState() ); tools::appendToRenderState(aRenderState, offsetTransform); @@ -305,10 +303,7 @@ namespace const geometry::RealPoint2D& aLeftTop ) throw (uno::RuntimeException) { ::osl::MutexGuard aGuard( m_aMutex ); - - basegfx::B2DHomMatrix offsetTransform; - offsetTransform.translate(aLeftTop.X,aLeftTop.Y); - + const basegfx::B2DHomMatrix offsetTransform(basegfx::tools::createTranslateB2DHomMatrix(aLeftTop.X,aLeftTop.Y)); rendering::RenderState aRenderState( createStrokingRenderState() ); tools::appendToRenderState(aRenderState, offsetTransform); diff --git a/canvas/source/tools/canvastools.cxx b/canvas/source/tools/canvastools.cxx index 23d6124e4cb8..278789637c72 100644 --- a/canvas/source/tools/canvastools.cxx +++ b/canvas/source/tools/canvastools.cxx @@ -63,6 +63,7 @@ #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/tools/canvastools.hxx> #include <basegfx/numeric/ftools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <cppuhelper/compbase1.hxx> #include <rtl/instance.hxx> @@ -679,9 +680,8 @@ namespace canvas i_transformation ); // now move resulting left,top point of bounds to (0,0) - ::basegfx::B2DHomMatrix aCorrectedTransform; - aCorrectedTransform.translate( -aTransformedRect.getMinX(), - -aTransformedRect.getMinY() ); + const basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix( + -aTransformedRect.getMinX(), -aTransformedRect.getMinY())); // prepend to original transformation o_transform = aCorrectedTransform * i_transformation; @@ -745,9 +745,8 @@ namespace canvas transformation ); // now move resulting left,top point of bounds to (0,0) - ::basegfx::B2DHomMatrix aCorrectedTransform; - aCorrectedTransform.translate( -aTransformedRect.getMinX(), - -aTransformedRect.getMinY() ); + basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix( + -aTransformedRect.getMinX(), -aTransformedRect.getMinY())); // scale to match outRect const double xDenom( aTransformedRect.getWidth() ); diff --git a/canvas/source/tools/surface.cxx b/canvas/source/tools/surface.cxx index c3161758ea3e..96162f6d78af 100644 --- a/canvas/source/tools/surface.cxx +++ b/canvas/source/tools/surface.cxx @@ -33,6 +33,7 @@ #include "surface.hxx" #include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <comphelper/scopeguard.hxx> #include <boost/bind.hpp> @@ -150,9 +151,8 @@ namespace canvas // 4) scale to normalized device coordinates // 5) flip y-axis // 6) translate to account for viewport transform - ::basegfx::B2DHomMatrix aTransform; - aTransform.translate(maSourceOffset.getX(), - maSourceOffset.getY()); + basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix( + maSourceOffset.getX(), maSourceOffset.getY())); aTransform = aTransform * rTransform; aTransform.translate(::basegfx::fround(rPos.getX()), ::basegfx::fround(rPos.getY())); @@ -277,8 +277,7 @@ namespace canvas // 1) offset of surface subarea // 2) surface transform // 3) translation to output position [rPos] - ::basegfx::B2DHomMatrix aTransform; - aTransform.translate(aPos1.getX(),aPos1.getY()); + basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(aPos1.getX(), aPos1.getY())); aTransform = aTransform * rTransform; aTransform.translate(::basegfx::fround(rPos.getX()), ::basegfx::fround(rPos.getY())); @@ -380,7 +379,7 @@ namespace canvas // be transformed by the overall transform and uv coordinates will // be calculated from the result, and this is why we need to use // integer coordinates here... - ::basegfx::B2DHomMatrix aTransform; + basegfx::B2DHomMatrix aTransform; aTransform = aTransform * rTransform; aTransform.translate(::basegfx::fround(rPos.getX()), ::basegfx::fround(rPos.getY())); diff --git a/comphelper/source/property/opropertybag.cxx b/comphelper/source/property/opropertybag.cxx index 8b816e8c1ce9..caa895021103 100644 --- a/comphelper/source/property/opropertybag.cxx +++ b/comphelper/source/property/opropertybag.cxx @@ -240,7 +240,7 @@ namespace comphelper if ( !( _element >>= aProperty ) ) throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); - ::osl::MutexGuard aGuard( m_aMutex ); + ::osl::ClearableMutexGuard g( m_aMutex ); // check whether the type is allowed, everything else will be checked // by m_aDynamicProperties @@ -254,6 +254,7 @@ namespace comphelper // our property info is dirty m_pArrayHelper.reset(); + g.clear(); setModified(sal_True); } @@ -346,7 +347,7 @@ namespace comphelper //-------------------------------------------------------------------- void SAL_CALL OPropertyBag::addProperty( const ::rtl::OUString& _rName, ::sal_Int16 _nAttributes, const Any& _rInitialValue ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException) { - ::osl::MutexGuard aGuard( m_aMutex ); + ::osl::ClearableMutexGuard g( m_aMutex ); // check whether the type is allowed, everything else will be checked // by m_aDynamicProperties @@ -362,19 +363,21 @@ namespace comphelper // our property info is dirty m_pArrayHelper.reset(); + g.clear(); setModified(sal_True); } //-------------------------------------------------------------------- void SAL_CALL OPropertyBag::removeProperty( const ::rtl::OUString& _rName ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException) { - ::osl::MutexGuard aGuard( m_aMutex ); + ::osl::ClearableMutexGuard g( m_aMutex ); m_aDynamicProperties.removeProperty( _rName ); // our property info is dirty m_pArrayHelper.reset(); + g.clear(); setModified(sal_True); } diff --git a/comphelper/source/property/property.cxx b/comphelper/source/property/property.cxx index fe6cbaa9d767..0ccc28d4238b 100644 --- a/comphelper/source/property/property.cxx +++ b/comphelper/source/property/property.cxx @@ -38,15 +38,11 @@ #include <osl/diagnose.h> #if OSL_DEBUG_LEVEL > 0 - #ifndef _RTL_STRBUF_HXX_ #include <rtl/strbuf.hxx> - #endif - #ifndef _CPPUHELPER_EXC_HLP_HXX_ #include <cppuhelper/exc_hlp.hxx> - #endif - #ifndef _OSL_THREAD_H_ #include <osl/thread.h> - #endif + #include <com/sun/star/lang/XServiceInfo.hpp> + #include <typeinfo> #endif #include <com/sun/star/beans/PropertyAttribute.hpp> #include <com/sun/star/lang/IllegalArgumentException.hpp> @@ -71,6 +67,10 @@ namespace comphelper using ::com::sun::star::uno::cpp_queryInterface; using ::com::sun::star::uno::cpp_acquire; using ::com::sun::star::uno::cpp_release; +#if OSL_DEBUG_LEVEL > 0 + using ::com::sun::star::lang::XServiceInfo; +#endif + using ::com::sun::star::uno::UNO_QUERY; /** === end UNO using === **/ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; @@ -110,7 +110,18 @@ void copyProperties(const Reference<XPropertySet>& _rxSource, ::rtl::OStringBuffer aBuffer; aBuffer.append( "::comphelper::copyProperties: could not copy property '" ); aBuffer.append( ::rtl::OString( pSourceProps->Name.getStr(), pSourceProps->Name.getLength(), RTL_TEXTENCODING_ASCII_US ) ); - aBuffer.append( "' to the destination set.\n" ); + aBuffer.append( "' to the destination set (a '" ); + + Reference< XServiceInfo > xSI( _rxDest, UNO_QUERY ); + if ( xSI.is() ) + { + aBuffer.append( ::rtl::OUStringToOString( xSI->getImplementationName(), osl_getThreadTextEncoding() ) ); + } + else + { + aBuffer.append( typeid( *_rxDest.get() ).name() ); + } + aBuffer.append( "' implementation).\n" ); Any aException( ::cppu::getCaughtException() ); aBuffer.append( "Caught an exception of type '" ); diff --git a/cppcanvas/source/mtfrenderer/bitmapaction.cxx b/cppcanvas/source/mtfrenderer/bitmapaction.cxx index 355dd336e2c5..4f54b10c4879 100644 --- a/cppcanvas/source/mtfrenderer/bitmapaction.cxx +++ b/cppcanvas/source/mtfrenderer/bitmapaction.cxx @@ -35,25 +35,21 @@ #include <com/sun/star/rendering/XBitmap.hpp> #include <com/sun/star/rendering/RepaintResult.hpp> #include <com/sun/star/rendering/XCachedPrimitive.hpp> - #include <vcl/bitmapex.hxx> #include <tools/gen.hxx> #include <vcl/canvastools.hxx> - #include <canvas/canvastools.hxx> - #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/vector/b2dsize.hxx> #include <basegfx/point/b2dpoint.hxx> #include <basegfx/range/b2drange.hxx> #include <basegfx/tools/canvastools.hxx> - #include <boost/utility.hpp> - #include "cachedprimitivebase.hxx" #include "bitmapaction.hxx" #include "outdevstate.hxx" #include "mtftools.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> using namespace ::com::sun::star; @@ -112,9 +108,7 @@ namespace cppcanvas // Setup transformation such that the next render call is // moved rPoint away. - ::basegfx::B2DHomMatrix aLocalTransformation; - aLocalTransformation.translate( rDstPoint.getX(), - rDstPoint.getY() ); + const basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createTranslateB2DHomMatrix(rDstPoint)); ::canvas::tools::appendToRenderState( maState, aLocalTransformation ); @@ -144,15 +138,12 @@ namespace cppcanvas // moved rPoint away, and scaled according to the ratio // given by src and dst size. const ::Size aBmpSize( rBmpEx.GetSizePixel() ); - ::basegfx::B2DHomMatrix aLocalTransformation; const ::basegfx::B2DVector aScale( rDstSize.getX() / aBmpSize.Width(), rDstSize.getY() / aBmpSize.Height() ); - aLocalTransformation.scale( aScale.getX(), aScale.getY() ); - aLocalTransformation.translate( rDstPoint.getX(), - rDstPoint.getY() ); - ::canvas::tools::appendToRenderState( maState, - aLocalTransformation ); + const basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createScaleTranslateB2DHomMatrix( + aScale, rDstPoint)); + ::canvas::tools::appendToRenderState( maState, aLocalTransformation ); // correct clip (which is relative to original transform) tools::modifyClip( maState, diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx index c6f9a295b332..8ea2ae453a97 100644 --- a/cppcanvas/source/mtfrenderer/implrenderer.cxx +++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx @@ -34,19 +34,14 @@ #include <canvas/debug.hxx> #include <tools/diagnose_ex.h> #include <canvas/verbosetrace.hxx> - #include <osl/mutex.hxx> #include <vos/mutex.hxx> #include <vcl/svapp.hxx> - #include <rtl/logfile.hxx> - #include <comphelper/sequence.hxx> #include <comphelper/anytostring.hxx> #include <cppuhelper/exc_hlp.hxx> - #include <cppcanvas/canvas.hxx> - #include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/TexturingMode.hpp> #include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp> @@ -59,7 +54,6 @@ #include <com/sun/star/rendering/XCanvas.hpp> #include <com/sun/star/rendering/PathCapType.hpp> #include <com/sun/star/rendering/PathJoinType.hpp> - #include <basegfx/tools/canvastools.hxx> #include <basegfx/numeric/ftools.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> @@ -73,7 +67,6 @@ #include <basegfx/tuple/b2dtuple.hxx> #include <basegfx/polygon/b2dpolygonclipper.hxx> #include <basegfx/polygon/b2dpolypolygoncutter.hxx> - #include <canvas/canvastools.hxx> #include <vcl/canvastools.hxx> #include <vcl/salbtype.hxx> @@ -84,11 +77,9 @@ #include <vcl/graphictools.hxx> #include <tools/poly.hxx> #include <i18npool/mslangid.hxx> - #include <implrenderer.hxx> #include <tools.hxx> #include <outdevstate.hxx> - #include <action.hxx> #include <bitmapaction.hxx> #include <lineaction.hxx> @@ -96,15 +87,13 @@ #include <polypolyaction.hxx> #include <textaction.hxx> #include <transparencygroupaction.hxx> - #include <vector> #include <algorithm> #include <iterator> - #include <boost/scoped_array.hpp> - #include "mtftools.hxx" #include "outdevstate.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> using namespace ::com::sun::star; @@ -286,10 +275,25 @@ namespace (getState( rParms.mrStates ).mapModeTransform * aWidth).getX(); // setup reasonable defaults - o_rStrokeAttributes.MiterLimit = 1.0; + o_rStrokeAttributes.MiterLimit = 15.0; // 1.0 was no good default; GDI+'s limit is 10.0, our's is 15.0 o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; o_rStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; - o_rStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + + switch(rLineInfo.GetLineJoin()) + { + default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE + o_rStrokeAttributes.JoinType = rendering::PathJoinType::NONE; + break; + case basegfx::B2DLINEJOIN_BEVEL: + o_rStrokeAttributes.JoinType = rendering::PathJoinType::BEVEL; + break; + case basegfx::B2DLINEJOIN_MITER: + o_rStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + break; + case basegfx::B2DLINEJOIN_ROUND: + o_rStrokeAttributes.JoinType = rendering::PathJoinType::ROUND; + break; + } if( LINE_DASH == rLineInfo.GetStyle() ) { @@ -729,12 +733,11 @@ namespace cppcanvas fabs( aBounds.getHeight()*sin(nRotation) ) + fabs( aBounds.getWidth()*cos(nRotation) ))); - aTextureTransformation.scale( nScale, nScale ); - - // translate back origin to center of + // scale and translate back origin to center of // primitive - aTextureTransformation.translate( 0.5*aBounds.getWidth(), - 0.5*aBounds.getHeight() ); + aTextureTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix( + nScale, nScale, 0.5*aBounds.getWidth(), 0.5*aBounds.getHeight()) + * aTextureTransformation; } break; @@ -856,9 +859,8 @@ namespace cppcanvas aTextureTransformation.scale( nScaleX, nScaleY ); // rotate texture according to gradient rotation - aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY ); - aTextureTransformation.rotate( nRotation ); - aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY ); + aTextureTransformation = basegfx::tools::createRotateAroundPoint(0.5*nScaleX, 0.5*nScaleY, nRotation) + * aTextureTransformation; aTextureTransformation.translate( nOffsetX, nOffsetY ); } diff --git a/cppcanvas/source/mtfrenderer/mtftools.cxx b/cppcanvas/source/mtfrenderer/mtftools.cxx index e4e227955da6..b6a548aa49be 100644 --- a/cppcanvas/source/mtfrenderer/mtftools.cxx +++ b/cppcanvas/source/mtfrenderer/mtftools.cxx @@ -34,10 +34,8 @@ #include <canvas/debug.hxx> #include <tools/diagnose_ex.h> #include <canvas/verbosetrace.hxx> - #include <com/sun/star/rendering/RenderState.hpp> #include <com/sun/star/rendering/XCanvas.hpp> - #include <basegfx/numeric/ftools.hxx> #include <basegfx/tools/canvastools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> @@ -45,16 +43,15 @@ #include <basegfx/range/b2drectangle.hxx> #include <basegfx/vector/b2dvector.hxx> #include <canvas/canvastools.hxx> - #include <vcl/gdimtf.hxx> #include <vcl/metaact.hxx> #include <vcl/virdev.hxx> #include <vcl/metric.hxx> #include <tools/poly.hxx> - #include "mtftools.hxx" #include "outdevstate.hxx" #include "polypolyaction.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> @@ -111,9 +108,9 @@ namespace cppcanvas const ::Size aSizePixel( rVDev.LogicToPixel( aSizeLogic ) ); - o_rMatrix.identity(); - o_rMatrix.scale( aSizePixel.Width() / (double)aSizeLogic.Width(), - aSizePixel.Height() / (double)aSizeLogic.Height() ); + o_rMatrix = basegfx::tools::createScaleB2DHomMatrix( + aSizePixel.Width() / (double)aSizeLogic.Width(), + aSizePixel.Height() / (double)aSizeLogic.Height() ); return o_rMatrix; } diff --git a/cppcanvas/source/mtfrenderer/textaction.cxx b/cppcanvas/source/mtfrenderer/textaction.cxx index f1191e6e57f3..038b68c3008e 100644 --- a/cppcanvas/source/mtfrenderer/textaction.cxx +++ b/cppcanvas/source/mtfrenderer/textaction.cxx @@ -48,6 +48,7 @@ #include <basegfx/vector/b2dsize.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <tools/gen.hxx> #include <vcl/canvastools.hxx> @@ -93,9 +94,7 @@ namespace cppcanvas NULL, &rState.fontRotation ); - ::basegfx::B2DHomMatrix aLocalTransformation; - - aLocalTransformation.rotate( rState.fontRotation ); + basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState.fontRotation)); aLocalTransformation.translate( rStartPoint.getX(), rStartPoint.getY() ); ::canvas::tools::appendToRenderState( o_rRenderState, diff --git a/goodies/inc/grfmgr.hxx b/goodies/inc/grfmgr.hxx index b44c27ea65e3..1ef351ae6d32 100644 --- a/goodies/inc/grfmgr.hxx +++ b/goodies/inc/grfmgr.hxx @@ -353,7 +353,7 @@ public: void ReleaseFromCache(); const Graphic& GetGraphic() const; - void SetGraphic( const Graphic& rGraphic ); + void SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj = 0); void SetGraphic( const Graphic& rGraphic, const String& rLink ); /** Get graphic transformed according to given attributes diff --git a/goodies/source/filter.vcl/epict/epict.cxx b/goodies/source/filter.vcl/epict/epict.cxx index 3e4dca455d05..cd9e33edd5d9 100644 --- a/goodies/source/filter.vcl/epict/epict.cxx +++ b/goodies/source/filter.vcl/epict/epict.cxx @@ -55,6 +55,9 @@ #include "dlgepct.hrc" #include "dlgepct.hxx" +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + //============================== PictWriter =================================== struct PictWriterAttrStackMember { @@ -77,7 +80,6 @@ struct PictPattern { sal_uInt32 nLo, nHi; }; - class PictWriter { private: @@ -178,6 +180,7 @@ private: void WriteTextArray(Point & rPoint, const String& rString, const sal_Int32 * pDXAry); + void HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); void WriteOpcodes(const GDIMetaFile & rMTF); void WriteHeader(const GDIMetaFile & rMTF); @@ -1371,6 +1374,65 @@ void PictWriter::WriteTextArray(Point & rPoint, const String& rString, const sal } } +void PictWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + aLinePolyPolygon = aLinePolyPolygon.getDefaultAdaptiveSubdivision(); + const sal_uInt32 nPolyCount(aLinePolyPolygon.count()); + SetAttrForFrame(); + + for(sal_uInt32 a(0); a < nPolyCount; a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aCandidate.count()); + + if(nPointCount) + { + const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount + 1 : nPointCount); + const basegfx::B2DPoint aCurr(aCandidate.getB2DPoint(0)); + Point nCurr(basegfx::fround(aCurr.getX()), basegfx::fround(aCurr.getY())); + + for(sal_uInt32 b(0); b < nEdgeCount; b++) + { + const sal_uInt32 nNextIndex((b + 1) % nPointCount); + const basegfx::B2DPoint aNext(aCandidate.getB2DPoint(nNextIndex)); + const Point nNext(basegfx::fround(aNext.getX()), basegfx::fround(aNext.getY())); + + WriteOpcode_Line(nCurr, nNext); + nCurr = nNext; + } + } + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(aLineColor); + const Color aOldFillColor(aFillColor); + + aLineColor = Color( COL_TRANSPARENT ); + aFillColor = aOldLineColor; + SetAttrForPaint(); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a).getDefaultAdaptiveSubdivision()); + WriteOpcode_Poly(PDM_PAINT, aPolygon); + } + + aLineColor = aOldLineColor; + aFillColor = aOldFillColor; + } + } +} void PictWriter::WriteOpcodes( const GDIMetaFile & rMTF ) { @@ -1417,8 +1479,19 @@ void PictWriter::WriteOpcodes( const GDIMetaFile & rMTF ) if( aLineColor != Color( COL_TRANSPARENT ) ) { - SetAttrForFrame(); - WriteOpcode_Line( pA->GetStartPoint(),pA->GetEndPoint() ); + if(pA->GetLineInfo().IsDefault()) + { + SetAttrForFrame(); + WriteOpcode_Line( pA->GetStartPoint(),pA->GetEndPoint() ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } } break; } @@ -1571,24 +1644,35 @@ void PictWriter::WriteOpcodes( const GDIMetaFile & rMTF ) { const Polygon& rPoly = pA->GetPolygon(); - Polygon aSimplePoly; - if ( rPoly.HasFlags() ) - rPoly.AdaptiveSubdivide( aSimplePoly ); - else - aSimplePoly = rPoly; - - const USHORT nSize = aSimplePoly.GetSize(); - Point aLast; - - if ( nSize ) + if( rPoly.GetSize() ) { - SetAttrForFrame(); - aLast = aSimplePoly[0]; + if(pA->GetLineInfo().IsDefault()) + { + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.AdaptiveSubdivide( aSimplePoly ); + else + aSimplePoly = rPoly; - for ( USHORT i = 1; i < nSize; i++ ) + const USHORT nSize = aSimplePoly.GetSize(); + Point aLast; + + if ( nSize ) + { + SetAttrForFrame(); + aLast = aSimplePoly[0]; + + for ( USHORT i = 1; i < nSize; i++ ) + { + WriteOpcode_Line( aLast, aSimplePoly[i] ); + aLast = aSimplePoly[i]; + } + } + } + else { - WriteOpcode_Line( aLast, aSimplePoly[i] ); - aLast = aSimplePoly[i]; + // LineInfo used; handle Dash/Dot and fat lines + HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); } } } diff --git a/goodies/source/filter.vcl/epict/makefile.mk b/goodies/source/filter.vcl/epict/makefile.mk index 4aa4bab80ffc..9f25a562488a 100644 --- a/goodies/source/filter.vcl/epict/makefile.mk +++ b/goodies/source/filter.vcl/epict/makefile.mk @@ -61,7 +61,7 @@ RESLIB1SRSFILES=$(SRS)$/$(TARGET).srs .IF "$(L10N_framework)"=="" SHL1TARGET= ept$(DLLPOSTFIX) SHL1IMPLIB= epict -SHL1STDLIBS= $(TOOLSLIB) $(VCLLIB) $(SVTOOLLIB) $(CPPULIB) $(SALLIB) +SHL1STDLIBS= $(TOOLSLIB) $(VCLLIB) $(SVTOOLLIB) $(CPPULIB) $(SALLIB) $(BASEGFXLIB) SHL1LIBS= $(SLB)$/epict.lib diff --git a/goodies/source/filter.vcl/eps/eps.cxx b/goodies/source/filter.vcl/eps/eps.cxx index dc8e407b178e..83b5a94f97f2 100644 --- a/goodies/source/filter.vcl/eps/eps.cxx +++ b/goodies/source/filter.vcl/eps/eps.cxx @@ -388,7 +388,7 @@ BOOL PSWriter::WritePS( const Graphic& rGraphic, SvStream& rTargetStream, Filter bTextFillColor = TRUE; aTextFillColor = Color( COL_BLACK ); fLineWidth = 1; - fMiterLimit = 10; + fMiterLimit = 15; // use same limit as most graphic systems and basegfx eLineCap = SvtGraphicStroke::capButt; eJoinType = SvtGraphicStroke::joinMiter; aBackgroundColor = Color( COL_WHITE ); @@ -701,7 +701,40 @@ void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev ) Polygon aPoly( ( (const MetaPolyLineAction*) pMA )->GetPolygon() ); const LineInfo& rLineInfo = ( ( const MetaPolyLineAction*)pMA )->GetLineInfo(); ImplWriteLineInfo( rLineInfo ); - ImplPolyLine( aPoly ); + + if(basegfx::B2DLINEJOIN_NONE == rLineInfo.GetLineJoin() + && rLineInfo.GetWidth() > 1) + { + // emulate B2DLINEJOIN_NONE by creating single edges + const sal_uInt16 nPoints(aPoly.GetSize()); + const bool bCurve(aPoly.HasFlags()); + + for(sal_uInt16 a(0); a + 1 < nPoints; a++) + { + if(bCurve + && POLY_NORMAL != aPoly.GetFlags(a + 1) + && a + 2 < nPoints + && POLY_NORMAL != aPoly.GetFlags(a + 2) + && a + 3 < nPoints) + { + const Polygon aSnippet(4, + aPoly.GetConstPointAry() + a, + aPoly.GetConstFlagAry() + a); + ImplPolyLine(aSnippet); + a += 2; + } + else + { + const Polygon aSnippet(2, + aPoly.GetConstPointAry() + a); + ImplPolyLine(aSnippet); + } + } + } + else + { + ImplPolyLine( aPoly ); + } } break; @@ -2343,8 +2376,28 @@ void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo ) SvtGraphicStroke::DashArray l_aDashArray; if ( rLineInfo.GetStyle() == LINE_DASH ) l_aDashArray.push_back( 2 ); - double fLWidth = ( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5; - ImplWriteLineInfo( fLWidth, 10.0, SvtGraphicStroke::capButt, SvtGraphicStroke::joinMiter, l_aDashArray ); + const double fLWidth(( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5); + SvtGraphicStroke::JoinType aJoinType(SvtGraphicStroke::joinMiter); + + switch(rLineInfo.GetLineJoin()) + { + default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE + // do NOT use SvtGraphicStroke::joinNone here + // since it will be written as numerical value directly + // and is NOT a valid EPS value + break; + case basegfx::B2DLINEJOIN_MITER: + aJoinType = SvtGraphicStroke::joinMiter; + break; + case basegfx::B2DLINEJOIN_BEVEL: + aJoinType = SvtGraphicStroke::joinBevel; + break; + case basegfx::B2DLINEJOIN_ROUND: + aJoinType = SvtGraphicStroke::joinRound; + break; + } + + ImplWriteLineInfo( fLWidth, fMiterLimit, SvtGraphicStroke::capButt, aJoinType, l_aDashArray ); } //--------------------------------------------------------------------------------- diff --git a/goodies/source/filter.vcl/ieps/ieps.cxx b/goodies/source/filter.vcl/ieps/ieps.cxx index f315ee864310..7f1ecfc65bd0 100644 --- a/goodies/source/filter.vcl/ieps/ieps.cxx +++ b/goodies/source/filter.vcl/ieps/ieps.cxx @@ -164,12 +164,54 @@ static void MakeAsMeta(Graphic &rGraphic) rGraphic = aMtf; } +static oslProcessError runProcessWithPathSearch(const rtl::OUString &rProgName, + rtl_uString* pArgs[], sal_uInt32 nArgs, oslProcess *pProcess, + oslFileHandle *pIn, oslFileHandle *pOut, oslFileHandle *pErr) +{ +#ifdef WNT + /* + * ooo#72096 + * On Window the underlying SearchPath searches in order of... + * The directory from which the application loaded. + * The current directory. + * The Windows system directory. + * The Windows directory. + * The directories that are listed in the PATH environment variable. + * + * Because one of our programs is called "convert" and there is a convert + * in the windows system directory, we want to explicitly search the PATH + * to avoid picking up on that one if ImageMagick's convert preceeds it in + * PATH. + * + */ + rtl::OUString url; + rtl::OUString path(_wgetenv(L"PATH")); + + oslFileError err = osl_searchFileURL(rProgName.pData, path.pData, &url.pData); + if (err != osl_File_E_None) + return osl_Process_E_NotFound; + return osl_executeProcess_WithRedirectedIO(url.pData, + pArgs, nArgs, osl_Process_HIDDEN, + osl_getCurrentSecurity(), 0, 0, 0, pProcess, pIn, pOut, pErr); +#else + return osl_executeProcess_WithRedirectedIO(rProgName.pData, + pArgs, nArgs, osl_Process_SEARCHPATH | osl_Process_HIDDEN, + osl_getCurrentSecurity(), 0, 0, 0, pProcess, pIn, pOut, pErr); +#endif +} + +#if defined(WNT) || defined(OS2) +# define EXESUFFIX ".exe" +#else +# define EXESUFFIX "" +#endif + static bool RenderAsEMF(const sal_uInt8* pBuf, sal_uInt32 nBytesRead, Graphic &rGraphic) { TempFile aTemp; aTemp.EnableKillingFile(); rtl::OUString fileName = - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("pstoedit")); + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("pstoedit"EXESUFFIX)); rtl::OUString arg1 = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-f")); rtl::OUString arg2 = @@ -186,10 +228,10 @@ static bool RenderAsEMF(const sal_uInt8* pBuf, sal_uInt32 nBytesRead, Graphic &r oslFileHandle pIn = NULL; oslFileHandle pOut = NULL; oslFileHandle pErr = NULL; - oslProcessError eErr = osl_executeProcess_WithRedirectedIO(fileName.pData, - args, sizeof(args)/sizeof(rtl_uString *), - osl_Process_SEARCHPATH | osl_Process_HIDDEN, - osl_getCurrentSecurity(), 0, 0, 0, &aProcess, &pIn, &pOut, &pErr); + oslProcessError eErr = runProcessWithPathSearch(fileName, + args, sizeof(args)/sizeof(rtl_uString *), + &aProcess, &pIn, &pOut, &pErr); + if (eErr!=osl_Process_E_None) return false; @@ -222,15 +264,15 @@ static bool RenderAsEMF(const sal_uInt8* pBuf, sal_uInt32 nBytesRead, Graphic &r } static bool RenderAsPNGThroughHelper(const sal_uInt8* pBuf, sal_uInt32 nBytesRead, - Graphic &rGraphic, rtl::OUString &rProgName, rtl_uString **pArgs, size_t nArgs) + Graphic &rGraphic, rtl::OUString &rProgName, rtl_uString *pArgs[], size_t nArgs) { oslProcess aProcess; oslFileHandle pIn = NULL; oslFileHandle pOut = NULL; oslFileHandle pErr = NULL; - oslProcessError eErr = osl_executeProcess_WithRedirectedIO(rProgName.pData, - pArgs, nArgs, osl_Process_SEARCHPATH | osl_Process_HIDDEN, - osl_getCurrentSecurity(), 0, 0, 0, &aProcess, &pIn, &pOut, &pErr); + oslProcessError eErr = runProcessWithPathSearch(rProgName, + pArgs, nArgs, + &aProcess, &pIn, &pOut, &pErr); if (eErr!=osl_Process_E_None) return false; @@ -251,7 +293,7 @@ static bool RenderAsPNGThroughHelper(const sal_uInt8* pBuf, sal_uInt32 nBytesRea aMemStm.Seek(0); if ( - eFileErr == osl_File_E_None && + aMemStm.GetEndOfData() && GraphicConverter::Import(aMemStm, rGraphic, CVT_PNG) == ERRCODE_NONE ) { @@ -270,7 +312,7 @@ static bool RenderAsPNGThroughConvert(const sal_uInt8* pBuf, sal_uInt32 nBytesRe Graphic &rGraphic) { rtl::OUString fileName = - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("convert")); + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("convert"EXESUFFIX)); // density in pixel/inch rtl::OUString arg1 = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-density")); // since the preview is also used for PDF-Export & printing on non-PS-printers, @@ -293,10 +335,10 @@ static bool RenderAsPNGThroughGS(const sal_uInt8* pBuf, sal_uInt32 nBytesRead, { #ifdef WNT rtl::OUString fileName = - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gswin32c")); + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gswin32c"EXESUFFIX)); #else rtl::OUString fileName = - rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gs")); + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gs"EXESUFFIX)); #endif rtl::OUString arg1 = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-q")); diff --git a/goodies/source/filter.vcl/ios2met/ios2met.cxx b/goodies/source/filter.vcl/ios2met/ios2met.cxx index 0fbf24f56029..8c3c19e22379 100644 --- a/goodies/source/filter.vcl/ios2met/ios2met.cxx +++ b/goodies/source/filter.vcl/ios2met/ios2met.cxx @@ -846,7 +846,7 @@ void OS2METReader::ReadRelLine(BOOL bGivenPos, USHORT nOrderLen) if (nPolySize==0) return; Polygon aPolygon(nPolySize); for (i=0; i<nPolySize; i++) { -#if (defined SOLARIS && defined PPC) || defined IRIX +#if defined SOLARIS && defined PPC UINT8 nunsignedbyte; *pOS2MET >> nunsignedbyte; aP0.X()+=(INT8)nunsignedbyte; *pOS2MET >> nunsignedbyte; aP0.Y()+=(INT8)nunsignedbyte; diff --git a/goodies/source/graphic/grfmgr.cxx b/goodies/source/graphic/grfmgr.cxx index 39c1e53e7184..7f5970383075 100644 --- a/goodies/source/graphic/grfmgr.cxx +++ b/goodies/source/graphic/grfmgr.cxx @@ -845,7 +845,7 @@ const Graphic& GraphicObject::GetGraphic() const // ----------------------------------------------------------------------------- -void GraphicObject::SetGraphic( const Graphic& rGraphic ) +void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj ) { mpMgr->ImplUnregisterObj( *this ); @@ -858,7 +858,7 @@ void GraphicObject::SetGraphic( const Graphic& rGraphic ) delete mpLink, mpLink = NULL; delete mpSimpleCache, mpSimpleCache = NULL; - mpMgr->ImplRegisterObj( *this, maGraphic ); + mpMgr->ImplRegisterObj( *this, maGraphic, 0, pCopyObj); if( mpSwapOutTimer ) mpSwapOutTimer->Start(); diff --git a/padmin/source/padialog.cxx b/padmin/source/padialog.cxx index f73427526be6..5a6a1d0e319e 100644 --- a/padmin/source/padialog.cxx +++ b/padmin/source/padialog.cxx @@ -60,11 +60,16 @@ #include "unotools/localedatawrapper.hxx" #include "unotools/configitem.hxx" #include "unotools/configmgr.hxx" + +#include "com/sun/star/awt/Size.hpp" + using namespace psp; using namespace rtl; using namespace padmin; using namespace osl; +using namespace com::sun::star; using namespace com::sun::star::uno; +using namespace com::sun::star::beans; PADialog* PADialog::Create( Window* pParent, BOOL bAdmin ) { @@ -96,7 +101,6 @@ PADialog::PADialog( Window* pParent, BOOL /*bAdmin*/ ) : m_aCancelButton( this, PaResId( RID_PA_BTN_CANCEL ) ), m_aDefPrt( PaResId( RID_PA_STR_DEFPRT ) ), m_aRenameStr( PaResId( RID_PA_STR_RENAME ) ), - m_pPrinter( 0 ), m_rPIManager( PrinterInfoManager::get() ) { FreeResource(); @@ -248,18 +252,6 @@ IMPL_LINK( PADialog, SelectHdl, ListBox*, pListBox ) return 0; } -IMPL_LINK( PADialog, EndPrintHdl, void*, EMPTYARG ) -{ - String aInfoString( PaResId( RID_PA_TXT_TESTPAGE_PRINTED ) ); - InfoBox aInfoBox( this, aInfoString ); - aInfoBox.SetText( String( PaResId( RID_BXT_TESTPAGE ) ) ); - aInfoBox.Execute(); - - delete m_pPrinter; - m_pPrinter = NULL; - return 0; -} - void PADialog::UpdateDefPrt() { m_rPIManager.setDefaultPrinter( getSelectedDevice() ); @@ -369,66 +361,77 @@ static Color approachColor( const Color& rFrom, const Color& rTo ) return aColor; } -#define DELTA 5.0 -void PADialog::PrintTestPage() +class SpaPrinterController : public vcl::PrinterController { - if( m_pPrinter ) // already printing; user pressed button twice - return; +public: + SpaPrinterController( const boost::shared_ptr<Printer>& i_pPrinter ) + : vcl::PrinterController( i_pPrinter ) + {} + virtual ~SpaPrinterController() + {} + + virtual int getPageCount() const { return 1; } + virtual Sequence< PropertyValue > getPageParameters( int i_nPage ) const; + virtual void printPage( int i_nPage ) const; + virtual void jobFinished( com::sun::star::view::PrintableState ); +}; + +Sequence< PropertyValue > SpaPrinterController::getPageParameters( int ) const +{ + Sequence< PropertyValue > aRet( 1 ); - String sPrinter( getSelectedDevice() ); + Size aPageSize( getPrinter()->GetPaperSizePixel() ); + aPageSize = getPrinter()->PixelToLogic( aPageSize, MapMode( MAP_100TH_MM ) ); + + awt::Size aSize; + aSize.Width = aPageSize.Width(); + aSize.Height = aPageSize.Height(); + aRet[0].Value = makeAny(aSize); - m_pPrinter = new Printer( sPrinter ); + return aRet; +} - PrinterInfo aInfo( m_rPIManager.getPrinterInfo( sPrinter ) ); +void SpaPrinterController::printPage( int ) const +{ + const double DELTA = 5.0; + + boost::shared_ptr<Printer> pPrinter( getPrinter() ); + + PrinterInfo aInfo( psp::PrinterInfoManager::get().getPrinterInfo( pPrinter->GetName() ) ); const PPDParser* pPrintParser = aInfo.m_pParser; MapMode aMapMode( MAP_100TH_MM ); Bitmap aButterfly( PaResId( RID_BUTTERFLY ) ); - m_pPrinter->SetMapMode( aMapMode ); - m_pPrinter->SetEndPrintHdl( LINK( this, PADialog, EndPrintHdl ) ); + pPrinter->SetMapMode( aMapMode ); Any aRet = utl::ConfigManager::GetDirectConfigProperty( utl::ConfigManager::PRODUCTNAME ); OUString aJobName; aRet >>= aJobName; aJobName = aJobName + OUString( RTL_CONSTASCII_USTRINGPARAM( " Testpage" ) ); - if( m_pPrinter->GetName() != sPrinter || ! m_pPrinter->StartJob( aJobName ) ) - { - String aString( PaResId( RID_ERR_NOPRINTER ) ); - aString.SearchAndReplaceAscii( "%s", sPrinter ); - ErrorBox aErrorBox( this, WB_OK | WB_DEF_OK, aString ); - aErrorBox.SetText( String( PaResId( RID_BXT_ENVIRONMENT ) ) ); - aErrorBox.Execute(); - delete m_pPrinter; - m_pPrinter = 0; - return; - } - m_pPrinter->StartPage(); - - Size aPaperSize=m_pPrinter->GetOutputSize(); + Size aPaperSize=pPrinter->GetOutputSize(); Point aCenter( aPaperSize.Width()/2-300, aPaperSize.Height() - aPaperSize.Width()/2 ); Point aP1( aPaperSize.Width()/48, 0), aP2( aPaperSize.Width()/40, 0 ), aPoint; - m_pPrinter->DrawRect( Rectangle( Point( 0,0 ), aPaperSize ) ); - m_pPrinter->DrawRect( Rectangle( Point( 100,100 ), + pPrinter->DrawRect( Rectangle( Point( 0,0 ), aPaperSize ) ); + pPrinter->DrawRect( Rectangle( Point( 100,100 ), Size( aPaperSize.Width()-200, aPaperSize.Height()-200 ) ) ); - m_pPrinter->DrawRect( Rectangle( Point( 200,200 ), + pPrinter->DrawRect( Rectangle( Point( 200,200 ), Size( aPaperSize.Width()-400, aPaperSize.Height()-400 ) ) ); - m_pPrinter->DrawRect( Rectangle( Point( 300,300 ), + pPrinter->DrawRect( Rectangle( Point( 300,300 ), Size( aPaperSize.Width()-600, aPaperSize.Height()-600 ) ) ); - Font aFont( m_pPrinter->GetFont() ); - aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ) ); + Font aFont( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ), Size( 0, 400 ) ); aFont.SetWeight( WEIGHT_NORMAL ); aFont.SetItalic( ITALIC_NONE ); - m_pPrinter->SetFont( aFont ); + pPrinter->SetFont( aFont ); OUStringBuffer aPrintText(1024); long nWidth = 0, nMaxWidth = 0; @@ -455,12 +458,12 @@ void PADialog::PrintTestPage() aToken = String::CreateFromAscii( aResIds[i].pDirect ); else aToken = String( PaResId( aResIds[i].nResId ) ); - nMaxWidth = ( nWidth = m_pPrinter->GetTextWidth( aToken ) ) > nMaxWidth ? nWidth : nMaxWidth; + nMaxWidth = ( nWidth = pPrinter->GetTextWidth( aToken ) ) > nMaxWidth ? nWidth : nMaxWidth; aPrintText.append( aToken ); aPrintText.append( (sal_Unicode)'\n' ); }; - m_pPrinter->DrawText( Rectangle( Point( 1000, 2000 ), + pPrinter->DrawText( Rectangle( Point( 1000, 1000 ), Size( aPaperSize.Width() - 2000, aPaperSize.Height() - 4000 ) ), aPrintText.makeStringAndClear(), @@ -470,7 +473,7 @@ void PADialog::PrintTestPage() const LocaleDataWrapper& rLocaleWrapper( aSettings.GetLocaleDataWrapper() ); aPrintText.appendAscii( ": " ); - aPrintText.append( sPrinter ); + aPrintText.append( pPrinter->GetName() ); aPrintText.appendAscii( "\n: " ); if( pPrintParser ) aPrintText.append( pPrintParser->getPrinterName() ); @@ -487,17 +490,17 @@ void PADialog::PrintTestPage() aPrintText.appendAscii( "\n: " ); aPrintText.append( rLocaleWrapper.getTime( Time() ) ); - m_pPrinter->DrawText( Rectangle( Point( 1100 + nMaxWidth, 2000 ), + pPrinter->DrawText( Rectangle( Point( 1100 + nMaxWidth, 1000 ), Size( aPaperSize.Width() - 2100 - nMaxWidth, aPaperSize.Height() - 4000 ) ), aPrintText.makeStringAndClear(), TEXT_DRAW_MULTILINE ); - m_pPrinter->DrawBitmap( Point( aPaperSize.Width() - 4000, 1000 ), + pPrinter->DrawBitmap( Point( aPaperSize.Width() - 4000, 1000 ), Size( 3000,3000 ), aButterfly ); - m_pPrinter->SetFillColor(); - m_pPrinter->DrawRect( Rectangle( Point( aPaperSize.Width() - 4000, 1000 ), + pPrinter->SetFillColor(); + pPrinter->DrawRect( Rectangle( Point( aPaperSize.Width() - 4000, 1000 ), Size( 3000,3000 ) ) ); Color aWhite( 0xff, 0xff, 0xff ); @@ -511,22 +514,22 @@ void PADialog::PrintTestPage() Gradient aGradient( GRADIENT_LINEAR, aBlack, aWhite ); aGradient.SetAngle( 900 ); - m_pPrinter->DrawGradient( Rectangle( Point( 1000, 5500 ), + pPrinter->DrawGradient( Rectangle( Point( 1000, 5500 ), Size( aPaperSize.Width() - 2000, 500 ) ), aGradient ); aGradient.SetStartColor( aDarkRed ); aGradient.SetEndColor( aLightBlue ); - m_pPrinter->DrawGradient( Rectangle( Point( 1000, 6300 ), + pPrinter->DrawGradient( Rectangle( Point( 1000, 6300 ), Size( aPaperSize.Width() - 2000, 500 ) ), aGradient ); aGradient.SetStartColor( aDarkBlue ); aGradient.SetEndColor( aLightGreen ); - m_pPrinter->DrawGradient( Rectangle( Point( 1000, 7100 ), + pPrinter->DrawGradient( Rectangle( Point( 1000, 7100 ), Size( aPaperSize.Width() - 2000, 500 ) ), aGradient ); aGradient.SetStartColor( aDarkGreen ); aGradient.SetEndColor( aLightRed ); - m_pPrinter->DrawGradient( Rectangle( Point( 1000, 7900 ), + pPrinter->DrawGradient( Rectangle( Point( 1000, 7900 ), Size( aPaperSize.Width() - 2000, 500 ) ), aGradient ); @@ -543,7 +546,7 @@ void PADialog::PrintTestPage() { aLineInfo.SetWidth( n/3 ); aLineColor = approachColor( aLineColor, aApproachColor ); - m_pPrinter->SetLineColor( aLineColor ); + pPrinter->SetLineColor( aLineColor ); // switch aproach color if( aApproachColor.IsRGBEqual( aLineColor ) ) @@ -556,7 +559,7 @@ void PADialog::PrintTestPage() aApproachColor = Color( 0, 200, 0 ); } - m_pPrinter->DrawLine( project( aP1 ) + aCenter, + pPrinter->DrawLine( project( aP1 ) + aCenter, project( aP2 ) + aCenter, aLineInfo ); aPoint.X() = (int)((((double)aP1.X())*cosd - ((double)aP1.Y())*sind)*factor); @@ -569,8 +572,38 @@ void PADialog::PrintTestPage() #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL fprintf( stderr, "%d lines\n",n ); #endif - m_pPrinter->EndPage(); - m_pPrinter->EndJob(); +} + +void SpaPrinterController::jobFinished( com::sun::star::view::PrintableState ) +{ + String aInfoString( PaResId( RID_PA_TXT_TESTPAGE_PRINTED ) ); + InfoBox aInfoBox( NULL, aInfoString ); + aInfoBox.SetText( String( PaResId( RID_BXT_TESTPAGE ) ) ); + aInfoBox.Execute(); +} + +void PADialog::PrintTestPage() +{ + String sPrinter( getSelectedDevice() ); + + boost::shared_ptr<Printer> pPrinter( new Printer( sPrinter ) ); + + if( pPrinter->GetName() != sPrinter ) + { + String aString( PaResId( RID_ERR_NOPRINTER ) ); + aString.SearchAndReplaceAscii( "%s", sPrinter ); + + ErrorBox aErrorBox( this, WB_OK | WB_DEF_OK, aString ); + aErrorBox.SetText( String( PaResId( RID_BXT_ENVIRONMENT ) ) ); + aErrorBox.Execute(); + return; + } + + boost::shared_ptr<vcl::PrinterController> pController( new SpaPrinterController( pPrinter ) ); + JobSetup aJobSetup( pPrinter->GetJobSetup() ); + aJobSetup.SetValue( String( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ), + String( RTL_CONSTASCII_USTRINGPARAM( "true" ) ) ); + Printer::PrintJob( pController, aJobSetup ); } void PADialog::AddDevice() diff --git a/padmin/source/padialog.hxx b/padmin/source/padialog.hxx index ac6ee8f4279f..0350f66a2905 100644 --- a/padmin/source/padialog.hxx +++ b/padmin/source/padialog.hxx @@ -83,7 +83,6 @@ namespace padmin { String m_aDefPrt; String m_aRenameStr; - Printer* m_pPrinter; ::psp::PrinterInfoManager& m_rPIManager; ::std::list< ::rtl::OUString > m_aPrinters; @@ -94,7 +93,6 @@ namespace padmin { DECL_LINK( ClickBtnHdl, PushButton* ); DECL_LINK( DoubleClickHdl, ListBox* ); DECL_LINK( SelectHdl, ListBox* ); - DECL_LINK( EndPrintHdl, void* ); DECL_LINK( DelPressedHdl, ListBox* ); PADialog( Window*, BOOL ); diff --git a/rsc/source/parser/rscicpx.cxx b/rsc/source/parser/rscicpx.cxx index 9ae58087a335..e59a1e056f4b 100644 --- a/rsc/source/parser/rscicpx.cxx +++ b/rsc/source/parser/rscicpx.cxx @@ -2281,6 +2281,7 @@ RscTop * RscTypCont::InitClassTabControl( RscTop * pSuper, RSC_TABCONTROL_ITEMLIST ); INS_WINBIT( pClassTabControl, SingleLine ); + INS_WINBIT( pClassTabControl, DropDown ); } return pClassTabControl; diff --git a/rsc/source/parser/rsclex.cxx b/rsc/source/parser/rsclex.cxx index 3c2c95e541d1..8c34637fa304 100644 --- a/rsc/source/parser/rsclex.cxx +++ b/rsc/source/parser/rsclex.cxx @@ -317,7 +317,7 @@ int yylex() /****************** yyerror **********************************************/ #ifdef RS6000 extern "C" void yyerror( char* pMessage ) -#elif defined HP9000 || defined SCO || defined IRIX || defined SOLARIS +#elif defined HP9000 || defined SCO || defined SOLARIS extern "C" void yyerror( const char* pMessage ) #else void yyerror( char* pMessage ) diff --git a/rsc/source/parser/rsclex.hxx b/rsc/source/parser/rsclex.hxx index 89feed4dd132..63afd0b208c7 100644 --- a/rsc/source/parser/rsclex.hxx +++ b/rsc/source/parser/rsclex.hxx @@ -107,7 +107,7 @@ class ObjectStack { extern "C" int yyparse(); // forward Deklaration fuer erzeugte Funktion extern "C" void yyerror( char * ); extern "C" int yylex( void ); -#elif defined( HP9000 ) || defined( SCO ) || defined ( IRIX ) || defined ( SOLARIS ) +#elif defined( HP9000 ) || defined( SCO ) || defined ( SOLARIS ) extern "C" int yyparse(); // forward Deklaration fuer erzeugte Funktion extern "C" void yyerror( const char * ); extern "C" int yylex( void ); diff --git a/rsc/source/rsc/makefile.mk b/rsc/source/rsc/makefile.mk index 40e2d77740a3..89abd22207d9 100644 --- a/rsc/source/rsc/makefile.mk +++ b/rsc/source/rsc/makefile.mk @@ -40,10 +40,6 @@ ENABLE_EXCEPTIONS=true .INCLUDE : settings.mk -.IF "$(OS)"=="IRIX" -NOOPTFILES= $(OBJ)$/rsc.obj -.ENDIF - OBJFILES= $(OBJ)$/rsc.obj .INCLUDE : target.mk diff --git a/sot/source/sdstor/stgstrms.cxx b/sot/source/sdstor/stgstrms.cxx index 46ae3529439c..0e20af6118af 100644 --- a/sot/source/sdstor/stgstrms.cxx +++ b/sot/source/sdstor/stgstrms.cxx @@ -1104,7 +1104,7 @@ StgTmpStrm::~StgTmpStrm() } } -ULONG StgTmpStrm::GetSize() +ULONG StgTmpStrm::GetSize() const { ULONG n; if( pStrm ) diff --git a/sot/source/sdstor/stgstrms.hxx b/sot/source/sdstor/stgstrms.hxx index 806d562af6d0..fd7971da3aba 100644 --- a/sot/source/sdstor/stgstrms.hxx +++ b/sot/source/sdstor/stgstrms.hxx @@ -167,8 +167,7 @@ public: ~StgTmpStrm(); BOOL Copy( StgTmpStrm& ); void SetSize( ULONG ); - using SvMemoryStream::GetSize; - ULONG GetSize(); + ULONG GetSize() const; }; #endif diff --git a/svl/inc/svl/solar.hrc b/svl/inc/svl/solar.hrc index 96149b89131c..26ab8a959c5e 100644 --- a/svl/inc/svl/solar.hrc +++ b/svl/inc/svl/solar.hrc @@ -2,13 +2,10 @@ * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2008 by Sun Microsystems, Inc. + * Copyright 2009 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * - * $RCSfile: solar.hrc,v $ - * $Revision: 1.6 $ - * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify @@ -171,6 +168,9 @@ #define HID_START 32768 +#define HID_VCL_START (HID_START+100) +#define HID_VCL_END (HID_START+150) + #define HID_SVTOOLS_START (HID_START+200) #define HID_SVTOOLS_END (HID_START+299) @@ -207,8 +207,10 @@ #define HID_GOODIES_START (HID_LIB_START+2100) #define HID_GOODIES_END (HID_LIB_START+2199) +#if 0 // currently unused range #define HID_SCHEDULE_START (HID_LIB_START+2200) #define HID_SCHEDULE_END (HID_LIB_START+3399) +#endif #define HID_CHANNEL_START (HID_LIB_START+3400) #define HID_CHANNEL_END (HID_LIB_START+3499) @@ -300,6 +302,5 @@ #define HID_EXTENSIONS_START (HID_OBJ_START+2281) #define HID_EXTENSIONS_END (HID_OBJ_START+2800) - #endif diff --git a/svl/inc/svl/svarray.hxx b/svl/inc/svl/svarray.hxx index d2479cd5364f..555b7ad5fe84 100644 --- a/svl/inc/svl/svarray.hxx +++ b/svl/inc/svl/svarray.hxx @@ -1034,7 +1034,7 @@ public:\ #define C40_PTR_REPLACE( c, p) Replace( (c const *) p ) #define C40_GETPOS( c, r) GetPos( (c const *)r ) #else -#if defined WTC || defined IRIX || defined ICC || defined HPUX || (defined GCC && __GNUC__ >= 3) || (defined(WNT) && _MSC_VER >= 1400) +#if defined WTC || defined ICC || defined HPUX || (defined GCC && __GNUC__ >= 3) || (defined(WNT) && _MSC_VER >= 1400) #define C40_INSERT( c, p, n ) Insert( (c const *&) p, n ) #define C40_PUSH( c, p) Push( (c const *&) p ) #define C40_PTR_INSERT( c, p ) Insert( (c const *&) p ) diff --git a/svl/source/numbers/numhead.cxx b/svl/source/numbers/numhead.cxx index 99ff33433de3..3bb650b0c9ae 100644 --- a/svl/source/numbers/numhead.cxx +++ b/svl/source/numbers/numhead.cxx @@ -139,7 +139,7 @@ ImpSvNumMultipleReadHeader::ImpSvNumMultipleReadHeader(SvStream& rNewStream) : ImpSvNumMultipleReadHeader::~ImpSvNumMultipleReadHeader() { - DBG_ASSERT( pMemStream->Tell() == pMemStream->GetSize(), + DBG_ASSERT( pMemStream->Tell() == pMemStream->GetEndOfData(), "Sizes nicht vollstaendig gelesen" ); delete pMemStream; delete [] pBuf; diff --git a/svtools/inc/svtools/imapobj.hxx b/svtools/inc/svtools/imapobj.hxx index b8da0e5c3ee8..46b73ee95f2c 100644 --- a/svtools/inc/svtools/imapobj.hxx +++ b/svtools/inc/svtools/imapobj.hxx @@ -96,7 +96,7 @@ public: static rtl_TextEncoding nActualTextEncoding; - IMapObject() {}; + IMapObject(); IMapObject( const String& rURL, const String& rAltText, const String& rDesc, diff --git a/svtools/source/control/filectrl.cxx b/svtools/source/control/filectrl.cxx index d820dce097ed..f00cf45be0e6 100644 --- a/svtools/source/control/filectrl.cxx +++ b/svtools/source/control/filectrl.cxx @@ -78,6 +78,9 @@ WinBits FileControl::ImplInitStyle( WinBits nStyle ) maButton.SetStyle( (maButton.GetStyle()|WB_NOTABSTOP)&(~WB_TABSTOP) ); } + const WinBits nAlignmentStyle = ( WB_TOP | WB_VCENTER | WB_BOTTOM ); + maEdit.SetStyle( ( maEdit.GetStyle() & ~nAlignmentStyle ) | ( nStyle & nAlignmentStyle ) ); + if ( !(nStyle & WB_NOGROUP) ) nStyle |= WB_GROUP; diff --git a/svtools/source/dialogs/prnsetup.cxx b/svtools/source/dialogs/prnsetup.cxx index dedb5b2d7143..74cfe7b1286a 100644 --- a/svtools/source/dialogs/prnsetup.cxx +++ b/svtools/source/dialogs/prnsetup.cxx @@ -59,7 +59,7 @@ void ImplFillPrnDlgListBox( const Printer* pPrinter, } pBox->Enable( nCount != 0 ); - pPropBtn->Enable( pPrinter->HasSupport( SUPPORT_SETUPDIALOG ) ); + pPropBtn->Show( pPrinter->HasSupport( SUPPORT_SETUPDIALOG ) ); } // ----------------------------------------------------------------------- diff --git a/svtools/source/filter.vcl/filter/filter2.cxx b/svtools/source/filter.vcl/filter/filter2.cxx index d570dd34e50f..9e0e3ba43d54 100644 --- a/svtools/source/filter.vcl/filter/filter2.cxx +++ b/svtools/source/filter.vcl/filter/filter2.cxx @@ -471,7 +471,8 @@ BOOL GraphicDescriptor::ImpDetectJPG( SvStream& rStm, BOOL bExtendedInfo ) // Groesse des verbleibenden Puffers ermitteln if ( bLinked ) - nMax = ( (SvMemoryStream&) rStm ).GetSize() - 16; + nMax = static_cast< SvMemoryStream& >(rStm).GetEndOfData() + - 16; else nMax = DATA_SIZE - 16; diff --git a/svtools/source/filter.vcl/wmf/emfwr.cxx b/svtools/source/filter.vcl/wmf/emfwr.cxx index df56afc4a250..e011dde1a0e8 100644 --- a/svtools/source/filter.vcl/wmf/emfwr.cxx +++ b/svtools/source/filter.vcl/wmf/emfwr.cxx @@ -33,6 +33,9 @@ #include "emfwr.hxx" #include <vcl/salbtype.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <vcl/lineinfo.hxx> // ----------- // - Defines - @@ -829,6 +832,46 @@ void EMFWriter::ImplWriteTextRecord( const Point& rPos, const String rText, cons // ----------------------------------------------------------------------------- +void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + ImplWritePolygonRecord( Polygon(aCandidate), FALSE ); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(maVDev.GetLineColor()); + const Color aOldFillColor(maVDev.GetFillColor()); + + maVDev.SetLineColor(); + maVDev.SetFillColor(aOldLineColor); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + ImplWritePolyPolygonRecord(PolyPolygon(Polygon(aPolygon))); + } + + maVDev.SetLineColor(aOldLineColor); + maVDev.SetFillColor(aOldFillColor); + } + } +} + +// ----------------------------------------------------------------------------- + void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) { for( ULONG j = 0, nActionCount = rMtf.GetActionCount(); j < nActionCount; j++ ) @@ -871,20 +914,31 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) { const MetaLineAction* pA = (const MetaLineAction*) pAction; - ImplCheckLineAttr(); + if(pA->GetLineInfo().IsDefault()) + { + ImplCheckLineAttr(); - ImplBeginRecord( WIN_EMR_MOVETOEX ); - ImplWritePoint( pA->GetStartPoint() ); - ImplEndRecord(); + ImplBeginRecord( WIN_EMR_MOVETOEX ); + ImplWritePoint( pA->GetStartPoint() ); + ImplEndRecord(); - ImplBeginRecord( WIN_EMR_LINETO ); - ImplWritePoint( pA->GetEndPoint() ); - ImplEndRecord(); + ImplBeginRecord( WIN_EMR_LINETO ); + ImplWritePoint( pA->GetEndPoint() ); + ImplEndRecord(); - ImplBeginRecord( WIN_EMR_SETPIXELV ); - ImplWritePoint( pA->GetEndPoint() ); - ImplWriteColor( maVDev.GetLineColor() ); - ImplEndRecord(); + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetEndPoint() ); + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } } } break; @@ -983,7 +1037,23 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) case( META_POLYLINE_ACTION ): { if( maVDev.IsLineColor() ) - ImplWritePolygonRecord( ( (const MetaPolyLineAction*) pAction )->GetPolygon(), FALSE ); + { + const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction; + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + ImplWritePolygonRecord( rPoly, FALSE ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } + } } break; diff --git a/svtools/source/filter.vcl/wmf/emfwr.hxx b/svtools/source/filter.vcl/wmf/emfwr.hxx index 150aa1692ade..2d3c8801ba49 100644 --- a/svtools/source/filter.vcl/wmf/emfwr.hxx +++ b/svtools/source/filter.vcl/wmf/emfwr.hxx @@ -42,6 +42,9 @@ // - EMFWriter - // ------------- +class LineInfo; +namespace basegfx { class B2DPolygon; } + class EMFWriter { private: @@ -86,6 +89,7 @@ private: void ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt, const Size& rSz, UINT32 nROP ); void ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth ); + void Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); void ImplWrite( const GDIMetaFile& rMtf ); public: diff --git a/svtools/source/filter.vcl/wmf/wmfwr.cxx b/svtools/source/filter.vcl/wmf/wmfwr.cxx index d25d4e94f97a..30d4ff06c0d2 100644 --- a/svtools/source/filter.vcl/wmf/wmfwr.cxx +++ b/svtools/source/filter.vcl/wmf/wmfwr.cxx @@ -42,8 +42,9 @@ #include <i18nutil/unicode.hxx> //unicode::getUnicodeScriptType #endif - #include <vcl/metric.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> //====================== MS-Windows-defines =============================== @@ -1136,6 +1137,49 @@ void WMFWriter::SetAllAttr() } +void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + aSrcLineInfo = rInfo; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + WMFRecord_PolyLine(Polygon(aCandidate)); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(aSrcLineColor); + const Color aOldFillColor(aSrcFillColor); + + aSrcLineColor = Color( COL_TRANSPARENT ); + aSrcFillColor = aOldLineColor; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + WMFRecord_Polygon(Polygon(aPolygon)); + } + + aSrcLineColor = aOldLineColor; + aSrcFillColor = aOldFillColor; + SetLineAndFillAttr(); + } + } +} + void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) { ULONG nA, nACount; @@ -1176,10 +1220,21 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) case META_LINE_ACTION: { const MetaLineAction* pA = (const MetaLineAction *) pMA; - aSrcLineInfo = pA->GetLineInfo(); - SetLineAndFillAttr(); - WMFRecord_MoveTo( pA->GetStartPoint() ); - WMFRecord_LineTo( pA->GetEndPoint() ); + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_MoveTo( pA->GetStartPoint() ); + WMFRecord_LineTo( pA->GetEndPoint() ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } } break; @@ -1241,9 +1296,22 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) case META_POLYLINE_ACTION: { const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pMA; - aSrcLineInfo = pA->GetLineInfo(); - SetLineAndFillAttr(); - WMFRecord_PolyLine( pA->GetPolygon() ); + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyLine( rPoly ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } } break; diff --git a/svtools/source/filter.vcl/wmf/wmfwr.hxx b/svtools/source/filter.vcl/wmf/wmfwr.hxx index 48986a280404..03ca14e7633f 100644 --- a/svtools/source/filter.vcl/wmf/wmfwr.hxx +++ b/svtools/source/filter.vcl/wmf/wmfwr.hxx @@ -65,6 +65,9 @@ struct WMFWriterAttrStackMember // ------------- class StarSymbolToMSMultiFont; +class LineInfo; +namespace basegfx { class B2DPolygon; } + class WMFWriter { private: @@ -202,6 +205,7 @@ private: void SetLineAndFillAttr(); void SetAllAttr(); + void HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); void WriteRecords(const GDIMetaFile & rMTF); void WriteHeader(const GDIMetaFile & rMTF, BOOL bPlaceable); diff --git a/svtools/source/misc/imap.cxx b/svtools/source/misc/imap.cxx index df7760f7931b..b0aaee113c20 100644 --- a/svtools/source/misc/imap.cxx +++ b/svtools/source/misc/imap.cxx @@ -64,6 +64,12 @@ UINT16 IMapObject::nActualTextEncoding = (UINT16) RTL_TEXTENCODING_DONTKNOW; #pragma optimize ( "", off ) #endif +IMapObject::IMapObject() + : bActive( false ) + , nReadVersion( 0 ) +{ +} + IMapObject::IMapObject( const String& rURL, const String& rAltText, const String& rDesc, const String& rTarget, const String& rName, BOOL bURLActive ) : aURL( rURL ) @@ -72,6 +78,7 @@ IMapObject::IMapObject( const String& rURL, const String& rAltText, const String , aTarget( rTarget ) , aName( rName ) , bActive( bURLActive ) +, nReadVersion( 0 ) { } diff --git a/svtools/source/uno/unoiface.cxx b/svtools/source/uno/unoiface.cxx index a1ff1ad2ac3e..9c7c3eec33d1 100644 --- a/svtools/source/uno/unoiface.cxx +++ b/svtools/source/uno/unoiface.cxx @@ -549,86 +549,6 @@ void VCLXMultiLineEdit::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) } // ---------------------------------------------------- -// class VCLXFileDialog -// ---------------------------------------------------- -/* -VCLXFileDialog::VCLXFileDialog() -{ -} - -VCLXFileDialog::~VCLXFileDialog() -{ -} - -::com::sun::star::uno::Any VCLXFileDialog::queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException) -{ - ::com::sun::star::uno::Any aRet = ::cppu::queryInterface( rType, - SAL_STATIC_CAST( ::com::sun::star::awt::XXX*, this ) ); - return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); -} - -// ::com::sun::star::lang::XTypeProvider -IMPL_XTYPEPROVIDER_START( VCLXFileDialog ) - getCppuType( ( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XXX>* ) NULL ) -IMPL_XTYPEPROVIDER_END - -void VCLXFileDialog::setPath( const ::rtl::OUString& rPath ) -{ - ::vos::OGuard aGuard( GetMutex() ); - - FileDialog* pDlg = (FileDialog*)GetWindow(); - if ( pDlg ) - pDlg->SetPath( ::rtl::OUStringToOString( rPath, CHARSET_SYSTEM ) ); -} - -::rtl::OUString VCLXFileDialog::getPath() -{ - ::vos::OGuard aGuard( GetMutex() ); - - ::rtl::OUString aPath; - FileDialog* pDlg = (FileDialog*)GetWindow(); - if ( pDlg ) - aPath = StringToOUString( pDlg->GetPath(), CHARSET_SYSTEM ); - return aPath; -} - -void VCLXFileDialog::setFilters( const ::com::sun::star::uno::Sequence< ::rtl::OUString>& rFilterNames, const ::com::sun::star::uno::Sequence< ::rtl::OUString>& rMasks ) -{ - ::vos::OGuard aGuard( GetMutex() ); - - FileDialog* pDlg = (FileDialog*)GetWindow(); - if ( pDlg ) - { - sal_uInt32 nFlts = rFilterNames.getLength(); - for ( sal_uInt32 n = 0; n < nFlts; n++ ) - pDlg->AddFilter( - ::rtl::OUStringToOString( rFilterNames.getConstArray()[n], CHARSET_SYSTEM ), - ::rtl::OUStringToOString( rMasks.getConstArray()[n], CHARSET_SYSTEM ) ); - } -} - -void VCLXFileDialog::setCurrentFilter( const ::rtl::OUString& rFilterName ) -{ - ::vos::OGuard aGuard( GetMutex() ); - - FileDialog* pDlg = (FileDialog*)GetWindow(); - if ( pDlg ) - pDlg->SetCurFilter( ::rtl::OUStringToOString( rFilterName, CHARSET_SYSTEM ) ); -} - -::rtl::OUString VCLXFileDialog::getCurrentFilter() -{ - ::vos::OGuard aGuard( GetMutex() ); - - ::rtl::OUString aFilter; - FileDialog* pDlg = (FileDialog*)GetWindow(); - if ( pDlg ) - aFilter = StringToOUString( pDlg->GetCurFilter(), CHARSET_SYSTEM ); - return aFilter; -} -*/ - -// ---------------------------------------------------- // class VCLXFileControl // ---------------------------------------------------- VCLXFileControl::VCLXFileControl() : maTextListeners( *this ) diff --git a/svtools/util/makefile.mk b/svtools/util/makefile.mk index 51ea7a9fef31..22be04f95d3f 100644 --- a/svtools/util/makefile.mk +++ b/svtools/util/makefile.mk @@ -112,6 +112,7 @@ SHL1STDLIBS+= \ $(VCLLIB) \ $(SVLLIB) \ $(SOTLIB) \ + $(BASEGFXLIB) \ $(UNOTOOLSLIB) \ $(TOOLSLIB) \ $(I18NISOLANGLIB) \ diff --git a/toolkit/inc/toolkit/awt/vclxprinter.hxx b/toolkit/inc/toolkit/awt/vclxprinter.hxx index e94864b51280..4db43a3c5d77 100644 --- a/toolkit/inc/toolkit/awt/vclxprinter.hxx +++ b/toolkit/inc/toolkit/awt/vclxprinter.hxx @@ -43,9 +43,7 @@ #include <toolkit/helper/mutexandbroadcasthelper.hxx> #include <cppuhelper/propshlp.hxx> -class Printer; -class String; - +#include "vcl/oldprintadaptor.hxx" // Fuer den Drucker relevante Properties: /* @@ -65,20 +63,17 @@ class VCLXPrinterPropertySet : public ::com::sun::star::awt::XPrinterPropertySe public MutexAndBroadcastHelper, public ::cppu::OPropertySetHelper { -private: - Printer* mpPrinter; +protected: + boost::shared_ptr<Printer> mpPrinter; ::com::sun::star::uno::Reference< ::com::sun::star::awt::XDevice > mxPrnDevice; sal_Int16 mnOrientation; sal_Bool mbHorizontal; - -protected: - public: VCLXPrinterPropertySet( const String& rPrinterName ); virtual ~VCLXPrinterPropertySet(); - Printer* GetPrinter() const { return mpPrinter; } + Printer* GetPrinter() const { return mpPrinter.get(); } ::com::sun::star::uno::Reference< ::com::sun::star::awt::XDevice > GetDevice(); // ::com::sun::star::uno::XInterface @@ -120,6 +115,8 @@ class VCLXPrinter: public ::com::sun::star::awt::XPrinter, public VCLXPrinterPropertySet, public ::cppu::OWeakObject { + boost::shared_ptr<vcl::OldStylePrintAdaptor> mpListener; + JobSetup maInitJobSetup; public: VCLXPrinter( const String& rPrinterName ); ~VCLXPrinter(); diff --git a/toolkit/source/awt/vclxprinter.cxx b/toolkit/source/awt/vclxprinter.cxx index 69d8dd827497..a8059463a297 100644 --- a/toolkit/source/awt/vclxprinter.cxx +++ b/toolkit/source/awt/vclxprinter.cxx @@ -102,10 +102,10 @@ IMPL_XTYPEPROVIDER_END VCLXPrinterPropertySet::VCLXPrinterPropertySet( const String& rPrinterName ) : OPropertySetHelper( BrdcstHelper ) + , mpPrinter( new Printer( rPrinterName ) ) { osl::Guard< vos::IMutex > aSolarGuard( Application::GetSolarMutex() ); - mpPrinter = new Printer( rPrinterName ); mnOrientation = 0; mbHorizontal = sal_False; } @@ -113,8 +113,7 @@ VCLXPrinterPropertySet::VCLXPrinterPropertySet( const String& rPrinterName ) VCLXPrinterPropertySet::~VCLXPrinterPropertySet() { osl::Guard< vos::IMutex > aSolarGuard( Application::GetSolarMutex() ); - - delete mpPrinter; + mpPrinter.reset(); } ::com::sun::star::uno::Reference< ::com::sun::star::awt::XDevice > VCLXPrinterPropertySet::GetDevice() @@ -326,13 +325,16 @@ IMPL_XTYPEPROVIDER_START( VCLXPrinter ) VCLXPrinterPropertySet::getTypes() IMPL_XTYPEPROVIDER_END -sal_Bool VCLXPrinter::start( const ::rtl::OUString& rJobName, sal_Int16 /*nCopies*/, sal_Bool /*bCollate*/ ) throw(::com::sun::star::awt::PrinterException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) +sal_Bool VCLXPrinter::start( const ::rtl::OUString& /*rJobName*/, sal_Int16 /*nCopies*/, sal_Bool /*bCollate*/ ) throw(::com::sun::star::awt::PrinterException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) { ::osl::Guard< ::osl::Mutex > aGuard( Mutex ); sal_Bool bDone = sal_True; - if ( GetPrinter() ) - bDone = GetPrinter()->StartJob( rJobName ); + if ( mpListener.get() ) + { + maInitJobSetup = mpPrinter->GetJobSetup(); + mpListener.reset( new vcl::OldStylePrintAdaptor( mpPrinter ) ); + } return bDone; } @@ -341,24 +343,28 @@ void VCLXPrinter::end( ) throw(::com::sun::star::awt::PrinterException, ::com:: { ::osl::Guard< ::osl::Mutex > aGuard( Mutex ); - if ( GetPrinter() ) - GetPrinter()->EndJob(); + if ( mpListener.get() ) + { + Printer::PrintJob( mpListener, maInitJobSetup ); + mpListener.reset(); + } } void VCLXPrinter::terminate( ) throw(::com::sun::star::uno::RuntimeException) { ::osl::Guard< ::osl::Mutex > aGuard( Mutex ); - if ( GetPrinter() ) - GetPrinter()->AbortJob(); + mpListener.reset(); } ::com::sun::star::uno::Reference< ::com::sun::star::awt::XDevice > VCLXPrinter::startPage( ) throw(::com::sun::star::awt::PrinterException, ::com::sun::star::uno::RuntimeException) { ::osl::Guard< ::osl::Mutex > aGuard( Mutex ); - if ( GetPrinter() ) - GetPrinter()->StartPage(); + if ( mpListener.get() ) + { + mpListener->StartPage(); + } return GetDevice(); } @@ -366,8 +372,10 @@ void VCLXPrinter::endPage( ) throw(::com::sun::star::awt::PrinterException, ::c { ::osl::Guard< ::osl::Mutex > aGuard( Mutex ); - if ( GetPrinter() ) - GetPrinter()->EndPage(); + if ( mpListener.get() ) + { + mpListener->EndPage(); + } } diff --git a/toolkit/source/awt/vclxwindows.cxx b/toolkit/source/awt/vclxwindows.cxx index 7757d170256a..e41de1e8bd25 100644 --- a/toolkit/source/awt/vclxwindows.cxx +++ b/toolkit/source/awt/vclxwindows.cxx @@ -3390,6 +3390,7 @@ void VCLXEdit::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) BASEPROPERTY_PAINTTRANSPARENT, BASEPROPERTY_AUTOHSCROLL, BASEPROPERTY_AUTOVSCROLL, + BASEPROPERTY_VERTICALALIGN, BASEPROPERTY_WRITING_MODE, BASEPROPERTY_CONTEXT_WRITING_MODE, 0); @@ -4283,6 +4284,7 @@ void VCLXDateField::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) BASEPROPERTY_ENFORCE_FORMAT, BASEPROPERTY_TEXT, BASEPROPERTY_HIDEINACTIVESELECTION, + BASEPROPERTY_VERTICALALIGN, BASEPROPERTY_WRITING_MODE, BASEPROPERTY_CONTEXT_WRITING_MODE, BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR, @@ -4624,6 +4626,7 @@ void VCLXTimeField::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) BASEPROPERTY_ENFORCE_FORMAT, BASEPROPERTY_TEXT, BASEPROPERTY_HIDEINACTIVESELECTION, + BASEPROPERTY_VERTICALALIGN, BASEPROPERTY_WRITING_MODE, BASEPROPERTY_CONTEXT_WRITING_MODE, BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR, @@ -4927,6 +4930,7 @@ void VCLXNumericField::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) BASEPROPERTY_VALUE_DOUBLE, BASEPROPERTY_ENFORCE_FORMAT, BASEPROPERTY_HIDEINACTIVESELECTION, + BASEPROPERTY_VERTICALALIGN, BASEPROPERTY_WRITING_MODE, BASEPROPERTY_CONTEXT_WRITING_MODE, BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR, @@ -5521,6 +5525,7 @@ void VCLXCurrencyField::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) BASEPROPERTY_VALUE_DOUBLE, BASEPROPERTY_ENFORCE_FORMAT, BASEPROPERTY_HIDEINACTIVESELECTION, + BASEPROPERTY_VERTICALALIGN, BASEPROPERTY_WRITING_MODE, BASEPROPERTY_CONTEXT_WRITING_MODE, BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR, @@ -5868,6 +5873,7 @@ void VCLXPatternField::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) BASEPROPERTY_TABSTOP, BASEPROPERTY_TEXT, BASEPROPERTY_HIDEINACTIVESELECTION, + BASEPROPERTY_VERTICALALIGN, BASEPROPERTY_WRITING_MODE, BASEPROPERTY_CONTEXT_WRITING_MODE, BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR, diff --git a/toolkit/source/controls/formattedcontrol.cxx b/toolkit/source/controls/formattedcontrol.cxx index 6171067f1185..5ac7a0237479 100644 --- a/toolkit/source/controls/formattedcontrol.cxx +++ b/toolkit/source/controls/formattedcontrol.cxx @@ -160,6 +160,7 @@ namespace toolkit ImplRegisterProperty( BASEPROPERTY_TEXTCOLOR ); ImplRegisterProperty( BASEPROPERTY_HIDEINACTIVESELECTION ); ImplRegisterProperty( BASEPROPERTY_ENFORCE_FORMAT ); + ImplRegisterProperty( BASEPROPERTY_VERTICALALIGN ); ImplRegisterProperty( BASEPROPERTY_WRITING_MODE ); ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE ); ImplRegisterProperty( BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR ); diff --git a/toolkit/source/controls/unocontrols.cxx b/toolkit/source/controls/unocontrols.cxx index 3abacef7b67f..9e508c884f59 100644 --- a/toolkit/source/controls/unocontrols.cxx +++ b/toolkit/source/controls/unocontrols.cxx @@ -476,6 +476,7 @@ void UnoEditControl::getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines ) t // ---------------------------------------------------- UnoControlFileControlModel::UnoControlFileControlModel() { + ImplRegisterProperty( BASEPROPERTY_ALIGN ); ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR ); ImplRegisterProperty( BASEPROPERTY_BORDER ); ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR ); @@ -489,6 +490,7 @@ UnoControlFileControlModel::UnoControlFileControlModel() ImplRegisterProperty( BASEPROPERTY_READONLY ); ImplRegisterProperty( BASEPROPERTY_TABSTOP ); ImplRegisterProperty( BASEPROPERTY_TEXT ); + ImplRegisterProperty( BASEPROPERTY_VERTICALALIGN ); ImplRegisterProperty( BASEPROPERTY_WRITING_MODE ); ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE ); ImplRegisterProperty( BASEPROPERTY_HIDEINACTIVESELECTION ); diff --git a/tools/inc/tools/inetdef.hxx b/tools/inc/tools/inetdef.hxx index 38cd8935e06b..d9861f64961d 100644 --- a/tools/inc/tools/inetdef.hxx +++ b/tools/inc/tools/inetdef.hxx @@ -61,8 +61,6 @@ #define TOOLS_INETDEF_OS "FreeBSD/amd64" #elif defined SINIX #define TOOLS_INETDEF_OS "SINIX" -#elif defined IRIX -#define TOOLS_INETDEF_OS "IRIX" #else // AIX, HPUX, SOLARIS, ... #define TOOLS_INETDEF_OS "Unix" #endif // AIX, HPUX, SOLARIS, ... diff --git a/tools/inc/tools/multisel.hxx b/tools/inc/tools/multisel.hxx index 46fd8947e21b..9de3cc172e70 100644 --- a/tools/inc/tools/multisel.hxx +++ b/tools/inc/tools/multisel.hxx @@ -35,6 +35,9 @@ #include <tools/list.hxx> #include <tools/string.hxx> +#include <vector> +#include <set> + //------------------------------------------------------------------ #ifdef _SV_MULTISEL_CXX @@ -112,4 +115,105 @@ public: const Range& GetRange( ULONG nRange ) const { return *(const Range*)aSels.GetObject(nRange); } }; +class TOOLS_DLLPUBLIC StringRangeEnumerator +{ + struct Range + { + sal_Int32 nFirst; + sal_Int32 nLast; + + Range() : nFirst( -1 ), nLast( -1 ) {} + Range( sal_Int32 i_nFirst, sal_Int32 i_nLast ) : nFirst( i_nFirst ), nLast( i_nLast ) {} + }; + std::vector< StringRangeEnumerator::Range > maSequence; + sal_Int32 mnCount; + sal_Int32 mnMin; + sal_Int32 mnMax; + sal_Int32 mnOffset; + + bool insertRange( sal_Int32 nFirst, sal_Int32 nLast, bool bSequence, bool bMayAdjust ); + bool checkValue( sal_Int32, const std::set< sal_Int32 >* i_pPossibleValues = NULL ) const; +public: + class TOOLS_DLLPUBLIC Iterator + { + const StringRangeEnumerator* pEnumerator; + const std::set< sal_Int32 >* pPossibleValues; + sal_Int32 nRangeIndex; + sal_Int32 nCurrent; + + friend class StringRangeEnumerator; + Iterator( const StringRangeEnumerator* i_pEnum, + const std::set< sal_Int32 >* i_pPossibleValues, + sal_Int32 i_nRange, + sal_Int32 i_nCurrent ) + : pEnumerator( i_pEnum ), pPossibleValues( i_pPossibleValues ) + , nRangeIndex( i_nRange ), nCurrent( i_nCurrent ) {} + public: + Iterator() : pEnumerator( NULL ), pPossibleValues( NULL ), nRangeIndex( -1 ), nCurrent( -1 ) {} + Iterator& operator++(); + sal_Int32 operator*() const; + bool operator==(const Iterator&) const; + bool operator!=(const Iterator& i_rComp) const + { return ! (*this == i_rComp); } + }; + + friend class StringRangeEnumerator::Iterator; + + StringRangeEnumerator() : mnCount( 0 ), mnMin( -1 ), mnMax( -1 ), mnOffset( -1 ) {} + StringRangeEnumerator( const rtl::OUString& i_rInput, + sal_Int32 i_nMinNumber = -1, + sal_Int32 i_nMaxNumber = -1, + sal_Int32 i_nLogicalOffset = -1 + ); + + size_t size() const { return size_t(mnCount); } + Iterator begin( const std::set< sal_Int32 >* i_pPossibleValues = NULL ) const; + Iterator end( const std::set< sal_Int32 >* i_pPossibleValues = NULL ) const; + + sal_Int32 getMin() const { return mnMin; } + void setMin( sal_Int32 i_nMinValue ) { mnMin = i_nMinValue; } + sal_Int32 getMax() const { return mnMax; } + void setMax( sal_Int32 i_nMaxValue ) { mnMax = i_nMaxValue; } + sal_Int32 getLogicalOffset() const { return mnOffset; } + void setLogicalOffset( sal_Int32 i_nOffset ) { mnOffset = i_nOffset; } + + bool setRange( const rtl::OUString& i_rNewRange, bool i_bStrict = false ); + bool hasValue( sal_Int32 nValue, const std::set< sal_Int32 >* i_pPossibleValues = NULL ) const; + + + /** + i_rPageRange: the string to be changed into a sequence of numbers + valid format example "5-3,9,9,7-8" ; instead of ',' ';' or ' ' are allowed as well + o_rPageVector: the output sequence of numbers + i_nLogicalOffset: an offset to be applied to each number in the string before inserting it in the resulting sequence + example: a user enters page numbers from 1 to n (since that is logical) + of course usable page numbers in code would start from 0 and end at n-1 + so the logical offset would be -1 + i_nMinNumber: the minimum allowed number, a negative number means no minimum check + i_nMaxNumber: the maximum allowed number, a negative number means no maximum check + + @returns: true if the input string was valid, o_rPageVector will contain the resulting sequence + false if the input string was invalid, o_rPageVector will be unchanged + + behavior: + - only non-negative sequence numbers are allowed + - only non-negative values in the input string are allowed + - the string "-3" will be either + * an error if no minimum is given + * or result in the sequence i_nMinNumber to 3 + - the string "3-" will be either + * an error if no maximum is given + * or result in the seqeuence 3 to i_nMaxNumber + - an empty string as input is valid and will result in the range [min,max] if given + or an empty vector, if not + */ + static bool getRangesFromString( const rtl::OUString& i_rPageRange, + std::vector< sal_Int32 >& o_rPageVector, + sal_Int32 i_nMinNumber = -1, + sal_Int32 i_nMaxNumber = -1, + sal_Int32 i_nLogicalOffset = -1, + std::set< sal_Int32 >* i_pPossibleValues = NULL + ); +}; + #endif // _SV_MULTISEL_HXX diff --git a/tools/inc/tools/solar.h b/tools/inc/tools/solar.h index cd069886d8b6..195a6fd3ce87 100644 --- a/tools/inc/tools/solar.h +++ b/tools/inc/tools/solar.h @@ -393,8 +393,6 @@ template<typename T> inline T Abs(T a) { return (a>=0?a:-a); } #define __DLLEXTENSION "fi.so" #elif defined FREEBSD && defined X86_64 #define __DLLEXTENSION "fx.so" -#elif defined IRIX - #define __DLLEXTENSION "im.so" #elif defined MACOSX && defined POWERPC #define __DLLEXTENSION "mxp.dylib" #elif defined MACOSX && defined X86 diff --git a/tools/inc/tools/stream.hxx b/tools/inc/tools/stream.hxx index bacaac89fe44..23496322fa4c 100644 --- a/tools/inc/tools/stream.hxx +++ b/tools/inc/tools/stream.hxx @@ -776,6 +776,9 @@ class TOOLS_DLLPUBLIC SvMemoryStream : public SvStream SvMemoryStream (const SvMemoryStream&); SvMemoryStream & operator= (const SvMemoryStream&); + friend class SvCacheStream; + sal_Size GetSize() const { return nSize; } + protected: sal_Size nSize; sal_Size nResize; @@ -817,7 +820,7 @@ public: virtual void ResetError(); - sal_Size GetSize() const { return nSize; } + sal_Size GetEndOfData() const { return nEndOfData; } const void* GetData() { Flush(); return pBuf; } operator const void*() { Flush(); return pBuf; } virtual sal_uInt16 IsA() const; diff --git a/tools/source/fsys/unx.cxx b/tools/source/fsys/unx.cxx index 76910683df13..4a2e3c6ad76a 100644 --- a/tools/source/fsys/unx.cxx +++ b/tools/source/fsys/unx.cxx @@ -36,7 +36,7 @@ #include <stdlib.h> #include <unistd.h> #include <utime.h> -#if defined HPUX || defined LINUX || defined IRIX +#if defined HPUX || defined LINUX #include <mntent.h> #define mnttab mntent #elif defined SCO diff --git a/tools/source/fsys/urlobj.cxx b/tools/source/fsys/urlobj.cxx index f7ffed5e4dd1..e0f711bd2883 100644 --- a/tools/source/fsys/urlobj.cxx +++ b/tools/source/fsys/urlobj.cxx @@ -1022,16 +1022,14 @@ bool INetURLObject::setAbsURIRef(rtl::OUString const & rTheAbsURIRef, if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') { sal_Unicode const * p1 = pPos + 2; - if ( - p1 == pEnd || *p1 == nFragmentDelimiter || *p1 == '/' || - ( - ( - scanDomain(p1, pEnd) > 0 || - scanIPv6reference(p1, pEnd) - ) && - (p1 == pEnd || *p1 == nFragmentDelimiter || *p1 == '/') - ) - ) + while (p1 != pEnd && *p1 != '/' && + *p1 != nFragmentDelimiter) + { + ++p1; + } + if (parseHostOrNetBiosName( + pPos + 2, p1, bOctets, ENCODE_ALL, + RTL_TEXTENCODING_DONTKNOW, true, NULL)) { aSynAbsURIRef. appendAscii(RTL_CONSTASCII_STRINGPARAM("//")); diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx index 7f1eb94b646d..509d2ab4969d 100644 --- a/tools/source/generic/poly.cxx +++ b/tools/source/generic/poly.cxx @@ -1615,7 +1615,16 @@ void Polygon::Clip( const Rectangle& rRect, BOOL bPolygon ) Rectangle Polygon::GetBoundRect() const { DBG_CHKTHIS( Polygon, NULL ); - DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" ); + // Removing the assert. Bezier curves have the attribute that each single + // curve segment defined by four points can not exit the four-point polygon + // defined by that points. This allows to say that the curve segment can also + // never leave the Range of it's defining points. + // The result is that Polygon::GetBoundRect() may not create the minimal + // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes), + // but will always create a valid BoundRect, at least as long as this method + // 'blindly' travels over all points, including control points. + // + // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" ); USHORT nCount = mpImplPolygon->mnPoints; if( ! nCount ) diff --git a/tools/source/memtools/makefile.mk b/tools/source/memtools/makefile.mk index 037dadbf4a46..51d831ec0fed 100644 --- a/tools/source/memtools/makefile.mk +++ b/tools/source/memtools/makefile.mk @@ -47,6 +47,8 @@ SLOFILES= $(SLO)$/contnr.obj \ $(SLO)$/mempool.obj \ $(SLO)$/multisel.obj +EXCEPTIONSFILES= $(SLO)$/multisel.obj $(OBJ)$/multisel.obj + OBJFILES= $(OBJ)$/contnr.obj \ $(OBJ)$/table.obj \ $(OBJ)$/unqidx.obj \ diff --git a/tools/source/memtools/multisel.cxx b/tools/source/memtools/multisel.cxx index 6b32badc283e..5fe920b6998a 100644 --- a/tools/source/memtools/multisel.cxx +++ b/tools/source/memtools/multisel.cxx @@ -41,12 +41,16 @@ #include <tools/debug.hxx> #include <tools/multisel.hxx> +#include "rtl/ustrbuf.hxx" + #ifdef MI_DEBUG #define DBG(x) x #else #define DBG(x) #endif +using namespace rtl; + //================================================================== #ifdef MI_DEBUG @@ -865,3 +869,297 @@ void MultiSelection::SetTotalRange( const Range& rTotRange ) bCurValid = FALSE; nCurIndex = 0; } + +// ----------------------------------------------------------------------- +// +// StringRangeEnumerator +// +// ----------------------------------------------------------------------- +StringRangeEnumerator::StringRangeEnumerator( const rtl::OUString& i_rInput, + sal_Int32 i_nMinNumber, + sal_Int32 i_nMaxNumber, + sal_Int32 i_nLogicalOffset + ) + : mnCount( 0 ) + , mnMin( i_nMinNumber ) + , mnMax( i_nMaxNumber ) + , mnOffset( i_nLogicalOffset ) +{ + setRange( i_rInput ); +} + +bool StringRangeEnumerator::checkValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const +{ + if( mnMin >= 0 && i_nValue < mnMin ) + return false; + if( mnMax >= 0 && i_nValue > mnMax ) + return false; + if( i_nValue < 0 ) + return false; + if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() ) + return false; + return true; +} + +bool StringRangeEnumerator::insertRange( sal_Int32 i_nFirst, sal_Int32 i_nLast, bool bSequence, bool bMayAdjust ) +{ + bool bSuccess = true; + if( bSequence ) + { + if( i_nFirst == -1 ) + i_nFirst = mnMin; + if( i_nLast == -1 ) + i_nLast = mnMax; + if( bMayAdjust ) + { + if( i_nFirst < mnMin ) + i_nFirst = mnMin; + if( i_nFirst > mnMax ) + i_nFirst = mnMax; + if( i_nLast < mnMin ) + i_nLast = mnMin; + if( i_nLast > mnMax ) + i_nLast = mnMax; + } + if( checkValue( i_nFirst ) && checkValue( i_nLast ) ) + { + maSequence.push_back( Range( i_nFirst, i_nLast ) ); + sal_Int32 nNumber = i_nLast - i_nFirst; + nNumber = nNumber < 0 ? -nNumber : nNumber; + mnCount += nNumber + 1; + } + else + bSuccess = false; + } + else + { + if( i_nFirst >= 0 ) + { + if( checkValue( i_nFirst ) ) + { + maSequence.push_back( Range( i_nFirst, i_nFirst ) ); + mnCount++; + } + else + bSuccess = false; + } + if( i_nLast >= 0 ) + { + if( checkValue( i_nLast ) ) + { + maSequence.push_back( Range( i_nLast, i_nLast ) ); + mnCount++; + } + else + bSuccess = false; + } + } + + return bSuccess; +} + +bool StringRangeEnumerator::setRange( const rtl::OUString& i_rNewRange, bool i_bStrict ) +{ + mnCount = 0; + maSequence.clear(); + + // we love special cases + if( i_rNewRange.getLength() == 0 ) + { + if( mnMin >= 0 && mnMax >= 0 ) + { + insertRange( mnMin, mnMax, mnMin != mnMax, ! i_bStrict ); + } + return true; + } + + const sal_Unicode* pInput = i_rNewRange.getStr(); + rtl::OUStringBuffer aNumberBuf( 16 ); + sal_Int32 nLastNumber = -1, nNumber = -1; + bool bSequence = false; + bool bSuccess = true; + while( *pInput ) + { + while( *pInput >= sal_Unicode('0') && *pInput <= sal_Unicode('9') ) + aNumberBuf.append( *pInput++ ); + if( aNumberBuf.getLength() ) + { + if( nNumber != -1 ) + { + if( bSequence ) + { + if( ! insertRange( nLastNumber, nNumber, true, ! i_bStrict ) && i_bStrict ) + { + bSuccess = false; + break; + } + nLastNumber = -1; + } + else + { + if( ! insertRange( nNumber, nNumber, false, ! i_bStrict ) && i_bStrict ) + { + bSuccess = false; + break; + } + } + } + nNumber = aNumberBuf.makeStringAndClear().toInt32(); + nNumber += mnOffset; + } + bool bInsertRange = false; + if( *pInput == sal_Unicode('-') ) + { + nLastNumber = nNumber; + nNumber = -1; + bSequence = true; + } + else if( *pInput == ' ' ) + { + } + else if( *pInput == sal_Unicode(',') || *pInput == sal_Unicode(';') ) + bInsertRange = true; + else if( *pInput ) + { + + bSuccess = false; + break; // parse error + } + + if( bInsertRange ) + { + if( ! insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict ) && i_bStrict ) + { + bSuccess = false; + break; + } + nNumber = nLastNumber = -1; + bSequence = false; + } + if( *pInput ) + pInput++; + } + // insert last entries + insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict ); + + return bSuccess; +} + +bool StringRangeEnumerator::hasValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const +{ + if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() ) + return false; + size_t n = maSequence.size(); + for( size_t i= 0; i < n; ++i ) + { + const StringRangeEnumerator::Range rRange( maSequence[i] ); + if( rRange.nFirst < rRange.nLast ) + { + if( i_nValue >= rRange.nFirst && i_nValue <= rRange.nLast ) + return true; + } + else + { + if( i_nValue >= rRange.nLast && i_nValue <= rRange.nFirst ) + return true; + } + } + return false; +} + +StringRangeEnumerator::Iterator& StringRangeEnumerator::Iterator::operator++() +{ + if( nRangeIndex >= 0 && nCurrent >= 0 && pEnumerator ) + { + const StringRangeEnumerator::Range& rRange( pEnumerator->maSequence[nRangeIndex] ); + bool bRangeChange = false; + if( rRange.nLast < rRange.nFirst ) + { + // backward range + if( nCurrent > rRange.nLast ) + nCurrent--; + else + bRangeChange = true; + } + else + { + // forward range + if( nCurrent < rRange.nLast ) + nCurrent++; + else + bRangeChange = true; + } + if( bRangeChange ) + { + nRangeIndex++; + if( size_t(nRangeIndex) == pEnumerator->maSequence.size() ) + { + // reached the end + nRangeIndex = nCurrent = -1; + } + else + nCurrent = pEnumerator->maSequence[nRangeIndex].nFirst; + } + if( nRangeIndex != -1 && nCurrent != -1 ) + { + if( ! pEnumerator->checkValue( nCurrent, pPossibleValues ) ) + return ++(*this); + } + } + return *this; +} + +sal_Int32 StringRangeEnumerator::Iterator::operator*() const +{ + return nCurrent; +} + +bool StringRangeEnumerator::Iterator::operator==( const Iterator& i_rCompare ) const +{ + return i_rCompare.pEnumerator == pEnumerator && i_rCompare.nRangeIndex == nRangeIndex && i_rCompare.nCurrent == nCurrent; +} + +StringRangeEnumerator::Iterator StringRangeEnumerator::begin( const std::set< sal_Int32 >* i_pPossibleValues ) const +{ + StringRangeEnumerator::Iterator it( this, + i_pPossibleValues, + maSequence.empty() ? -1 : 0, + maSequence.empty() ? -1 : maSequence[0].nFirst ); + if( ! checkValue(*it, i_pPossibleValues ) ) + ++it; + return it; +} + +StringRangeEnumerator::Iterator StringRangeEnumerator::end( const std::set< sal_Int32 >* i_pPossibleValues ) const +{ + return StringRangeEnumerator::Iterator( this, i_pPossibleValues, -1, -1 ); +} + +bool StringRangeEnumerator::getRangesFromString( const OUString& i_rPageRange, + std::vector< sal_Int32 >& o_rPageVector, + sal_Int32 i_nMinNumber, + sal_Int32 i_nMaxNumber, + sal_Int32 i_nLogicalOffset, + std::set< sal_Int32 >* i_pPossibleValues + ) +{ + StringRangeEnumerator aEnum; + aEnum.setMin( i_nMinNumber ); + aEnum.setMax( i_nMaxNumber ); + aEnum.setLogicalOffset( i_nLogicalOffset ); + + bool bRes = aEnum.setRange( i_rPageRange ); + if( bRes ) + { + o_rPageVector.clear(); + o_rPageVector.reserve( aEnum.size() ); + for( StringRangeEnumerator::Iterator it = aEnum.begin( i_pPossibleValues ); + it != aEnum.end( i_pPossibleValues ); ++it ) + { + o_rPageVector.push_back( *it ); + } + } + + return bRes; +} + diff --git a/tools/workben/urltest.cxx b/tools/workben/urltest.cxx index a232f8ebdd93..0e9d22081cb4 100644 --- a/tools/workben/urltest.cxx +++ b/tools/workben/urltest.cxx @@ -1629,6 +1629,20 @@ main() rtl::OUString(urlobj.GetMainURL(INetURLObject::NO_DECODE))); } + if (true) { // #i53184# + rtl::OUString url(RTL_CONSTASCII_USTRINGPARAM("file://comp_name/path")); + bSuccess &= assertEqual( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("#i53184# smart INET_PROT_FILE")), + INetURLObject(url, INET_PROT_FILE).GetMainURL( + INetURLObject::NO_DECODE), + url); + bSuccess &= assertEqual( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("#i53184# strict")), + INetURLObject(url).GetMainURL(INetURLObject::NO_DECODE), url); + } + if (true) { rtl::OUString path; path = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/a/b/c")); diff --git a/transex3/source/inireader.cxx b/transex3/source/inireader.cxx index 0985e788452d..1ff34fad8e95 100644 --- a/transex3/source/inireader.cxx +++ b/transex3/source/inireader.cxx @@ -120,7 +120,7 @@ void INIreader::toStlString( const UnicodeString& str , string& stl_str) char* buffer = new char[ str.length()*3 ]; str.extract( 0 , str.length() , buffer ); stl_str = string( buffer ); - delete buffer; + delete[] buffer; } void INIreader::trim( string& str ) diff --git a/unotools/inc/unotools/confignode.hxx b/unotools/inc/unotools/confignode.hxx index 580274004e1a..2e305030fa2b 100644 --- a/unotools/inc/unotools/confignode.hxx +++ b/unotools/inc/unotools/confignode.hxx @@ -88,6 +88,9 @@ namespace utl /// dtor ~OConfigurationNode() {} + /// returns the local name of the node + ::rtl::OUString getLocalName() const; + /** open a sub node @param _rPath access path of the to-be-opened sub node. May be a hierarchical path. */ diff --git a/unotools/source/config/confignode.cxx b/unotools/source/config/confignode.cxx index 4b1b9fe272db..56d258461e95 100644 --- a/unotools/source/config/confignode.cxx +++ b/unotools/source/config/confignode.cxx @@ -41,6 +41,7 @@ #include <com/sun/star/lang/XComponent.hpp> #include <com/sun/star/util/XStringEscape.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XNamed.hpp> #include <comphelper/extract.hxx> #include <rtl/string.hxx> #if OSL_DEBUG_LEVEL > 0 @@ -139,6 +140,22 @@ namespace utl } //------------------------------------------------------------------------ + ::rtl::OUString OConfigurationNode::getLocalName() const + { + ::rtl::OUString sLocalName; + try + { + Reference< XNamed > xNamed( m_xDirectAccess, UNO_QUERY_THROW ); + sLocalName = xNamed->getName(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sLocalName; + } + + //------------------------------------------------------------------------ ::rtl::OUString OConfigurationNode::normalizeName(const ::rtl::OUString& _rName, NAMEORIGIN _eOrigin) const { ::rtl::OUString sName(_rName); @@ -155,13 +172,9 @@ namespace utl else sName = xEscaper->unescapeString(sName); } - catch(IllegalArgumentException&) - { - OSL_ENSURE(sal_False, "OConfigurationNode::normalizeName: illegal argument (caught an exception saying so)!"); - } catch(Exception&) { - OSL_ENSURE(sal_False, "OConfigurationNode::normalizeName: caught an exception!"); + DBG_UNHANDLED_EXCEPTION(); } } } 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 6598ac71ae91..832d93d4a5a0 100644 --- a/vcl/aqua/source/gdi/makefile.mk +++ b/vcl/aqua/source/gdi/makefile.mk @@ -61,6 +61,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 1c9bdda3fbdb..dedae3ac7cfc 100644 --- a/vcl/aqua/source/gdi/salgdi.cxx +++ b/vcl/aqua/source/gdi/salgdi.cxx @@ -54,6 +54,7 @@ #include "basegfx/polygon/b2dpolygon.hxx" #include "basegfx/polygon/b2dpolygontools.hxx" #include "basegfx/matrix/b2dhommatrix.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> using namespace vcl; @@ -603,7 +604,8 @@ void AquaSalGraphics::EndSetClipRegion() void AquaSalGraphics::SetLineColor() { maLineColor.SetAlpha( 0.0 ); // transparent - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); + if( CheckContext() ) + CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); } // ----------------------------------------------------------------------- @@ -611,7 +613,8 @@ void AquaSalGraphics::SetLineColor() void AquaSalGraphics::SetLineColor( SalColor nSalColor ) { maLineColor = RGBAColor( nSalColor ); - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); + if( CheckContext() ) + CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); } // ----------------------------------------------------------------------- @@ -619,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() ); } // ----------------------------------------------------------------------- @@ -627,7 +631,8 @@ void AquaSalGraphics::SetFillColor() void AquaSalGraphics::SetFillColor( SalColor nSalColor ) { maFillColor = RGBAColor( nSalColor ); - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); + if( CheckContext() ) + CGContextSetFillColor( mrContext, maFillColor.AsArray() ); } // ----------------------------------------------------------------------- @@ -1768,9 +1773,7 @@ BOOL AquaSalGraphics::GetGlyphOutline( long nGlyphId, basegfx::B2DPolyPolygon& r GgoClosePathProc( &aGgoData ); if( mfFontScale != 1.0 ) { - basegfx::B2DHomMatrix aScale; - aScale.scale( +mfFontScale, +mfFontScale ); - rPolyPoly.transform( aScale ); + rPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(+mfFontScale, +mfFontScale)); } return true; } 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/cvtsvm.hxx b/vcl/inc/vcl/cvtsvm.hxx index 8a17015d99cf..c6f4f2c9a126 100644 --- a/vcl/inc/vcl/cvtsvm.hxx +++ b/vcl/inc/vcl/cvtsvm.hxx @@ -85,6 +85,10 @@ #define GDI_COMMENT_COMMENT 1031 #define GDI_UNICODE_COMMENT 1032 +#define GDI_LINEJOIN_ACTION 1033 +#define GDI_EXTENDEDPOLYGON_ACTION 1034 +#define GDI_LINEDASHDOT_ACTION 1035 + // ---------------- // - SVMConverter - // ---------------- diff --git a/vcl/inc/vcl/edit.hxx b/vcl/inc/vcl/edit.hxx index fb99bd028631..ad6a4ee017d9 100644 --- a/vcl/inc/vcl/edit.hxx +++ b/vcl/inc/vcl/edit.hxx @@ -120,6 +120,7 @@ private: SAL_DLLPRIVATE void ImplCopy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard ); SAL_DLLPRIVATE void ImplPaste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard ); SAL_DLLPRIVATE long ImplGetExtraOffset() const; + SAL_DLLPRIVATE long ImplGetTextYPosition() const; SAL_DLLPRIVATE ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > ImplGetInputSequenceChecker() const; SAL_DLLPRIVATE ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > ImplGetBreakIterator() const; 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/lineinfo.hxx b/vcl/inc/vcl/lineinfo.hxx index 60fdc3a3a0b0..33758046c41e 100644 --- a/vcl/inc/vcl/lineinfo.hxx +++ b/vcl/inc/vcl/lineinfo.hxx @@ -32,26 +32,29 @@ #define _SV_LINEINFO_HXX #include <vcl/dllapi.h> - #include <tools/gen.hxx> #include <vcl/vclenum.hxx> +#include <basegfx/vector/b2enums.hxx> // ---------------- // - ImplLineInfo - // ---------------- class SvStream; +namespace basegfx { class B2DPolyPolygon; } struct ImplLineInfo { - ULONG mnRefCount; - LineStyle meStyle; - long mnWidth; - USHORT mnDashCount; - long mnDashLen; - USHORT mnDotCount; - long mnDotLen; - long mnDistance; + ULONG mnRefCount; + LineStyle meStyle; + long mnWidth; + USHORT mnDashCount; + long mnDashLen; + USHORT mnDotCount; + long mnDotLen; + long mnDistance; + + basegfx::B2DLineJoin meLineJoin; ImplLineInfo(); ImplLineInfo( const ImplLineInfo& rImplLineInfo ); @@ -107,10 +110,26 @@ public: void SetDistance( long nDistance ); long GetDistance() const { return mpImplLineInfo->mnDistance; } + void SetLineJoin(basegfx::B2DLineJoin eLineJoin); + basegfx::B2DLineJoin GetLineJoin() const { return mpImplLineInfo->meLineJoin; } + BOOL IsDefault() const { return( !mpImplLineInfo->mnWidth && ( LINE_SOLID == mpImplLineInfo->meStyle ) ); } friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, LineInfo& rLineInfo ); friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo ); + + // helper to check if line width or DashDot is used + bool isDashDotOrFatLineUsed() const; + + // helper to get decomposed polygon data with the LineInfo applied. The source + // hairline polygon is given in io_rLinePolyPolygon. Both given polygons may + // contain results; e.g. when no fat line but DasDot is defined, the resut will + // be in io_rLinePolyPolygon while o_rFillPolyPolygon will be empty. When fat line + // is defined, it will be vice-versa. If none is defined, io_rLinePolyPolygon will + // not be changed (but o_rFillPolyPolygon will be freed) + void applyToB2DPolyPolygon( + basegfx::B2DPolyPolygon& io_rLinePolyPolygon, + basegfx::B2DPolyPolygon& o_rFillPolyPolygon) const; }; #endif // _SV_LINEINFO_HXX 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/menu.hxx b/vcl/inc/vcl/menu.hxx index 8d3ac4e8b505..66f35823b06a 100644 --- a/vcl/inc/vcl/menu.hxx +++ b/vcl/inc/vcl/menu.hxx @@ -93,6 +93,8 @@ typedef USHORT MenuItemBits; #define MIB_POPUPSELECT ((MenuItemBits)0x0020) // not in rsc/vclsrc.hxx because only a prelimitary solution #define MIB_NOSELECT ((MenuItemBits)0x0040) +#define MIB_ICON ((MenuItemBits)0x0080) +#define MIB_TEXT ((MenuItemBits)0x0100) #define MENU_FLAG_NOAUTOMNEMONICS 0x0001 #define MENU_FLAG_HIDEDISABLEDENTRIES 0x0002 diff --git a/vcl/source/gdi/implncvt.hxx b/vcl/inc/vcl/oldprintadaptor.hxx index 2d369d12f253..d8b26433af94 100644 --- a/vcl/source/gdi/implncvt.hxx +++ b/vcl/inc/vcl/oldprintadaptor.hxx @@ -6,9 +6,6 @@ * * OpenOffice.org - a multi-platform office productivity suite * - * $RCSfile: implncvt.hxx,v $ - * $Revision: 1.5 $ - * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify @@ -28,51 +25,28 @@ * ************************************************************************/ -#ifndef _SV_LINECONV_HXX -#define _SV_LINECONV_HXX - -#include <tools/poly.hxx> -#include <vcl/lineinfo.hxx> - -// -------------------- -// - ImplLineConverter -// -------------------- +#ifndef _VCL_OLDPRINTADAPTOR +#define _VCL_OLDPRINTADAPTOR -struct ImplFloatPoint; +#include "vcl/print.hxx" -class ImplLineConverter +namespace vcl { - BOOL mbClosed; - BOOL mbRefPoint; - INT32 mnRefDistance; - - double mfWidthHalf; - LineInfo maLineInfo; - - double mfDashDotLenght; - double mfDistanceLenght; - - UINT32 mnDashCount; - UINT32 mnDotCount; - - Polygon maPolygon; - UINT32 mnFloat0Points; - ImplFloatPoint* mpFloat0; - UINT32 mnFloat1Points; - ImplFloatPoint* mpFloat1; - - UINT32 mnLinesAvailable; - UINT32 mnLines; - - ImplFloatPoint* mpFloatPoint; - + struct ImplOldStyleAdaptorData; + class VCL_DLLPUBLIC OldStylePrintAdaptor : public PrinterController + { + ImplOldStyleAdaptorData* mpData; public: + OldStylePrintAdaptor( const boost::shared_ptr< Printer >& ); + virtual ~OldStylePrintAdaptor(); - ImplLineConverter( const Polygon& rPoly, const LineInfo& rLineInfo, const Point* pRefPoint ); - ~ImplLineConverter(); + void StartPage(); + void EndPage(); - const Polygon* ImplGetFirst(); - const Polygon* ImplGetNext(); -}; + 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 cff866d39459..54eaba057730 100644 --- a/vcl/inc/vcl/outdev.hxx +++ b/vcl/inc/vcl/outdev.hxx @@ -562,6 +562,9 @@ public: // Helper who tries to use SalGDI's DrawPolyLine direct and returns it's bool. Contains no AA check. SAL_DLLPRIVATE bool ImpTryDrawPolyLineDirect(const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth, basegfx::B2DLineJoin eLineJoin); + // Helper for line geometry paint with support for graphic expansion (pattern and fat_to_area) + void impPaintLineGeometryWithEvtlExpand(const LineInfo& rInfo, basegfx::B2DPolyPolygon aLinePolyPolygon); + protected: OutputDevice(); @@ -1111,7 +1114,12 @@ public: */ BOOL HasAlpha(); - void DrawEPS( const Point& rPt, const Size& rSz, + /** Added return value to see if EPS could be painted directly. + Theoreticaly, handing over a matrix would be needed to handle + painting rotated EPS files (e.g. contained mín Metafiles). This + would then need to be supported for Mac and PS printers, but + that's too much for now, wrote #i107046# for this */ + bool DrawEPS( const Point& rPt, const Size& rSz, const GfxLink& rGfxLink, GDIMetaFile* pSubst = NULL ); /// request XCanvas render interface for this OutputDevice @@ -1146,12 +1154,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/toolbox.hxx b/vcl/inc/vcl/toolbox.hxx index 6e4c300ccc40..c2547e4b01ba 100644 --- a/vcl/inc/vcl/toolbox.hxx +++ b/vcl/inc/vcl/toolbox.hxx @@ -124,6 +124,9 @@ typedef USHORT ToolBoxItemBits; #define TIB_DROPDOWN ((ToolBoxItemBits)0x0020) #define TIB_REPEAT ((ToolBoxItemBits)0x0040) #define TIB_DROPDOWNONLY ((ToolBoxItemBits)0x0080 | TIB_DROPDOWN) // this button has only drop down functionality +#define TIB_TEXT_ONLY ((ToolBoxItemBits)0x0100) +#define TIB_ICON_ONLY ((ToolBoxItemBits)0x0200) +#define TIB_TEXTICON ((ToolBoxItemBits) TIB_TEXT_ONLY | TIB_ICON_ONLY ) // ----------------- // - ToolBox-Types - 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/salgdi3.cxx b/vcl/os2/source/gdi/salgdi3.cxx index 573fa7336fb0..b25feee266e4 100644 --- a/vcl/os2/source/gdi/salgdi3.cxx +++ b/vcl/os2/source/gdi/salgdi3.cxx @@ -1361,10 +1361,8 @@ BOOL Os2SalGraphics::GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& rB // rescaling needed for the PolyPolygon conversion if( rB2DPolyPoly.count() ) { - ::basegfx::B2DHomMatrix aMatrix; - aMatrix.scale( 1.0/256, 1.0/256 ); - aMatrix.scale( mfFontScale, mfFontScale ); - rB2DPolyPoly.transform( aMatrix ); + const double fFactor((1.0/256) * mfFontScale); + rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor)); } return bRet; 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 b654e034470f..320f235a8c30 100644 --- a/vcl/source/control/edit.cxx +++ b/vcl/source/control/edit.cxx @@ -492,6 +492,17 @@ void Edit::ImplInvalidateOrRepaint( xub_StrLen nStart, xub_StrLen nEnd ) // ----------------------------------------------------------------------- +long Edit::ImplGetTextYPosition() const +{ + if ( GetStyle() & WB_TOP ) + return ImplGetExtraOffset(); + else if ( GetStyle() & WB_BOTTOM ) + return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraOffset(); + return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2; +} + +// ----------------------------------------------------------------------- + void Edit::ImplRepaint( xub_StrLen nStart, xub_StrLen nEnd, bool bLayout ) { if ( !IsReallyVisible() ) @@ -516,10 +527,8 @@ void Edit::ImplRepaint( xub_StrLen nStart, xub_StrLen nEnd, bool bLayout ) GetCaretPositions( aText, pDX, nStart, nEnd ); } - // center vertically - long nH = GetOutputSize().Height(); long nTH = GetTextHeight(); - Point aPos( mnXOffset, (nH-nTH)/2 ); + Point aPos( mnXOffset, ImplGetTextYPosition() ); if( bLayout ) { @@ -1193,7 +1202,7 @@ void Edit::ImplShowCursor( BOOL bOnlyIfVisible ) long nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset(); // Cursor muss im sichtbaren Bereich landen: - Size aOutSize = GetOutputSizePixel(); + const Size aOutSize = GetOutputSizePixel(); if ( (nCursorPosX < 0) || (nCursorPosX >= aOutSize.Width()) ) { long nOldXOffset = mnXOffset; @@ -1227,8 +1236,8 @@ void Edit::ImplShowCursor( BOOL bOnlyIfVisible ) ImplInvalidateOrRepaint(); } - long nTextHeight = GetTextHeight(); - long nCursorPosY = (aOutSize.Height()-nTextHeight) / 2; + const long nTextHeight = GetTextHeight(); + const long nCursorPosY = ImplGetTextYPosition(); pCursor->SetPos( Point( nCursorPosX, nCursorPosY ) ); pCursor->SetSize( Size( nCursorWidth, nTextHeight ) ); pCursor->Show(); @@ -2831,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 6698f51b7ab1..3dbc69de8a96 100644 --- a/vcl/source/control/fixed.cxx +++ b/vcl/source/control/fixed.cxx @@ -1044,6 +1044,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/bmpconv.cxx b/vcl/source/gdi/bmpconv.cxx index 9d9b81ba50d4..03d85acb0159 100644 --- a/vcl/source/gdi/bmpconv.cxx +++ b/vcl/source/gdi/bmpconv.cxx @@ -192,7 +192,8 @@ BmpTransporter::BmpTransporter( const Bitmap& rBM ) m_aSize.Height = rBM.GetSizePixel().Height(); SvMemoryStream aStream; rBM.Write( aStream, FALSE, TRUE ); - m_aBM = Sequence<sal_Int8>((const sal_Int8*)aStream.GetData(), aStream.GetSize() ); + m_aBM = Sequence<sal_Int8>(static_cast<const sal_Int8*>(aStream.GetData()), + aStream.GetEndOfData()); } BmpTransporter::~BmpTransporter() diff --git a/vcl/source/gdi/cvtsvm.cxx b/vcl/source/gdi/cvtsvm.cxx index 4ecb89ec5a8e..8c4b6f1a2cb2 100644 --- a/vcl/source/gdi/cvtsvm.cxx +++ b/vcl/source/gdi/cvtsvm.cxx @@ -88,23 +88,6 @@ void ImplReadPoly( SvStream& rIStm, Polygon& rPoly ) // ------------------------------------------------------------------------ -void ImplWritePoly( SvStream& rOStm, const Polygon& rPoly ) -{ - // #i102224# Here the evtl. curved nature of Polygon was - // ignored (for all those Years). Adapted to at least write - // a polygon representing the curve as good as possible - Polygon aSimplePoly; - rPoly.AdaptiveSubdivide(aSimplePoly); - INT32 nSize = aSimplePoly.GetSize(); - - rOStm << nSize; - - for( INT32 i = 0; i < nSize; i++ ) - rOStm << aSimplePoly[ (USHORT) i ]; -} - -// ------------------------------------------------------------------------ - void ImplReadPolyPoly( SvStream& rIStm, PolyPolygon& rPolyPoly ) { Polygon aPoly; @@ -139,10 +122,9 @@ void ImplWritePolyPolyAction( SvStream& rOStm, const PolyPolygon& rPolyPoly ) // #i102224# Here the evtl. curved nature of Polygon was // ignored (for all those Years). Adapted to at least write // a polygon representing the curve as good as possible - const Polygon& rPoly = rPolyPoly[ n ]; - Polygon aSimplePoly; - rPoly.AdaptiveSubdivide(aSimplePoly); - const USHORT nSize = aSimplePoly.GetSize(); + Polygon aSimplePoly; + rPolyPoly[n].AdaptiveSubdivide(aSimplePoly); + const USHORT nSize(aSimplePoly.GetSize()); rOStm << (INT32) nSize; @@ -388,6 +370,128 @@ void ImplSkipActions( SvStream& rIStm, ULONG nSkipCount ) } } +// ------------------------------------------------------------------------ + +bool ImplWriteExtendedPolyPolygonAction(SvStream& rOStm, const PolyPolygon& rPolyPolygon, bool bOnlyWhenCurve) +{ + const sal_uInt16 nPolygonCount(rPolyPolygon.Count()); + + if(nPolygonCount) + { + sal_uInt32 nAllPolygonCount(0); + sal_uInt32 nAllPointCount(0); + sal_uInt32 nAllFlagCount(0); + sal_uInt16 a(0); + + for(a = 0; a < nPolygonCount; a++) + { + const Polygon& rCandidate = rPolyPolygon.GetObject(a); + const sal_uInt16 nPointCount(rCandidate.GetSize()); + + if(nPointCount) + { + nAllPolygonCount++; + nAllPointCount += nPointCount; + + if(rCandidate.HasFlags()) + { + nAllFlagCount += nPointCount; + } + } + } + + if((bOnlyWhenCurve && nAllFlagCount) || (!bOnlyWhenCurve && nAllPointCount)) + { + rOStm << (INT16) GDI_EXTENDEDPOLYGON_ACTION; + + const sal_Int32 nActionSize( + 4 + // Action size + 2 + // PolygonCount + (nAllPolygonCount * 2) + // Points per polygon + (nAllPointCount << 3) + // Points themselves + nAllPolygonCount + // Bool if (when poly has points) it has flags, too + nAllFlagCount); // Flags themselves + + rOStm << nActionSize; + rOStm << (sal_uInt16)nAllPolygonCount; + + for(a = 0; a < nPolygonCount; a++) + { + const Polygon& rCandidate = rPolyPolygon.GetObject(a); + const sal_uInt16 nPointCount(rCandidate.GetSize()); + + if(nPointCount) + { + rOStm << nPointCount; + + for(sal_uInt16 b(0); b < nPointCount; b++) + { + rOStm << rCandidate[b]; + } + + if(rCandidate.HasFlags()) + { + rOStm << (BYTE)true; + + for(sal_uInt16 c(0); c < nPointCount; c++) + { + rOStm << (BYTE)rCandidate.GetFlags(c); + } + } + else + { + rOStm << (BYTE)false; + } + } + } + + return true; + } + } + + return false; +} + +// ------------------------------------------------------------------------ + +void ImplReadExtendedPolyPolygonAction(SvStream& rIStm, PolyPolygon& rPolyPoly) +{ + rPolyPoly.Clear(); + sal_uInt16 nPolygonCount(0); + rIStm >> nPolygonCount; + + for(sal_uInt16 a(0); a < nPolygonCount; a++) + { + sal_uInt16 nPointCount(0); + rIStm >> nPointCount; + Polygon aCandidate(nPointCount); + + if(nPointCount) + { + for(sal_uInt16 b(0); b < nPointCount; b++) + { + rIStm >> aCandidate[b]; + } + + BYTE bHasFlags(false); + rIStm >> bHasFlags; + + if(bHasFlags) + { + BYTE aPolyFlags(0); + + for(sal_uInt16 c(0); c < nPointCount; c++) + { + rIStm >> aPolyFlags; + aCandidate.SetFlags(c, (PolyFlags)aPolyFlags); + } + } + } + + rPolyPoly.Insert(aCandidate); + } +} + // ---------------- // - SVMConverter - // ---------------- @@ -460,6 +564,7 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) rMtf.SetPrefSize( aPrefSz ); rMtf.SetPrefMapMode( aMapMode ); + sal_uInt32 nLastPolygonAction(0); for( INT32 i = 0L; i < nActions; i++ ) { @@ -493,6 +598,99 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) } break; + case (GDI_LINEJOIN_ACTION) : + { + INT16 nLineJoin(0); + rIStm >> nLineJoin; + aLineInfo.SetLineJoin((basegfx::B2DLineJoin)nLineJoin); + } + break; + + case (GDI_LINEDASHDOT_ACTION) : + { + INT16 a(0); + INT32 b(0); + + rIStm >> a; aLineInfo.SetDashCount(a); + rIStm >> b; aLineInfo.SetDashLen(b); + rIStm >> a; aLineInfo.SetDotCount(a); + rIStm >> b; aLineInfo.SetDotLen(b); + rIStm >> b; aLineInfo.SetDistance(b); + + if(((aLineInfo.GetDashCount() && aLineInfo.GetDashLen()) + || (aLineInfo.GetDotCount() && aLineInfo.GetDotLen())) + && aLineInfo.GetDistance()) + { + aLineInfo.SetStyle(LINE_DASH); + } + } + break; + + case (GDI_EXTENDEDPOLYGON_ACTION) : + { + // read the PolyPolygon in every case + PolyPolygon aInputPolyPolygon; + ImplReadExtendedPolyPolygonAction(rIStm, aInputPolyPolygon); + + // now check if it can be set somewhere + if(nLastPolygonAction < rMtf.GetActionCount()) + { + MetaPolyLineAction* pPolyLineAction = dynamic_cast< MetaPolyLineAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolyLineAction) + { + // replace MetaPolyLineAction when we have a single polygon. Do not rely on the + // same point count; the originally written GDI_POLYLINE_ACTION may have been + // Subdivided for better quality for older usages + if(1 == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolyLineAction( + aInputPolyPolygon.GetObject(0), + pPolyLineAction->GetLineInfo()), + nLastPolygonAction); + pPolyLineAction->Delete(); + } + } + else + { + MetaPolyPolygonAction* pPolyPolygonAction = dynamic_cast< MetaPolyPolygonAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolyPolygonAction) + { + // replace MetaPolyPolygonAction when we have a curved polygon. Do rely on the + // same sub-polygon count + if(pPolyPolygonAction->GetPolyPolygon().Count() == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolyPolygonAction( + aInputPolyPolygon), + nLastPolygonAction); + pPolyPolygonAction->Delete(); + } + } + else + { + MetaPolygonAction* pPolygonAction = dynamic_cast< MetaPolygonAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolygonAction) + { + // replace MetaPolygonAction + if(1 == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolygonAction( + aInputPolyPolygon.GetObject(0)), + nLastPolygonAction); + pPolygonAction->Delete(); + } + } + } + } + } + } + break; + case( GDI_RECT_ACTION ): { ImplReadRect( rIStm, aRect ); @@ -583,6 +781,7 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) case( GDI_POLYLINE_ACTION ): { ImplReadPoly( rIStm, aActionPoly ); + nLastPolygonAction = rMtf.GetActionCount(); if( bFatLine ) rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) ); @@ -604,7 +803,10 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) ); } else + { + nLastPolygonAction = rMtf.GetActionCount(); rMtf.AddAction( new MetaPolygonAction( aActionPoly ) ); + } } break; @@ -625,7 +827,10 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) ); } else + { + nLastPolygonAction = rMtf.GetActionCount(); rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); + } } break; @@ -1257,12 +1462,32 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, { MetaLineAction* pAct = (MetaLineAction*) pAction; const LineInfo& rInfo = pAct->GetLineInfo(); - const BOOL bFatLine = ( !rInfo.IsDefault() && ( LINE_NONE != rInfo.GetStyle() ) ); + const bool bFatLine(!rInfo.IsDefault() && (LINE_NONE != rInfo.GetStyle())); + const bool bLineJoin(bFatLine && basegfx::B2DLINEJOIN_ROUND != rInfo.GetLineJoin()); + const bool bLineDashDot(LINE_DASH == rInfo.GetStyle()); if( bFatLine ) { ImplWritePushAction( rOStm ); ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() ); + + if(bLineJoin) + { + rOStm << (INT16) GDI_LINEJOIN_ACTION; + rOStm << (INT32) 6; + rOStm << (INT16) rInfo.GetLineJoin(); + } + + if(bLineDashDot) + { + rOStm << (INT16) GDI_LINEDASHDOT_ACTION; + rOStm << (INT32) 4 + 16; + rOStm << (INT16)rInfo.GetDashCount(); + rOStm << (INT32)rInfo.GetDashLen(); + rOStm << (INT16)rInfo.GetDotCount(); + rOStm << (INT32)rInfo.GetDotLen(); + rOStm << (INT32)rInfo.GetDistance(); + } } rOStm << (INT16) GDI_LINE_ACTION; @@ -1275,6 +1500,16 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, { ImplWritePopAction( rOStm ); nCount += 3; + + if(bLineJoin) + { + nCount += 1; + } + + if(bLineDashDot) + { + nCount += 1; + } } } break; @@ -1355,30 +1590,47 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, for( USHORT n = 0; n < nPoints; n++ ) rOStm << aChordPoly[ n ]; - nCount++; } break; case( META_POLYLINE_ACTION ): { + // #i102224# MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction; - const Polygon& rPoly = pAct->GetPolygon(); - // #i102224# Here the evtl. curved nature of Polygon was // ignored (for all those Years). Adapted to at least write // a polygon representing the curve as good as possible - Polygon aSimplePoly; - rPoly.AdaptiveSubdivide(aSimplePoly); - - const LineInfo& rInfo = pAct->GetLineInfo(); - const USHORT nPoints = aSimplePoly.GetSize(); - const BOOL bFatLine = ( !rInfo.IsDefault() && ( LINE_NONE != rInfo.GetStyle() ) ); + Polygon aSimplePoly; + pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly); + const LineInfo& rInfo = pAct->GetLineInfo(); + const USHORT nPoints(aSimplePoly.GetSize()); + const bool bFatLine(!rInfo.IsDefault() && (LINE_NONE != rInfo.GetStyle())); + const bool bLineJoin(bFatLine && basegfx::B2DLINEJOIN_ROUND != rInfo.GetLineJoin()); + const bool bLineDashDot(LINE_DASH == rInfo.GetStyle()); if( bFatLine ) { ImplWritePushAction( rOStm ); ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() ); + + if(bLineJoin) + { + rOStm << (INT16) GDI_LINEJOIN_ACTION; + rOStm << (INT32) 6; + rOStm << (INT16) rInfo.GetLineJoin(); + } + } + + if(bLineDashDot) + { + rOStm << (INT16) GDI_LINEDASHDOT_ACTION; + rOStm << (INT32) 4 + 16; + rOStm << (INT16)rInfo.GetDashCount(); + rOStm << (INT32)rInfo.GetDashLen(); + rOStm << (INT16)rInfo.GetDotCount(); + rOStm << (INT32)rInfo.GetDotLen(); + rOStm << (INT32)rInfo.GetDistance(); } rOStm << (INT16) GDI_POLYLINE_ACTION; @@ -1386,30 +1638,45 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, rOStm << (INT32) nPoints; for( USHORT n = 0; n < nPoints; n++ ) + { rOStm << aSimplePoly[ n ]; + } nCount++; + const PolyPolygon aPolyPolygon(pAct->GetPolygon()); + if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true)) + { + nCount++; + } + if( bFatLine ) { ImplWritePopAction( rOStm ); nCount += 3; + + if(bLineJoin) + { + nCount += 1; + } + } + + if(bLineDashDot) + { + nCount += 1; } } break; case( META_POLYGON_ACTION ): { - MetaPolygonAction* pAct = (MetaPolygonAction*) pAction; - const Polygon& rPoly = pAct->GetPolygon(); - + MetaPolygonAction* pAct = (MetaPolygonAction*)pAction; // #i102224# Here the evtl. curved nature of Polygon was // ignored (for all those Years). Adapted to at least write // a polygon representing the curve as good as possible - Polygon aSimplePoly; - rPoly.AdaptiveSubdivide(aSimplePoly); - - const USHORT nPoints = aSimplePoly.GetSize(); + Polygon aSimplePoly; + pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly); + const USHORT nPoints(aSimplePoly.GetSize()); rOStm << (INT16) GDI_POLYGON_ACTION; rOStm << (INT32) ( 8 + ( nPoints << 3 ) ); @@ -1419,6 +1686,12 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, rOStm << aSimplePoly[ n ]; nCount++; + + const PolyPolygon aPolyPolygon(pAct->GetPolygon()); + if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true)) + { + nCount++; + } } break; @@ -1427,6 +1700,11 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction; ImplWritePolyPolyAction( rOStm, pAct->GetPolyPolygon() ); nCount++; + + if(ImplWriteExtendedPolyPolygonAction(rOStm, pAct->GetPolyPolygon(), true)) + { + nCount++; + } } break; 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/implncvt.cxx b/vcl/source/gdi/implncvt.cxx deleted file mode 100644 index e59fde15b5be..000000000000 --- a/vcl/source/gdi/implncvt.cxx +++ /dev/null @@ -1,577 +0,0 @@ -/************************************************************************* - * - * 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: implncvt.cxx,v $ - * $Revision: 1.10.136.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 <vcl/salbtype.hxx> -#ifndef _SV_IMPLNCVT_HXX -#include "implncvt.hxx" -#endif - -// ----------- -// - Defines - -// ----------- - -#define CURVE_LEFT 1 -#define CURVE_RIGHT 2 -#define CURVE_STRAIGHTON 3 - -// ----------------- -// - ImplFloatPoint -// ----------------- - -struct ImplFloatPoint -{ - double fX; - double fY; - - inline ImplFloatPoint() {} - inline ImplFloatPoint( const Point& rPoint ) { fX = rPoint.X(); fY = rPoint.Y(); } - inline ImplFloatPoint( double _fX, double _fY ) { fX = _fX; fY = _fY; } - inline ImplFloatPoint( const ImplFloatPoint& rPoint ) { fX = rPoint.fX; fY = rPoint.fY; } - inline ~ImplFloatPoint() {} - - void operator+=( const ImplFloatPoint& rPoint ) { fX += rPoint.fX; fY += rPoint.fY; } - void operator-=( const ImplFloatPoint& rPoint ) { fX -= rPoint.fX; fY -= rPoint.fY; } - void operator*=( const double& rD ) { fX *= rD; fY *= rD; } - BOOL operator==( const ImplFloatPoint& rPoint ) const { return ( ( rPoint.fX == fX ) && ( rPoint.fY == fY ) ); } - void operator=( const Point& rPoint ) { fX = rPoint.X(); fY = rPoint.Y(); } - - ImplFloatPoint GetOVec( const ImplFloatPoint& rPoint ) const; - ImplFloatPoint GetNVec( const ImplFloatPoint& rPoint ) const; -}; - -// ----------------------------------------------------------------------------- - -ImplFloatPoint ImplFloatPoint::GetOVec( const ImplFloatPoint& rPoint ) const -{ - double fxt = rPoint.fX - fX; - double fyt = rPoint.fY - fY; - double fL; - - if( fyt != 0.0 ) - { - fyt = -fxt / fyt; - fL = sqrt( 1 + fyt * fyt ); - - return ImplFloatPoint( 1.0 / fL, fyt / fL ); - } - else - return ImplFloatPoint( fyt, ( fxt > 0.0 ) ? 1.0 : -1.0 ); -}; - -// ----------------------------------------------------------------------------- - -ImplFloatPoint ImplFloatPoint::GetNVec( const ImplFloatPoint& rPoint ) const -{ - const double fxt = rPoint.fX - fX; - const double fyt = rPoint.fY - fY; - const double fL = hypot( fxt, fyt ); - - return ImplFloatPoint( fxt / fL, fyt / fL ); -}; - -// -------------------- -// - ImplLineConverter -// -------------------- - -ImplLineConverter::ImplLineConverter( const Polygon& rPolygon, const LineInfo& rLineInfo, const Point* pRefPoint ) : - mbRefPoint ( FALSE ), - mfWidthHalf ( rLineInfo.GetWidth() >> 1 ), - maLineInfo ( rLineInfo ), - mpFloat0 ( new ImplFloatPoint[ 6 ] ), - mpFloat1 ( new ImplFloatPoint[ 6 ] ), - mnLines ( 0 ), - mpFloatPoint ( NULL ) -{ - UINT16 nIndex, nPolySize = rPolygon.GetSize(); - if ( nPolySize ) - { - if( rPolygon.GetFlags( 0 ) == POLY_NORMAL ) - { - mpFloatPoint = new ImplFloatPoint[ nPolySize ]; - mpFloatPoint[ 0 ] = rPolygon[ 0 ]; - - nIndex = 0; - - while( ++nIndex < nPolySize ) // doppelte Punkte eliminieren und ein FloatPointArray anlegen - { - if( rPolygon.GetFlags( nIndex ) == POLY_NORMAL ) - { - double nxt = mpFloatPoint[ mnLines ].fX; - double nyt = mpFloatPoint[ mnLines ].fY; - - if ( ( nxt == rPolygon[ nIndex ].X() ) && ( nyt == rPolygon[ nIndex ].Y() ) ) - continue; - - mpFloatPoint[ ++mnLines ] = rPolygon[ nIndex ]; - } - else - { - DBG_ERROR( "Bezier points not supported!" ); - } - } - mbClosed = ( mpFloatPoint[ 0 ] == mpFloatPoint[ mnLines ] ) ; - - if ( ( mnLines == 1 ) && ( maLineInfo.GetStyle() == LINE_DASH ) ) - { - BOOL bX = mpFloatPoint[ 0 ].fY == mpFloatPoint[ 1 ].fY; - BOOL bY = mpFloatPoint[ 0 ].fX == mpFloatPoint[ 1 ].fX; - mbRefPoint = pRefPoint && ( bX || bY ); - if ( mbRefPoint ) - { - if ( !maLineInfo.GetDashCount() ) - { - maLineInfo.SetDashCount( maLineInfo.GetDotCount() ); - maLineInfo.SetDashLen( maLineInfo.GetDotLen() ); - maLineInfo.SetDotCount( 0 ); - } - INT32 nDistance = maLineInfo.GetDistance(); - INT32 nDashLen = maLineInfo.GetDashCount() * ( maLineInfo.GetDashLen() + nDistance ); - INT32 nDotLen = maLineInfo.GetDotCount() * ( maLineInfo.GetDotLen() + nDistance ); - if ( bX ) - { - if ( mpFloatPoint[ 1 ].fX > mpFloatPoint[ 0 ].fX ) - { - ImplFloatPoint aFloat = mpFloatPoint[ 0 ]; - mpFloatPoint[ 0 ] = mpFloatPoint[ 1 ]; - mpFloatPoint[ 1 ] = aFloat; - } - mnRefDistance = (INT32)mpFloatPoint[ mnLines ].fX - pRefPoint->X(); - } - else - { - if ( mpFloatPoint[ 1 ].fY > mpFloatPoint[ 0 ].fY ) - { - ImplFloatPoint aFloat = mpFloatPoint[ 0 ]; - mpFloatPoint[ 0 ] = mpFloatPoint[ 1 ]; - mpFloatPoint[ 1 ] = aFloat; - } - mnRefDistance = (INT32)mpFloatPoint[ mnLines ].fY - pRefPoint->Y(); - } - -// mnRefDistance = ( (INT32)mpFloatPoint[ mnLines ].fX - pRefPoint->X() ) + -// ( (INT32)mpFloatPoint[ mnLines ].fY - pRefPoint->Y() ); - - mnRefDistance = mnRefDistance % ( nDashLen + nDotLen ); - if ( mnRefDistance < 0 ) - mnRefDistance = ( nDashLen + nDotLen ) + mnRefDistance; - } - } - } - } -}; - -//------------------------------------------------------------------------ - -ImplLineConverter::~ImplLineConverter() -{ - delete[] mpFloat0; - delete[] mpFloat1; - delete[] mpFloatPoint; -}; - -//------------------------------------------------------------------------ - -const Polygon* ImplLineConverter::ImplGetFirst() -{ - mnFloat1Points = 0; - mnLinesAvailable = mnLines; - - if ( mnLines ) - { - if ( maLineInfo.GetStyle() == LINE_DASH ) - { - mnDashCount = maLineInfo.GetDashCount(); - mnDotCount = maLineInfo.GetDotCount(); - mfDashDotLenght = mnDashCount ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); - - if ( mbRefPoint ) - { - INT32 nDistance = maLineInfo.GetDistance(); - INT32 nDashLen = maLineInfo.GetDashLen() + nDistance; - INT32 nDashesLen = maLineInfo.GetDashCount() * nDashLen; - INT32 nDotLen = maLineInfo.GetDotLen() + nDistance; - - if ( mnRefDistance >= nDashesLen ) - { - // get dotcount - if ( nDotLen ) - { - INT32 nLen = ( mnRefDistance - nDashesLen ) % nDotLen; - if ( nLen >= maLineInfo.GetDotLen() ) - { - mnDotCount -= 1 + ( mnRefDistance - nDashesLen ) / nDotLen; - if ( mnDotCount ) - mnDashCount = 0; - else - mnDotCount = maLineInfo.GetDotCount(); - mfDashDotLenght = 0.0; - mfDistanceLenght = ( maLineInfo.GetDotLen() + nDistance ) - nLen; - } - else - { - mnDashCount = 0; - mfDashDotLenght = maLineInfo.GetDotLen() - nLen; - mnDotCount -= ( mnRefDistance - nDashesLen ) / nDotLen; - } - } - } - else - { - if ( nDashLen ) - { - // get dashcount - INT32 nLen = mnRefDistance % nDashLen; - if ( nLen >= maLineInfo.GetDashLen() ) - { - mfDashDotLenght = 0.0; - mfDistanceLenght = ( maLineInfo.GetDashLen() + nDistance ) - nLen; - mnDashCount -= 1 + ( mnRefDistance / nDashLen ); - } - else - { - mfDashDotLenght = maLineInfo.GetDashLen() - nLen; - mnDashCount -= ( mnRefDistance / nDashLen ); - } - } - } - if ( ! ( mnDashCount | mnDotCount ) ) - { - mnDashCount = maLineInfo.GetDashCount(); - mnDotCount = maLineInfo.GetDotCount(); - } - if ( ( mfDashDotLenght == 0.0 ) && ( mfDistanceLenght == 0.0 ) ) - mfDistanceLenght = maLineInfo.GetDistance(); - } - } - } - return ImplGetNext(); -}; - -//------------------------------------------------------------------------ - -const Polygon* ImplLineConverter::ImplGetNext() -{ - while( mnFloat1Points || mnLinesAvailable ) - { - if ( maLineInfo.GetWidth() > 1 ) - { - if ( !mnFloat1Points ) - { - ImplFloatPoint aPointA( mpFloatPoint[ mnLinesAvailable-- ] ); - ImplFloatPoint aPointB( mpFloatPoint[ mnLinesAvailable ] ); - ImplFloatPoint aOVecAB( aPointA.GetOVec( aPointB ) ); - ImplFloatPoint aN1Vec( aPointA.GetNVec( aPointB ) ); - aN1Vec *= mfWidthHalf; - - if ( !mbClosed && ( ( mnLinesAvailable + 1 ) == mnLines ) ) - aPointA -= aN1Vec; - - aOVecAB *= mfWidthHalf; - mpFloat0[ 0 ] = aPointA; - mpFloat0[ 0 ] -= aOVecAB; - mpFloat0[ 3 ] = aPointA; - mpFloat0[ 3 ] += aOVecAB; - mpFloat0[ 1 ] = aPointB; - mpFloat0[ 1 ] -= aOVecAB; - mpFloat0[ 2 ] = aPointB; - mpFloat0[ 2 ] += aOVecAB; - - double f1D = ( aN1Vec.fX == 0 ) ? 1 : ( aN1Vec.fY / aN1Vec.fX ); - double f2D = -f1D; - - mnFloat0Points = 4; - - int nDirection; - - BOOL bContinues = ( mnLinesAvailable || mbClosed ); - if ( bContinues ) - { - ImplFloatPoint aPointC; - - if ( mnLinesAvailable ) - aPointC = mpFloatPoint[ mnLinesAvailable - 1 ]; - else - aPointC = mpFloatPoint[ mnLines - 1 ]; - - ImplFloatPoint aOVecBC( aPointB.GetOVec( aPointC ) ); - aOVecBC *= mfWidthHalf; - ImplFloatPoint aPointR0( aPointB ); - aPointR0 -= aOVecBC; - ImplFloatPoint aPointR1( aPointB ); - aPointR1 += aOVecBC; - ImplFloatPoint aN2Vec( aPointB.GetNVec( aPointC ) ); - aN2Vec *= mfWidthHalf; - - f2D = ( fabs( aN2Vec.fX ) < 0.00000001 ) ? 1 : ( aN2Vec.fY / aN2Vec.fX ); - if ( fabs( f1D - f2D ) < 0.00000001 ) - nDirection = CURVE_STRAIGHTON; - else - { - if ( ( aN1Vec.fX * aN2Vec.fY - aN1Vec.fY * aN2Vec.fX ) > 0 ) - nDirection = CURVE_LEFT; - else - nDirection = CURVE_RIGHT; - } - if ( nDirection != CURVE_STRAIGHTON ) - { - double fWidth; - ImplFloatPoint aDestPoint; - if ( hypot( aPointR0.fX - aPointA.fX, aPointR0.fY - aPointA.fY ) > hypot( aPointR1.fX - aPointA.fX, aPointR1.fY - aPointA.fY ) ) - aDestPoint = aPointR0; - else - aDestPoint = aPointR1; - - UINT16 nFirst = 0; - if ( aN1Vec.fY > 0 ) - { - if ( nDirection != CURVE_RIGHT ) - nFirst++; - } - else - { - if ( nDirection == CURVE_RIGHT ) - nFirst++; - } - fWidth = hypot( mpFloat0[ 1 + nFirst ].fX - aDestPoint.fX, mpFloat0[ 1 + nFirst ].fY - aDestPoint.fY ); - fWidth = sqrt( fWidth * fWidth / 2 ); - if ( fWidth > mfWidthHalf ) - { - // Spitzer Winkel : - mnFloat0Points = 6; - mpFloat0[ (4 + nFirst) ^ 1 ] = aDestPoint; - aDestPoint -= aN2Vec; - mpFloat0[ 4 + nFirst ] = aDestPoint; - mpFloat0[ 1 + nFirst ] += aN1Vec; - } - else - { - // Stumpferwinkel : Schnittpunkt wird berechnet - mnFloat0Points = 5; - ImplFloatPoint aSourcePoint; - double fX = 0; - double fY; - double fBDest = 0; - double fBSource = 0; - aSourcePoint = mpFloat0[ 1 + nFirst ]; - - int nValid = 0; - - if ( fabs( aN2Vec.fX ) < 0.00000001 ) - { - fX = aDestPoint.fX; - nValid = 1; - } - else - fBDest = aDestPoint.fY - ( aN2Vec.fY / aN2Vec.fX * aDestPoint.fX ); - - if ( fabs( aN1Vec.fX ) < 0.000000001 ) - { - fX = aSourcePoint.fX; - nValid = 2; - } - else - fBSource = aSourcePoint.fY - ( aN1Vec.fY / aN1Vec.fX * aSourcePoint.fX ); - - if ( !nValid ) - fX = ( fBSource - fBDest ) / ( aN2Vec.fY / aN2Vec.fX - aN1Vec.fY / aN1Vec.fX ); - if ( nValid < 2 ) - fY = aN1Vec.fY / aN1Vec.fX * fX + fBSource; - else - fY = aN2Vec.fY / aN2Vec.fX * fX + fBDest; - - mpFloat0[ 1 + nFirst ].fX = fX; - mpFloat0[ 1 + nFirst ].fY = fY; - mpFloat0[ 4 ] = aDestPoint; - } - } - else if ( ( aN1Vec.fX - aN2Vec.fX + aN1Vec.fY - aN2Vec.fY ) != 0 ) // besitzt zweiter Richtungsvektor die gleiche Steigung aber andere - bContinues = FALSE; // Richtung, dann wird hinten noch eine halbe Linienbreite angehaengt - } - if ( !bContinues ) - { - mpFloat0[ 1 ] += aN1Vec; - mpFloat0[ 2 ] += aN1Vec; - } - } - else - { - mnFloat0Points = mnFloat1Points; - ImplFloatPoint* pTemp = mpFloat1; - mpFloat1 = mpFloat0; - mpFloat0 = pTemp; - } - if ( maLineInfo.GetStyle() == LINE_DASH ) - { - double fLenghtDone = 0; - double fLenght = ( mfDashDotLenght > 0.0 ) ? mfDashDotLenght : mfDistanceLenght; - - double fDistance; - - fDistance = hypot( mpFloat0[ 0 ].fX - mpFloat0[ 1 ].fX, mpFloat0[ 0 ].fY - mpFloat0[ 1 ].fY ); - if ( mnFloat0Points == 5 ) - { - double fDist = hypot( mpFloat0[ 2 ].fX - mpFloat0[ 3 ].fX, mpFloat0[ 2 ].fY - mpFloat0[ 3 ].fY ); - if ( fDist < fDistance ) - fDistance = fDist; - } - - if ( fDistance > fLenght ) - { - fLenghtDone = fLenght; - - ImplFloatPoint aNVec( mpFloat0[ 0 ].GetNVec( mpFloat0[ 1 ] ) ); - aNVec *= fLenght; - mnFloat1Points = mnFloat0Points; - ImplFloatPoint* pTemp = mpFloat1; - mpFloat1 = mpFloat0; - mpFloat0 = pTemp; - mnFloat0Points = 4; - mpFloat0[ 0 ] = mpFloat0[ 1 ] = mpFloat1[ 0 ]; - mpFloat0[ 1 ] += aNVec; - mpFloat0[ 2 ] = mpFloat0[ 3 ] = mpFloat1[ 3 ]; - mpFloat0[ 2 ] += aNVec; - - mpFloat1[ 0 ] = mpFloat0[ 1 ]; - mpFloat1[ 3 ] = mpFloat0[ 2 ]; - } - else - { - mnFloat1Points = 0; - fLenghtDone = fDistance; - } - - if ( mfDashDotLenght > 0.0 ) - { // Ein Dash oder Dot wurde erzeugt - mfDashDotLenght -= fLenghtDone; - if ( mfDashDotLenght == 0.0 ) - { // Komplett erzeugt - if ( mnDashCount ) - mnDashCount--; - else - mnDotCount--; - - if ( ! ( mnDashCount | mnDotCount ) ) - { - mnDashCount = maLineInfo.GetDashCount(); - mnDotCount = maLineInfo.GetDotCount(); - } - mfDistanceLenght = maLineInfo.GetDistance(); - } - } - else - { // Das erzeugte Polygon muessen wir ignorieren - mfDistanceLenght -= fLenghtDone; - if ( mfDistanceLenght == 0.0 ) - mfDashDotLenght = ( mnDashCount ) ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); - continue; - } - } - maPolygon.SetSize( (UINT16)mnFloat0Points ); - UINT16 i = 0; - maPolygon[ i++ ] = Point( FRound( mpFloat0[ 0 ].fX ), FRound( mpFloat0[ 0 ].fY ) ); - maPolygon[ i++ ] = Point( FRound( mpFloat0[ 1 ].fX ), FRound( mpFloat0[ 1 ].fY ) ); - if ( mnFloat0Points > 4 ) - maPolygon[ i++ ] = Point( FRound( mpFloat0[ 4 ].fX ), FRound( mpFloat0[ 4 ].fY ) ); - if ( mnFloat0Points > 5 ) - maPolygon[ i++ ] = Point( FRound( mpFloat0[ 5 ].fX ), FRound( mpFloat0[ 5 ].fY ) ); - maPolygon[ i++ ] = Point( FRound( mpFloat0[ 2 ].fX ), FRound( mpFloat0[ 2 ].fY ) ); - maPolygon[ i ] = Point( FRound( mpFloat0[ 3 ].fX ), FRound( mpFloat0[ 3 ].fY ) ); - - } - else - { - if ( !mnFloat1Points ) - { - mpFloat0[ 0 ] = mpFloatPoint[ mnLinesAvailable-- ]; - mpFloat0[ 1 ] = mpFloatPoint[ mnLinesAvailable ]; - } - else - { - mpFloat0[ 0 ] = mpFloat1[ 0 ]; - mpFloat0[ 1 ] = mpFloat1[ 1 ]; - } - if ( maLineInfo.GetStyle() == LINE_DASH ) - { - double fLenghtDone = 0; - double fLenght = ( mfDashDotLenght > 0.0 ) ? mfDashDotLenght : mfDistanceLenght; - double fDistance; - fDistance = hypot( mpFloat0[ 0 ].fX - mpFloat0[ 1 ].fX, mpFloat0[ 0 ].fY - mpFloat0[ 1 ].fY ); - if ( fDistance > fLenght ) - { - fLenghtDone = fLenght; - ImplFloatPoint aNVec( mpFloat0[ 0 ].GetNVec( mpFloat0[ 1 ] ) ); - aNVec *= fLenght; - mpFloat1[ 1 ] = mpFloat0[ 1 ]; - mpFloat0[ 1 ] = mpFloat0[ 0 ]; - mpFloat0[ 1 ] += aNVec; - mpFloat1[ 0 ] = mpFloat0[ 1 ]; - mnFloat1Points = 2; - } - else - { - mnFloat1Points = 0; - fLenghtDone = fDistance; - } - if ( mfDashDotLenght > 0.0 ) - { // Ein Dash oder Dot wurde erzeugt - mfDashDotLenght -= fLenghtDone; - if ( mfDashDotLenght == 0.0 ) - { // Komplett erzeugt - if ( mnDashCount ) - mnDashCount--; - else - mnDotCount--; - - if ( ! ( mnDashCount | mnDotCount ) ) - { - mnDashCount = maLineInfo.GetDashCount(); - mnDotCount = maLineInfo.GetDotCount(); - } - mfDistanceLenght = maLineInfo.GetDistance(); - } - } - else - { // Das erzeugte Polygon muessen wir ignorieren - mfDistanceLenght -= fLenghtDone; - if ( mfDistanceLenght == 0.0 ) - mfDashDotLenght = ( mnDashCount ) ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); - continue; - } - } - maPolygon.SetSize( 2 ); - maPolygon[ 0 ] = Point( (long)mpFloat0[ 0 ].fX, (long)mpFloat0[ 0 ].fY ); - maPolygon[ 1 ] = Point( (long)mpFloat0[ 1 ].fX, (long)mpFloat0[ 1 ].fY ); - } - return &maPolygon; - } - return NULL; -}; 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/lineinfo.cxx b/vcl/source/gdi/lineinfo.cxx index 98f16713a145..7aa50811106b 100644 --- a/vcl/source/gdi/lineinfo.cxx +++ b/vcl/source/gdi/lineinfo.cxx @@ -34,6 +34,10 @@ #include <tools/vcompat.hxx> #include <tools/debug.hxx> #include <vcl/lineinfo.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dlinegeometry.hxx> +#include <numeric> DBG_NAME( LineInfo ) @@ -49,7 +53,8 @@ ImplLineInfo::ImplLineInfo() : mnDashLen ( 0 ), mnDotCount ( 0 ), mnDotLen ( 0 ), - mnDistance ( 0 ) + mnDistance ( 0 ), + meLineJoin ( basegfx::B2DLINEJOIN_ROUND ) { } @@ -63,7 +68,8 @@ ImplLineInfo::ImplLineInfo( const ImplLineInfo& rImplLineInfo ) : mnDashLen ( rImplLineInfo.mnDashLen ), mnDotCount ( rImplLineInfo.mnDotCount ), mnDotLen ( rImplLineInfo.mnDotLen ), - mnDistance ( rImplLineInfo.mnDistance ) + mnDistance ( rImplLineInfo.mnDistance ), + meLineJoin ( rImplLineInfo.meLineJoin ) { } @@ -209,6 +215,19 @@ void LineInfo::SetDistance( long nDistance ) // ----------------------------------------------------------------------- +void LineInfo::SetLineJoin(basegfx::B2DLineJoin eLineJoin) +{ + DBG_CHKTHIS( LineInfo, NULL ); + + if(eLineJoin != mpImplLineInfo->meLineJoin) + { + ImplMakeUnique(); + mpImplLineInfo->meLineJoin = eLineJoin; + } +} + +// ----------------------------------------------------------------------- + SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo ) { VersionCompat aCompat( rIStm, STREAM_READ ); @@ -225,6 +244,12 @@ SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo ) rIStm >> rImplLineInfo.mnDistance; } + if( aCompat.GetVersion() >= 3 ) + { + // version 3 + rIStm >> nTmp16; rImplLineInfo.meLineJoin = (basegfx::B2DLineJoin) nTmp16; + } + return rIStm; } @@ -232,7 +257,7 @@ SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo ) SvStream& operator<<( SvStream& rOStm, const ImplLineInfo& rImplLineInfo ) { - VersionCompat aCompat( rOStm, STREAM_WRITE, 2 ); + VersionCompat aCompat( rOStm, STREAM_WRITE, 3 ); // version 1 rOStm << (UINT16) rImplLineInfo.meStyle << rImplLineInfo.mnWidth; @@ -242,6 +267,9 @@ SvStream& operator<<( SvStream& rOStm, const ImplLineInfo& rImplLineInfo ) rOStm << rImplLineInfo.mnDotCount << rImplLineInfo.mnDotLen; rOStm << rImplLineInfo.mnDistance; + // since version3 + rOStm << (UINT16) rImplLineInfo.meLineJoin; + return rOStm; } @@ -259,3 +287,78 @@ SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo ) { return( rOStm << *rLineInfo.mpImplLineInfo ); } + +// ----------------------------------------------------------------------- + +bool LineInfo::isDashDotOrFatLineUsed() const +{ + return (LINE_DASH == GetStyle() || GetWidth() > 1); +} + +// ----------------------------------------------------------------------- + +void LineInfo::applyToB2DPolyPolygon( + basegfx::B2DPolyPolygon& io_rLinePolyPolygon, + basegfx::B2DPolyPolygon& o_rFillPolyPolygon) const +{ + o_rFillPolyPolygon.clear(); + + if(io_rLinePolyPolygon.count()) + { + if(LINE_DASH == GetStyle()) + { + ::std::vector< double > fDotDashArray; + const double fDashLen(GetDashLen()); + const double fDotLen(GetDotLen()); + const double fDistance(GetDistance()); + + for(sal_uInt16 a(0); a < GetDashCount(); a++) + { + fDotDashArray.push_back(fDashLen); + fDotDashArray.push_back(fDistance); + } + + for(sal_uInt16 b(0); b < GetDotCount(); b++) + { + fDotDashArray.push_back(fDotLen); + fDotDashArray.push_back(fDistance); + } + + const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0)); + + if(fAccumulated > 0.0) + { + basegfx::B2DPolyPolygon aResult; + + for(sal_uInt32 c(0); c < io_rLinePolyPolygon.count(); c++) + { + basegfx::B2DPolyPolygon aLineTraget; + basegfx::tools::applyLineDashing( + io_rLinePolyPolygon.getB2DPolygon(c), + fDotDashArray, + &aLineTraget); + aResult.append(aLineTraget); + } + + io_rLinePolyPolygon = aResult; + } + } + + if(GetWidth() > 1 && io_rLinePolyPolygon.count()) + { + const double fHalfLineWidth((GetWidth() * 0.5) + 0.5); + + for(sal_uInt32 a(0); a < io_rLinePolyPolygon.count(); a++) + { + o_rFillPolyPolygon.append(basegfx::tools::createAreaGeometry( + io_rLinePolyPolygon.getB2DPolygon(a), + fHalfLineWidth, + GetLineJoin())); + } + + io_rLinePolyPolygon.clear(); + } + } +} + +// ----------------------------------------------------------------------- diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk index 421505a3d500..ed2a9b2ba1e1 100755..100644 --- a/vcl/source/gdi/makefile.mk +++ b/vcl/source/gdi/makefile.mk @@ -57,7 +57,9 @@ EXCEPTIONSFILES= $(SLO)$/salmisc.obj \ $(SLO)$/gfxlink.obj \ $(SLO)$/print.obj \ $(SLO)$/print2.obj \ - $(SLO)$/configsettings.obj \ + $(SLO)$/print3.obj \ + $(SLO)$/oldprintadaptor.obj \ + $(SLO)$/configsettings.obj \ $(SLO)$/sallayout.obj \ $(SLO)$/image.obj \ $(SLO)$/impimage.obj \ @@ -72,10 +74,10 @@ 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 + $(SLO)$/textlayout.obj \ + $(SLO)$/lineinfo.obj SLOFILES= $(EXCEPTIONSFILES) \ $(SLO)$/animate.obj \ @@ -100,8 +102,6 @@ SLOFILES= $(EXCEPTIONSFILES) \ $(SLO)$/impbmp.obj \ $(SLO)$/imagerepository.obj \ $(SLO)$/impvect.obj \ - $(SLO)$/implncvt.obj \ - $(SLO)$/lineinfo.obj \ $(SLO)$/mapmod.obj \ $(SLO)$/metaact.obj \ $(SLO)$/octree.obj \ @@ -119,6 +119,7 @@ SLOFILES= $(EXCEPTIONSFILES) \ $(SLO)$/extoutdevdata.obj \ $(SLO)$/salnativewidgets-none.obj + # --- Targets ------------------------------------------------------ .INCLUDE : target.mk diff --git a/vcl/source/gdi/metaact.cxx b/vcl/source/gdi/metaact.cxx index 82566b2b4362..1f27ad2afe7d 100644 --- a/vcl/source/gdi/metaact.cxx +++ b/vcl/source/gdi/metaact.cxx @@ -52,14 +52,6 @@ inline void ImplScalePoint( Point& rPt, double fScaleX, double fScaleY ) // ------------------------------------------------------------------------ -inline void ImplScaleSize( Size& rSz, double fScaleX, double fScaleY ) -{ - rSz.Width() = FRound( fScaleX * rSz.Width() ); - rSz.Height() = FRound( fScaleY * rSz.Height() ); -} - -// ------------------------------------------------------------------------ - inline void ImplScaleRect( Rectangle& rRect, double fScaleX, double fScaleY ) { Point aTL( rRect.TopLeft() ); @@ -69,6 +61,7 @@ inline void ImplScaleRect( Rectangle& rRect, double fScaleX, double fScaleY ) ImplScalePoint( aBR, fScaleX, fScaleY ); rRect = Rectangle( aTL, aBR ); + rRect.Justify(); } // ------------------------------------------------------------------------ @@ -85,7 +78,7 @@ inline void ImplScaleLineInfo( LineInfo& rLineInfo, double fScaleX, double fScal { if( !rLineInfo.IsDefault() ) { - const double fScale = ( fScaleX + fScaleY ) * 0.5; + const double fScale = ( fabs(fScaleX) + fabs(fScaleY) ) * 0.5; rLineInfo.SetWidth( FRound( fScale * rLineInfo.GetWidth() ) ); rLineInfo.SetDashLen( FRound( fScale * rLineInfo.GetDashLen() ) ); @@ -598,8 +591,8 @@ void MetaRoundRectAction::Move( long nHorzMove, long nVertMove ) void MetaRoundRectAction::Scale( double fScaleX, double fScaleY ) { ImplScaleRect( maRect, fScaleX, fScaleY ); - mnHorzRound = FRound( mnHorzRound * fScaleX ); - mnVertRound = FRound( mnVertRound * fScaleY ); + mnHorzRound = FRound( mnHorzRound * fabs(fScaleX) ); + mnVertRound = FRound( mnVertRound * fabs(fScaleY) ); } // ------------------------------------------------------------------------ @@ -1396,7 +1389,7 @@ void MetaTextArrayAction::Scale( double fScaleX, double fScaleY ) if ( mpDXAry && mnLen ) { for ( USHORT i = 0, nCount = mnLen; i < nCount; i++ ) - mpDXAry[ i ] = FRound( mpDXAry[ i ] * fScaleX ); + mpDXAry[ i ] = FRound( mpDXAry[ i ] * fabs(fScaleX) ); } } @@ -1524,7 +1517,7 @@ void MetaStretchTextAction::Move( long nHorzMove, long nVertMove ) void MetaStretchTextAction::Scale( double fScaleX, double fScaleY ) { ImplScalePoint( maPt, fScaleX, fScaleY ); - mnWidth = (ULONG)FRound( mnWidth * fScaleX ); + mnWidth = (ULONG)FRound( mnWidth * fabs(fScaleX) ); } // ------------------------------------------------------------------------ @@ -1717,7 +1710,7 @@ void MetaTextLineAction::Move( long nHorzMove, long nVertMove ) void MetaTextLineAction::Scale( double fScaleX, double fScaleY ) { ImplScalePoint( maPos, fScaleX, fScaleY ); - mnWidth = FRound( mnWidth * fScaleX ); + mnWidth = FRound( mnWidth * fabs(fScaleX) ); } // ------------------------------------------------------------------------ @@ -1876,8 +1869,10 @@ void MetaBmpScaleAction::Move( long nHorzMove, long nVertMove ) void MetaBmpScaleAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maPt, fScaleX, fScaleY ); - ImplScaleSize( maSz, fScaleX, fScaleY ); + Rectangle aRectangle(maPt, maSz); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maPt = aRectangle.TopLeft(); + maSz = aRectangle.GetSize(); } // ------------------------------------------------------------------------ @@ -1953,8 +1948,10 @@ void MetaBmpScalePartAction::Move( long nHorzMove, long nVertMove ) void MetaBmpScalePartAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maDstPt, fScaleX, fScaleY ); - ImplScaleSize( maDstSz, fScaleX, fScaleY ); + Rectangle aRectangle(maDstPt, maDstSz); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maDstPt = aRectangle.TopLeft(); + maDstSz = aRectangle.GetSize(); } // ------------------------------------------------------------------------ @@ -2099,8 +2096,10 @@ void MetaBmpExScaleAction::Move( long nHorzMove, long nVertMove ) void MetaBmpExScaleAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maPt, fScaleX, fScaleY ); - ImplScaleSize( maSz, fScaleX, fScaleY ); + Rectangle aRectangle(maPt, maSz); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maPt = aRectangle.TopLeft(); + maSz = aRectangle.GetSize(); } // ------------------------------------------------------------------------ @@ -2176,8 +2175,10 @@ void MetaBmpExScalePartAction::Move( long nHorzMove, long nVertMove ) void MetaBmpExScalePartAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maDstPt, fScaleX, fScaleY ); - ImplScaleSize( maDstSz, fScaleX, fScaleY ); + Rectangle aRectangle(maDstPt, maDstSz); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maDstPt = aRectangle.TopLeft(); + maDstSz = aRectangle.GetSize(); } // ------------------------------------------------------------------------ @@ -2328,8 +2329,10 @@ void MetaMaskScaleAction::Move( long nHorzMove, long nVertMove ) void MetaMaskScaleAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maPt, fScaleX, fScaleY ); - ImplScaleSize( maSz, fScaleX, fScaleY ); + Rectangle aRectangle(maPt, maSz); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maPt = aRectangle.TopLeft(); + maSz = aRectangle.GetSize(); } // ------------------------------------------------------------------------ @@ -2408,8 +2411,10 @@ void MetaMaskScalePartAction::Move( long nHorzMove, long nVertMove ) void MetaMaskScalePartAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maDstPt, fScaleX, fScaleY ); - ImplScaleSize( maDstSz, fScaleX, fScaleY ); + Rectangle aRectangle(maDstPt, maDstSz); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maDstPt = aRectangle.TopLeft(); + maDstSz = aRectangle.GetSize(); } // ------------------------------------------------------------------------ @@ -3498,9 +3503,9 @@ MetaAction* MetaFontAction::Clone() void MetaFontAction::Scale( double fScaleX, double fScaleY ) { - Size aSize( maFont.GetSize() ); - - ImplScaleSize( aSize, fScaleX, fScaleY ); + const Size aSize( + FRound(maFont.GetSize().Width() * fabs(fScaleX)), + FRound(maFont.GetSize().Height() * fabs(fScaleY))); maFont.SetSize( aSize ); } @@ -3791,14 +3796,18 @@ MetaAction* MetaFloatTransparentAction::Clone() void MetaFloatTransparentAction::Move( long nHorzMove, long nVertMove ) { maPoint.Move( nHorzMove, nVertMove ); + maMtf.Move(nHorzMove, nVertMove); } // ------------------------------------------------------------------------ void MetaFloatTransparentAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maPoint, fScaleX, fScaleY ); - ImplScaleSize( maSize, fScaleX, fScaleY ); + Rectangle aRectangle(maPoint, maSize); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maPoint = aRectangle.TopLeft(); + maSize = aRectangle.GetSize(); + maMtf.Scale(fScaleX, fScaleY); } // ------------------------------------------------------------------------ @@ -3872,8 +3881,10 @@ void MetaEPSAction::Move( long nHorzMove, long nVertMove ) void MetaEPSAction::Scale( double fScaleX, double fScaleY ) { - ImplScalePoint( maPoint, fScaleX, fScaleY ); - ImplScaleSize( maSize, fScaleX, fScaleY ); + Rectangle aRectangle(maPoint, maSize); + ImplScaleRect( aRectangle, fScaleX, fScaleY ); + maPoint = aRectangle.TopLeft(); + maSize = aRectangle.GetSize(); } // ------------------------------------------------------------------------ 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/outdev.cxx b/vcl/source/gdi/outdev.cxx index 6298ff51a16a..91ea8419cba9 100644 --- a/vcl/source/gdi/outdev.cxx +++ b/vcl/source/gdi/outdev.cxx @@ -56,7 +56,6 @@ #include <vcl/gdimtf.hxx> #include <vcl/outdata.hxx> #include <vcl/print.hxx> -#include <implncvt.hxx> #include <vcl/outdev.h> #include <vcl/outdev.hxx> #include <vcl/unowrap.hxx> @@ -77,6 +76,8 @@ #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <vcl/unohelp.hxx> +#include <numeric> + using namespace ::com::sun::star; DBG_NAME( OutputDevice ) @@ -2330,6 +2331,130 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) // ----------------------------------------------------------------------- +void OutputDevice::impPaintLineGeometryWithEvtlExpand( + const LineInfo& rInfo, + basegfx::B2DPolyPolygon aLinePolyPolygon) +{ + const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) + && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) + && ROP_OVERPAINT == GetRasterOp() + && IsLineColor()); + basegfx::B2DPolyPolygon aFillPolyPolygon; + const bool bDashUsed(LINE_DASH == rInfo.GetStyle()); + const bool bLineWidthUsed(rInfo.GetWidth() > 1); + + if(bDashUsed && aLinePolyPolygon.count()) + { + ::std::vector< double > fDotDashArray; + const double fDashLen(rInfo.GetDashLen()); + const double fDotLen(rInfo.GetDotLen()); + const double fDistance(rInfo.GetDistance()); + + for(sal_uInt16 a(0); a < rInfo.GetDashCount(); a++) + { + fDotDashArray.push_back(fDashLen); + fDotDashArray.push_back(fDistance); + } + + for(sal_uInt16 b(0); b < rInfo.GetDotCount(); b++) + { + fDotDashArray.push_back(fDotLen); + fDotDashArray.push_back(fDistance); + } + + const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0)); + + if(fAccumulated > 0.0) + { + basegfx::B2DPolyPolygon aResult; + + for(sal_uInt32 c(0); c < aLinePolyPolygon.count(); c++) + { + basegfx::B2DPolyPolygon aLineTraget; + basegfx::tools::applyLineDashing( + aLinePolyPolygon.getB2DPolygon(c), + fDotDashArray, + &aLineTraget); + aResult.append(aLineTraget); + } + + aLinePolyPolygon = aResult; + } + } + + if(bLineWidthUsed && aLinePolyPolygon.count()) + { + const double fHalfLineWidth((rInfo.GetWidth() * 0.5) + 0.5); + + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + aFillPolyPolygon.append(basegfx::tools::createAreaGeometry( + aLinePolyPolygon.getB2DPolygon(a), + fHalfLineWidth, + rInfo.GetLineJoin())); + } + + aLinePolyPolygon.clear(); + } + + GDIMetaFile* pOldMetaFile = mpMetaFile; + mpMetaFile = NULL; + + if(aLinePolyPolygon.count()) + { + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + bool bDone(false); + + if(bTryAA) + { + bDone = mpGraphics->DrawPolyLine(aCandidate, basegfx::B2DVector(1.0, 1.0), basegfx::B2DLINEJOIN_NONE, this); + } + + if(!bDone) + { + const Polygon aPolygon(aCandidate); + mpGraphics->DrawPolyLine(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this); + } + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor( maLineColor ); + const Color aOldFillColor( maFillColor ); + + SetLineColor(); + ImplInitLineColor(); + SetFillColor( aOldLineColor ); + ImplInitFillColor(); + + bool bDone(false); + + if(bTryAA) + { + bDone = mpGraphics->DrawPolyPolygon(aFillPolyPolygon, 0.0, this); + } + + if(!bDone) + { + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + mpGraphics->DrawPolygon(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this); + } + } + + SetFillColor( aOldFillColor ); + SetLineColor( aOldLineColor ); + } + + mpMetaFile = pOldMetaFile; +} + +// ----------------------------------------------------------------------- + void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt, const LineInfo& rLineInfo ) { @@ -2357,47 +2482,22 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt, if ( mbOutputClipped ) return; + const Point aStartPt( ImplLogicToDevicePixel( rStartPt ) ); + const Point aEndPt( ImplLogicToDevicePixel( rEndPt ) ); const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); + const bool bDashUsed(LINE_DASH == aInfo.GetStyle()); + const bool bLineWidthUsed(aInfo.GetWidth() > 1); - if( ( aInfo.GetWidth() > 1L ) || ( LINE_DASH == aInfo.GetStyle() ) ) + if(bDashUsed || bLineWidthUsed) { - Polygon aPoly( 2 ); aPoly[ 0 ] = rStartPt; aPoly[ 1 ] = rEndPt; - GDIMetaFile* pOldMetaFile = mpMetaFile; - ImplLineConverter aLineCvt( ImplLogicToDevicePixel( aPoly ), aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); - - mpMetaFile = NULL; + basegfx::B2DPolygon aLinePolygon; + aLinePolygon.append(basegfx::B2DPoint(aStartPt.X(), aStartPt.Y())); + aLinePolygon.append(basegfx::B2DPoint(aEndPt.X(), aEndPt.Y())); - if ( aInfo.GetWidth() > 1 ) - { - const Color aOldLineColor( maLineColor ); - const Color aOldFillColor( maFillColor ); - - SetLineColor(); - ImplInitLineColor(); - SetFillColor( aOldLineColor ); - ImplInitFillColor(); - - for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) - mpGraphics->DrawPolygon( pPoly->GetSize(), (const SalPoint*) pPoly->GetConstPointAry(), this ); - - SetFillColor( aOldFillColor ); - SetLineColor( aOldLineColor ); - } - else - { - if ( mbInitLineColor ) - ImplInitLineColor(); - - for ( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) - mpGraphics->DrawLine( (*pPoly)[ 0 ].X(), (*pPoly)[ 0 ].Y(), (*pPoly)[ 1 ].X(), (*pPoly)[ 1 ].Y(), this ); - } - mpMetaFile = pOldMetaFile; + impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aLinePolygon)); } else { - const Point aStartPt( ImplLogicToDevicePixel( rStartPt ) ); - const Point aEndPt( ImplLogicToDevicePixel( rEndPt ) ); - if ( mbInitLineColor ) ImplInitLineColor(); @@ -2546,7 +2646,7 @@ void OutputDevice::DrawPolyLine( const Polygon& rPoly, const LineInfo& rLineInfo if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) && LINE_SOLID == rLineInfo.GetStyle()) { - DrawPolyLine(rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), basegfx::B2DLINEJOIN_ROUND); + DrawPolyLine(rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), rLineInfo.GetLineJoin()); return; } @@ -2558,7 +2658,7 @@ void OutputDevice::DrawPolyLine( const Polygon& rPoly, const LineInfo& rLineInfo void OutputDevice::ImpDrawPolyLineWithLineInfo(const Polygon& rPoly, const LineInfo& rLineInfo) { - USHORT nPoints = rPoly.GetSize(); + USHORT nPoints(rPoly.GetSize()); if ( !IsDeviceOutputNecessary() || !mbLineColor || ( nPoints < 2 ) || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() ) return; @@ -2566,11 +2666,19 @@ void OutputDevice::ImpDrawPolyLineWithLineInfo(const Polygon& rPoly, const LineI Polygon aPoly = ImplLogicToDevicePixel( rPoly ); // #100127# LineInfo is not curve-safe, subdivide always - if( aPoly.HasFlags() ) - { - aPoly = ImplSubdivideBezier( aPoly ); - nPoints = aPoly.GetSize(); - } + // + // What shall this mean? It's wrong to subdivide here when the + // polygon is a fat line. In that case, the painted geometry + // WILL be much different. + // I also have no idea how this could be related to the given ID + // which reads 'consolidate boost versions' in the task description. + // Removing. + // + //if( aPoly.HasFlags() ) + //{ + // aPoly = ImplSubdivideBezier( aPoly ); + // nPoints = aPoly.GetSize(); + //} // we need a graphics if ( !mpGraphics && !ImplGetGraphics() ) @@ -2582,67 +2690,29 @@ void OutputDevice::ImpDrawPolyLineWithLineInfo(const Polygon& rPoly, const LineI if ( mbOutputClipped ) return; - const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); - const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) - && mpGraphics->supportsOperation(OutDevSupport_B2DDraw) - && ROP_OVERPAINT == GetRasterOp() - && IsLineColor()); - - if( aInfo.GetWidth() > 1L ) - { - const Color aOldLineColor( maLineColor ); - const Color aOldFillColor( maFillColor ); - GDIMetaFile* pOldMetaFile = mpMetaFile; - ImplLineConverter aLineCvt( aPoly, aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); - - mpMetaFile = NULL; - SetLineColor(); + if ( mbInitLineColor ) ImplInitLineColor(); - SetFillColor( aOldLineColor ); - ImplInitFillColor(); - bool bDone(false); - if(bTryAA) - { - // #i101491# try AAed version - // Use old on-the-fly geometry preparation, combine with AA - bool bSuccess(true); - - for(const Polygon* pPoly = aLineCvt.ImplGetFirst(); bSuccess && pPoly; pPoly = aLineCvt.ImplGetNext()) - { - bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(pPoly->getB2DPolygon()), 0.0, this); - } - - if(bSuccess) - { - bDone = true; - } - } - - if(!bDone) - { - for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) - { - mpGraphics->DrawPolygon( pPoly->GetSize(), (const SalPoint*) pPoly->GetConstPointAry(), this ); - } - } + const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); + const bool bDashUsed(LINE_DASH == aInfo.GetStyle()); + const bool bLineWidthUsed(aInfo.GetWidth() > 1); - SetLineColor( aOldLineColor ); - SetFillColor( aOldFillColor ); - mpMetaFile = pOldMetaFile; + if(bDashUsed || bLineWidthUsed) + { + impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aPoly.getB2DPolygon())); } else { - if ( mbInitLineColor ) - ImplInitLineColor(); - if ( LINE_DASH == aInfo.GetStyle() ) + // #100127# the subdivision HAS to be done here since only a pointer + // to an array of points is given to the DrawPolyLine method, there is + // NO way to find out there that it's a curve. + if( aPoly.HasFlags() ) { - ImplLineConverter aLineCvt( aPoly, aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); - for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) - mpGraphics->DrawPolyLine( pPoly->GetSize(), (const SalPoint*)pPoly->GetConstPointAry(), this ); + aPoly = ImplSubdivideBezier( aPoly ); + nPoints = aPoly.GetSize(); } - else - mpGraphics->DrawPolyLine( nPoints, (const SalPoint*) aPoly.GetConstPointAry(), this ); + + mpGraphics->DrawPolyLine(nPoints, (const SalPoint*)aPoly.GetConstPointAry(), this); } if( mpAlphaVDev ) @@ -3047,7 +3117,12 @@ void OutputDevice::DrawPolyLine( SetFillColor(aOldLineColor); ImplInitFillColor(); - ImpDrawPolyPolygonWithB2DPolyPolygon(aAreaPolyPolygon); + // draw usig a loop; else the topology will paint a PolyPolygon + for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++) + { + ImpDrawPolyPolygonWithB2DPolyPolygon( + basegfx::B2DPolyPolygon(aAreaPolyPolygon.getB2DPolygon(a))); + } SetLineColor(aOldLineColor); ImplInitLineColor(); @@ -3064,14 +3139,15 @@ void OutputDevice::DrawPolyLine( } } } - - // fallback to old polygon drawing if needed. This will really - // use ImplLineConverter, but still try to AA lines - const Polygon aToolsPolygon( rB2DPolygon ); - LineInfo aLineInfo; - if( fLineWidth != 0.0 ) - aLineInfo.SetWidth( static_cast<long>(fLineWidth+0.5) ); - ImpDrawPolyLineWithLineInfo( aToolsPolygon, aLineInfo ); + else + { + // fallback to old polygon drawing if needed + const Polygon aToolsPolygon( rB2DPolygon ); + LineInfo aLineInfo; + if( fLineWidth != 0.0 ) + aLineInfo.SetWidth( static_cast<long>(fLineWidth+0.5) ); + ImpDrawPolyLineWithLineInfo( aToolsPolygon, aLineInfo ); + } } // ----------------------------------------------------------------------- diff --git a/vcl/source/gdi/outdev6.cxx b/vcl/source/gdi/outdev6.cxx index 79986988afd7..2d436ea43659 100644 --- a/vcl/source/gdi/outdev6.cxx +++ b/vcl/source/gdi/outdev6.cxx @@ -1158,9 +1158,11 @@ void OutputDevice::ImplDraw2ColorFrame( const Rectangle& rRect, // ----------------------------------------------------------------------- -void OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, +bool OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, const GfxLink& rGfxLink, GDIMetaFile* pSubst ) { + bool bDrawn(true); + if ( mpMetaFile ) { GDIMetaFile aSubst; @@ -1172,20 +1174,20 @@ void OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, } if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) - return; + return bDrawn; if( mbOutputClipped ) - return; + return bDrawn; Rectangle aRect( ImplLogicToDevicePixel( Rectangle( rPoint, rSize ) ) ); + if( !aRect.IsEmpty() ) { // draw the real EPS graphics - bool bDrawn = FALSE; if( rGfxLink.GetData() && rGfxLink.GetDataSize() ) { if( !mpGraphics && !ImplGetGraphics() ) - return; + return bDrawn; if( mbInitClipRegion ) ImplInitClipRegion(); @@ -1208,4 +1210,6 @@ void OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, if( mpAlphaVDev ) mpAlphaVDev->DrawEPS( rPoint, rSize, rGfxLink, pSubst ); + + return bDrawn; } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 723f856cac4a..40aa4898ba65 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -63,11 +63,9 @@ #include <comphelper/processfactory.hxx> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/util/URL.hpp> - -#include "implncvt.hxx" - #include "cppuhelper/implbase1.hxx" #include <icc/sRGB-IEC61966-2.1.hxx> +#include <vcl/lineinfo.hxx> using namespace vcl; using namespace rtl; 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/region.cxx b/vcl/source/gdi/region.cxx index 642690a8d32d..0eb25bdfa130 100644 --- a/vcl/source/gdi/region.cxx +++ b/vcl/source/gdi/region.cxx @@ -50,6 +50,7 @@ #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/range/b2drange.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> // ======================================================================= // @@ -1304,9 +1305,7 @@ void Region::Move( long nHorzMove, long nVertMove ) mpImplRegion->mpPolyPoly->Move( nHorzMove, nVertMove ); else if( mpImplRegion->mpB2DPolyPoly ) { - ::basegfx::B2DHomMatrix aTransform; - aTransform.translate( nHorzMove, nVertMove ); - mpImplRegion->mpB2DPolyPoly->transform( aTransform ); + mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove)); } else { @@ -1347,9 +1346,7 @@ void Region::Scale( double fScaleX, double fScaleY ) mpImplRegion->mpPolyPoly->Scale( fScaleX, fScaleY ); else if( mpImplRegion->mpB2DPolyPoly ) { - ::basegfx::B2DHomMatrix aTransform; - aTransform.scale( fScaleX, fScaleY ); - mpImplRegion->mpB2DPolyPoly->transform( aTransform ); + mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY)); } else { diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index e71c47d61c54..9934e2f39873 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -52,7 +52,6 @@ #include <vcl/gdimtf.hxx> #include <vcl/outdata.hxx> #include <vcl/print.hxx> -#include <implncvt.hxx> #include <vcl/outdev.h> #include <vcl/outdev.hxx> #include <vcl/unowrap.hxx> diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index d937d15ce7df..cb823fc912cd 100755 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -41,6 +41,7 @@ #include <vcl/sallayout.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <i18npool/lang.h> #ifndef _TL_DEBUG_HXX @@ -890,10 +891,8 @@ bool SalLayout::GetOutline( SalGraphics& rSalGraphics, { if( aPos.X() || aPos.Y() ) { - ::basegfx::B2DHomMatrix aMatrix; - aMatrix.translate( aPos.X(), aPos.Y() ); - aGlyphOutline.transform( aMatrix ); - } + aGlyphOutline.transform(basegfx::tools::createTranslateB2DHomMatrix(aPos.X(), aPos.Y())); + } // insert outline at correct position rVector.push_back( aGlyphOutline ); 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/glyphs/gcach_ftyp.cxx b/vcl/source/glyphs/gcach_ftyp.cxx index 18857b94af8f..b92bea929c51 100644 --- a/vcl/source/glyphs/gcach_ftyp.cxx +++ b/vcl/source/glyphs/gcach_ftyp.cxx @@ -43,6 +43,7 @@ #include "tools/poly.hxx" #include "basegfx/matrix/b2dhommatrix.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include "basegfx/polygon/b2dpolypolygon.hxx" #include "osl/file.hxx" @@ -2282,9 +2283,7 @@ bool FreetypeServerFont::GetGlyphOutline( int nGlyphIndex, // convert to basegfx polypolygon // TODO: get rid of the intermediate tools polypolygon rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon(); - ::basegfx::B2DHomMatrix aMatrix; - aMatrix.scale( +1.0/(1<<6), -1.0/(1<<6) ); - rB2DPolyPoly.transform( aMatrix ); + rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) )); return true; } diff --git a/vcl/source/glyphs/glyphcache.cxx b/vcl/source/glyphs/glyphcache.cxx index e3e840e40730..17e70c539254 100644 --- a/vcl/source/glyphs/glyphcache.cxx +++ b/vcl/source/glyphs/glyphcache.cxx @@ -79,9 +79,7 @@ GlyphCache::~GlyphCache() // ----------------------------------------------------------------------- -#ifndef IRIX inline -#endif size_t GlyphCache::IFSD_Hash::operator()( const ImplFontSelectData& rFontSelData ) const { // TODO: is it worth to improve this hash function? diff --git a/vcl/source/helper/xconnection.cxx b/vcl/source/helper/xconnection.cxx index 477ff5fb9902..489e3cf9340e 100644 --- a/vcl/source/helper/xconnection.cxx +++ b/vcl/source/helper/xconnection.cxx @@ -30,10 +30,31 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#include <svsys.h> -#include <vcl/xconnection.hxx> -#include <vcl/svdata.hxx> -#include <vcl/salinst.hxx> + +#include "svsys.h" +#include "vcl/xconnection.hxx" +#include "vcl/svdata.hxx" +#include "vcl/salinst.hxx" +#include "vcl/svapp.hxx" + +namespace vcl +{ + class SolarMutexReleaser + { + ULONG mnReleased; + public: + SolarMutexReleaser() + { + mnReleased = Application::ReleaseSolarMutex(); + } + + ~SolarMutexReleaser() + { + if( mnReleased ) + Application::AcquireSolarMutex( mnReleased ); + } + }; +} using namespace rtl; using namespace osl; @@ -41,6 +62,7 @@ using namespace vcl; using namespace com::sun::star::uno; using namespace com::sun::star::awt; + DisplayConnection::DisplayConnection() { ImplSVData* pSVData = ImplGetSVData(); @@ -108,6 +130,8 @@ Any SAL_CALL DisplayConnection::getIdentifier() throw() void DisplayConnection::dispatchDowningEvent() { + SolarMutexReleaser aRel; + MutexGuard aGuard( m_aMutex ); Any aEvent; std::list< Reference< XEventHandler > > aLocalList( m_aHandlers ); @@ -117,6 +141,8 @@ void DisplayConnection::dispatchDowningEvent() bool DisplayConnection::dispatchEvent( void* pThis, void* pData, int nBytes ) { + SolarMutexReleaser aRel; + DisplayConnection* This = (DisplayConnection*)pThis; MutexGuard aGuard( This->m_aMutex ); @@ -131,6 +157,8 @@ bool DisplayConnection::dispatchEvent( void* pThis, void* pData, int nBytes ) bool DisplayConnection::dispatchErrorEvent( void* pThis, void* pData, int nBytes ) { + SolarMutexReleaser aRel; + DisplayConnection* This = (DisplayConnection*)pThis; MutexGuard aGuard( This->m_aMutex ); 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/toolbox.cxx b/vcl/source/window/toolbox.cxx index 8aa4926f5e1a..ef58ea9e6bc6 100644 --- a/vcl/source/window/toolbox.cxx +++ b/vcl/source/window/toolbox.cxx @@ -229,6 +229,22 @@ int ToolBox::ImplGetDragWidth( ToolBox* pThis ) } return width; } + +ButtonType determineButtonType( ImplToolItem* pItem, ButtonType defaultType ) +{ + ButtonType tmpButtonType = defaultType; + ToolBoxItemBits nBits( pItem->mnBits & 0x300 ); + if ( nBits & TIB_TEXTICON ) // item has custom setting + { + tmpButtonType = BUTTON_SYMBOLTEXT; + if ( nBits == TIB_TEXT_ONLY ) + tmpButtonType = BUTTON_TEXT; + else if ( nBits == TIB_ICON_ONLY ) + tmpButtonType = BUTTON_SYMBOL; + } + return tmpButtonType; +} + // ----------------------------------------------------------------------- void ToolBox::ImplUpdateDragArea( ToolBox *pThis ) @@ -1992,12 +2008,13 @@ BOOL ToolBox::ImplCalcItem() bText = FALSE; else bText = TRUE; - + ButtonType tmpButtonType = determineButtonType( &(*it), meButtonType ); // default to toolbox setting if ( bImage || bText ) { + it->mbEmptyBtn = FALSE; - if ( meButtonType == BUTTON_SYMBOL ) + if ( tmpButtonType == BUTTON_SYMBOL ) { // we're drawing images only if ( bImage || !bText ) @@ -2011,7 +2028,7 @@ BOOL ToolBox::ImplCalcItem() it->mbVisibleText = TRUE; } } - else if ( meButtonType == BUTTON_TEXT ) + else if ( tmpButtonType == BUTTON_TEXT ) { // we're drawing text only if ( bText || !bImage ) @@ -3625,7 +3642,8 @@ void ToolBox::ImplDrawItem( USHORT nPos, BOOL bHighlight, BOOL bPaint, BOOL bLay // determine what has to be drawn on the button: image, text or both BOOL bImage; BOOL bText; - pItem->DetermineButtonDrawStyle( meButtonType, bImage, bText ); + ButtonType tmpButtonType = determineButtonType( pItem, meButtonType ); // default to toolbox setting + pItem->DetermineButtonDrawStyle( tmpButtonType, bImage, bText ); // compute output values long nBtnWidth = aBtnSize.Width()-SMALLBUTTON_HSIZE; 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 278ac0e61d92..d0b9ae5c7561 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -1105,6 +1105,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; + } if( (nType == CTRL_SLIDER) && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) ) { NWEnsureGTKSlider( m_nScreen ); 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/inc/salunx.h b/vcl/unx/inc/salunx.h index cdf45fd30867..c1fee6c68d94 100644 --- a/vcl/unx/inc/salunx.h +++ b/vcl/unx/inc/salunx.h @@ -38,12 +38,6 @@ #include <time.h> #include <sys/time.h> #include <strings.h> -#elif defined IRIX -#ifdef __cplusplus -#include <ctime> -#endif -#include <sys/time.h> -#include <unistd.h> #endif #include <svunx.h> #include <salstd.hxx> diff --git a/vcl/unx/source/app/i18n_ic.cxx b/vcl/unx/source/app/i18n_ic.cxx index cacffbcfdbb1..bb8f86d93e01 100644 --- a/vcl/unx/source/app/i18n_ic.cxx +++ b/vcl/unx/source/app/i18n_ic.cxx @@ -340,7 +340,7 @@ SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) : if ( mnPreeditStyle != XIMPreeditNone ) { -#if defined LINUX || defined FREEBSD || defined NETBSD || defined IRIX +#if defined LINUX || defined FREEBSD || defined NETBSD if ( mpPreeditAttributes != NULL ) #endif mpAttributes = XVaAddToNestedList( mpAttributes, @@ -348,7 +348,7 @@ SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) : } if ( mnStatusStyle != XIMStatusNone ) { -#if defined LINUX || defined FREEBSD || defined NETBSD || defined IRIX +#if defined LINUX || defined FREEBSD || defined NETBSD if ( mpStatusAttributes != NULL ) #endif mpAttributes = XVaAddToNestedList( mpAttributes, diff --git a/vcl/unx/source/app/i18n_im.cxx b/vcl/unx/source/app/i18n_im.cxx index ae472d6323f4..0a48c054167f 100644 --- a/vcl/unx/source/app/i18n_im.cxx +++ b/vcl/unx/source/app/i18n_im.cxx @@ -59,7 +59,7 @@ using namespace vcl; #include "i18n_cb.hxx" -#if defined(SOLARIS) || defined(LINUX) || defined(IRIX) +#if defined(SOLARIS) || defined(LINUX) extern "C" char * XSetIMValues(XIM im, ...); #endif diff --git a/vcl/unx/source/app/randrwrapper.cxx b/vcl/unx/source/app/randrwrapper.cxx index 8d01b64d4680..4fbe5db97ab9 100644 --- a/vcl/unx/source/app/randrwrapper.cxx +++ b/vcl/unx/source/app/randrwrapper.cxx @@ -161,7 +161,13 @@ RandRWrapper::RandRWrapper( Display* pDisplay ) : if( ! m_bValid ) { rtl::OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrandr.so.2" ) ); - m_pRandRLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT ); + // load and resolve dependencies immediately + // rationale: there are older distributions where libXrandr.so.2 is not linked + // with libXext.so, resulting in a missing symbol and terminating the office + // obviously they expected libXext to be linked in global symbolspace (that is + // linked by the application), which is not the case with us (because we want + // to be able to run in headless mode even without an installed X11 library) + m_pRandRLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT | SAL_LOADMODULE_NOW ); initFromModule(); } if( m_bValid ) diff --git a/vcl/unx/source/app/saldisp.cxx b/vcl/unx/source/app/saldisp.cxx index 07955d426b8c..558ae3714358 100644 --- a/vcl/unx/source/app/saldisp.cxx +++ b/vcl/unx/source/app/saldisp.cxx @@ -38,16 +38,13 @@ #include <stdio.h> #include <stdlib.h> #include <math.h> -#if defined(IRIX) -#include <ctime> -#endif #include <sys/time.h> #include <pthread.h> #include <unistd.h> #include <ctype.h> #include <string.h> -#if defined(SOLARIS) || defined(IRIX) +#if defined(SOLARIS) #include <sal/alloca.h> #include <osl/module.h> #endif @@ -898,7 +895,7 @@ void SalDisplay::Init() sscanf( pProperties, "%li", &nProperties_ ); else { -#if defined DBG_UTIL || defined SUN || defined LINUX || defined FREEBSD || defined IRIX +#if defined DBG_UTIL || defined SUN || defined LINUX || defined FREEBSD nProperties_ |= PROPERTY_FEATURE_Maximize; #endif // Server Bugs & Properties @@ -2307,11 +2304,7 @@ long SalX11Display::Dispatch( XEvent *pEvent ) return 0; SalInstance* pInstance = GetSalData()->m_pInstance; - if( pInstance->GetEventCallback() ) - { - YieldMutexReleaser aReleaser; - pInstance->CallEventCallback( pEvent, sizeof( XEvent ) ); - } + pInstance->CallEventCallback( pEvent, sizeof( XEvent ) ); switch( pEvent->type ) { diff --git a/vcl/unx/source/app/saltimer.cxx b/vcl/unx/source/app/saltimer.cxx index bf8aa202b066..afcecc0d0667 100644 --- a/vcl/unx/source/app/saltimer.cxx +++ b/vcl/unx/source/app/saltimer.cxx @@ -32,9 +32,6 @@ #include "precompiled_vcl.hxx" #include <stdio.h> -#if defined(IRIX) -#include <ctime> -#endif #include <sys/time.h> #include <sys/times.h> #include <time.h> diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx index cb554bccea21..5fe2295a8fed 100644 --- a/vcl/unx/source/gdi/salgdi.cxx +++ b/vcl/unx/source/gdi/salgdi.cxx @@ -50,6 +50,7 @@ #include "basegfx/polygon/b2dpolygonclipper.hxx" #include "basegfx/polygon/b2dlinegeometry.hxx" #include "basegfx/matrix/b2dhommatrix.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include "basegfx/polygon/b2dpolypolygoncutter.hxx" #include <vector> @@ -1567,6 +1568,9 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : // the used basegfx::tools::createAreaGeometry is simply too // expensive with very big polygons; fallback to caller (who // should use ImplLineConverter normally) + // AW: ImplLineConverter had to be removed since it does not even + // know LineJoins, so the fallback will now prepare the line geometry + // the same way. return false; } const XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); @@ -1579,9 +1583,7 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : && !basegfx::fTools::equalZero( rLineWidth.getY() ) ) { // prepare for createAreaGeometry() with anisotropic linewidth - basegfx::B2DHomMatrix aAnisoMatrix; - aAnisoMatrix.scale( 1.0, rLineWidth.getX() / rLineWidth.getY() ); - aPolygon.transform( aAnisoMatrix ); + aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY())); } // special handling for hairlines to improve the drawing performance @@ -1603,9 +1605,7 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : && !basegfx::fTools::equalZero( rLineWidth.getX() ) ) { // postprocess createAreaGeometry() for anisotropic linewidth - basegfx::B2DHomMatrix aAnisoMatrix; - aAnisoMatrix.scale( 1.0, rLineWidth.getY() / rLineWidth.getX() ); - aPolygon.transform( aAnisoMatrix ); + aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX())); } // temporarily adjust brush color to pen color 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/plugadapt/salplug.cxx b/vcl/unx/source/plugadapt/salplug.cxx index f1c63b8abee7..08820b2cb7f9 100644 --- a/vcl/unx/source/plugadapt/salplug.cxx +++ b/vcl/unx/source/plugadapt/salplug.cxx @@ -219,8 +219,10 @@ SalInstance *CreateSalInstance() if( !(pUsePlugin && *pUsePlugin) ) pInst = check_headless_plugin(); + else + pInst = tryInstance( OUString::createFromAscii( pUsePlugin ) ); - if( ! pInst && !(pUsePlugin && *pUsePlugin) ) + if( ! pInst ) pInst = autodetect_plugin(); // fallback to gen 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/printer/printerinfomanager.cxx b/vcl/unx/source/printer/printerinfomanager.cxx index b3e5b4667a6a..53cd662db8e0 100644 --- a/vcl/unx/source/printer/printerinfomanager.cxx +++ b/vcl/unx/source/printer/printerinfomanager.cxx @@ -441,7 +441,7 @@ void PrinterInfoManager::initialize() * porters: please append your platform to the Solaris * case if your platform has SystemV printing per default. */ - #if defined SOLARIS || defined(IRIX) + #if defined SOLARIS aValue = "lp"; #else aValue = "lpr"; 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/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx index d82830a9022f..12fdad65dfb1 100644 --- a/vcl/win/source/gdi/salgdi3.cxx +++ b/vcl/win/source/gdi/salgdi3.cxx @@ -65,6 +65,7 @@ #include "basegfx/polygon/b2dpolygon.hxx" #include "basegfx/polygon/b2dpolypolygon.hxx" #include "basegfx/matrix/b2dhommatrix.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include "sft.hxx" @@ -2480,9 +2481,8 @@ BOOL WinSalGraphics::GetGlyphOutline( long nIndex, // rescaling needed for the PolyPolygon conversion if( rB2DPolyPoly.count() ) { - ::basegfx::B2DHomMatrix aMatrix; - aMatrix.scale( mfFontScale/256, mfFontScale/256 ); - rB2DPolyPoly.transform( aMatrix ); + const double fFactor(mfFontScale/256); + rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor)); } return bRet; diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx index 5c00c786e22d..29e4ff1d801e 100644 --- a/vcl/win/source/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx @@ -62,9 +62,9 @@ // ----------------------------------------------------------------------- -void impAddB2DPolygonToGDIPlusGraphicsPath(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon) +void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) { - const sal_uInt32 nCount(rPolygon.count()); + sal_uInt32 nCount(rPolygon.count()); if(nCount) { @@ -97,8 +97,58 @@ void impAddB2DPolygonToGDIPlusGraphicsPath(Gdiplus::GraphicsPath& rPath, const b if(a + 1 < nEdgeCount) { - aCurr = aNext; aFCurr = aFNext; + + if(bNoLineJoin) + { + rPath.StartFigure(); + } + } + } + } +} + +void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) +{ + sal_uInt32 nCount(rPolygon.count()); + + if(nCount) + { + const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); + const bool bControls(rPolygon.areControlPointsUsed()); + basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); + Gdiplus::Point aICurr(INT(aCurr.getX()), INT(aCurr.getY())); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nCount); + const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); + const Gdiplus::Point aINext(INT(aNext.getX()), INT(aNext.getY())); + + if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) + { + const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); + + rPath.AddBezier( + aICurr, + Gdiplus::Point(INT(aCa.getX()), INT(aCa.getY())), + Gdiplus::Point(INT(aCb.getX()), INT(aCb.getY())), + aINext); + } + else + { + rPath.AddLine(aICurr, aINext); + } + + if(a + 1 < nEdgeCount) + { + aICurr = aINext; + + if(bNoLineJoin) + { + rPath.StartFigure(); + } } } } @@ -123,7 +173,7 @@ bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly aPath.StartFigure(); // #i101491# not needed for first run } - impAddB2DPolygonToGDIPlusGraphicsPath(aPath, rPolyPolygon.getB2DPolygon(a)); + impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolyPolygon.getB2DPolygon(a), false); aPath.CloseFigure(); } @@ -152,11 +202,16 @@ bool WinSalGraphics::drawPolyLine(const basegfx::B2DPolygon& rPolygon, const bas Gdiplus::Color aTestColor(255, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor)); Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX())); Gdiplus::GraphicsPath aPath; + bool bNoLineJoin(false); switch(eLineJoin) { default : // basegfx::B2DLINEJOIN_NONE : { + if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) + { + bNoLineJoin = true; + } break; } case basegfx::B2DLINEJOIN_BEVEL : @@ -179,9 +234,16 @@ bool WinSalGraphics::drawPolyLine(const basegfx::B2DPolygon& rPolygon, const bas } } - impAddB2DPolygonToGDIPlusGraphicsPath(aPath, rPolygon); + if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5)) + { + impAddB2DPolygonToGDIPlusGraphicsPathInteger(aPath, rPolygon, bNoLineJoin); + } + else + { + impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolygon, bNoLineJoin); + } - if(rPolygon.isClosed()) + if(rPolygon.isClosed() && !bNoLineJoin) { // #i101491# needed to create the correct line joins aPath.CloseFigure(); diff --git a/vcl/win/source/gdi/salnativewidgets-luna.cxx b/vcl/win/source/gdi/salnativewidgets-luna.cxx index 07bfe3c20695..819ae7b70253 100644 --- a/vcl/win/source/gdi/salnativewidgets-luna.cxx +++ b/vcl/win/source/gdi/salnativewidgets-luna.cxx @@ -341,7 +341,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; @@ -349,7 +349,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 @@ -1149,6 +1149,61 @@ 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; + } + } + } + } if( nType == CTRL_SLIDER && ( (nPart == PART_THUMB_HORZ) || (nPart == PART_THUMB_VERT) ) ) { HTHEME hTheme = getThemeHandle( mhWnd, L"Trackbar"); @@ -1173,8 +1228,10 @@ BOOL WinSalGraphics::getNativeControlRegion( ControlType nType, rNativeContentRegion = aRect; 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; |