diff options
Diffstat (limited to 'extensions/source/scanner')
-rw-r--r-- | extensions/source/scanner/exports.dxp | 3 | ||||
-rw-r--r-- | extensions/source/scanner/grid.cxx | 608 | ||||
-rw-r--r-- | extensions/source/scanner/grid.hrc | 42 | ||||
-rw-r--r-- | extensions/source/scanner/grid.hxx | 149 | ||||
-rw-r--r-- | extensions/source/scanner/grid.src | 112 | ||||
-rw-r--r-- | extensions/source/scanner/makefile.mk | 100 | ||||
-rw-r--r-- | extensions/source/scanner/sane.cxx | 1004 | ||||
-rw-r--r-- | extensions/source/scanner/sane.hxx | 200 | ||||
-rw-r--r-- | extensions/source/scanner/sanedlg.cxx | 1430 | ||||
-rw-r--r-- | extensions/source/scanner/sanedlg.hrc | 82 | ||||
-rw-r--r-- | extensions/source/scanner/sanedlg.hxx | 152 | ||||
-rw-r--r-- | extensions/source/scanner/sanedlg.src | 301 | ||||
-rw-r--r-- | extensions/source/scanner/scanner.cxx | 103 | ||||
-rw-r--r-- | extensions/source/scanner/scanner.hxx | 115 | ||||
-rw-r--r-- | extensions/source/scanner/scanunx.cxx | 352 | ||||
-rw-r--r-- | extensions/source/scanner/scanwin.cxx | 1053 | ||||
-rw-r--r-- | extensions/source/scanner/scnserv.cxx | 104 | ||||
-rw-r--r-- | extensions/source/scanner/twain.cxx | 532 | ||||
-rw-r--r-- | extensions/source/scanner/twain.hxx | 98 |
19 files changed, 6540 insertions, 0 deletions
diff --git a/extensions/source/scanner/exports.dxp b/extensions/source/scanner/exports.dxp new file mode 100644 index 000000000000..9630d7e06768 --- /dev/null +++ b/extensions/source/scanner/exports.dxp @@ -0,0 +1,3 @@ +component_getImplementationEnvironment +component_writeInfo +component_getFactory diff --git a/extensions/source/scanner/grid.cxx b/extensions/source/scanner/grid.cxx new file mode 100644 index 000000000000..ac3e322bc258 --- /dev/null +++ b/extensions/source/scanner/grid.cxx @@ -0,0 +1,608 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include <grid.hrc> +#include <cstdio> +#include <math.h> // for M_LN10 and M_E + +#define _USE_MATH_DEFINES +#include <cmath> +#undef _USE_MATH_DEFINES + +#include <grid.hxx> + +// for ::std::sort +#include <algorithm> + +ResId SaneResId( sal_uInt32 ); + +/*********************************************************************** + * + * GridWindow + * + ***********************************************************************/ + +// --------------------------------------------------------------------- + +GridWindow::GridWindow(double* pXValues, double* pYValues, int nValues, Window* pParent, BOOL bCutValues ) +: ModalDialog( pParent, SaneResId( GRID_DIALOG ) ), + m_aGridArea( 50, 15, 100, 100 ), + m_pXValues( pXValues ), + m_pOrigYValues( pYValues ), + m_nValues( nValues ), + m_pNewYValues( NULL ), + m_bCutValues( bCutValues ), + m_aHandles(), + m_nDragIndex( 0xffffffff ), + m_aMarkerBitmap( Bitmap( SaneResId( GRID_DIALOG_HANDLE_BMP ) ), Color( 255, 255, 255 ) ), + m_aOKButton( this, SaneResId( GRID_DIALOG_OK_BTN ) ), + m_aCancelButton( this, SaneResId( GRID_DIALOG_CANCEL_BTN ) ), + m_aResetTypeBox( this, SaneResId( GRID_DIALOG_TYPE_BOX ) ), + m_aResetButton( this, SaneResId( GRID_DIALOG_RESET_BTN ) ) +{ + USHORT nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_LINEAR_ASCENDING ) ) ); + m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_LINEAR_ASCENDING ); + + nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_LINEAR_DESCENDING ) ) ); + m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_LINEAR_DESCENDING ); + + nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_RESET ) ) ); + m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_RESET ); + + nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_EXPONENTIAL ) ) ); + m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_EXPONENTIAL ); + + m_aResetTypeBox.SelectEntryPos( 0 ); + + m_aResetButton.SetClickHdl( LINK( this, GridWindow, ClickButtonHdl ) ); + + SetMapMode( MapMode( MAP_PIXEL ) ); + Size aSize = GetOutputSizePixel(); + Size aBtnSize = m_aOKButton.GetOutputSizePixel(); + m_aGridArea.setWidth( aSize.Width() - aBtnSize.Width() - 80 ); + m_aGridArea.setHeight( aSize.Height() - 40 ); + + if( m_pOrigYValues && m_nValues ) + { + m_pNewYValues = new double[ m_nValues ]; + memcpy( m_pNewYValues, m_pOrigYValues, sizeof( double ) * m_nValues ); + } + + setBoundings( 0, 0, 1023, 1023 ); + computeExtremes(); + + // create left and right marker as first and last entry + m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1); + m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1); + m_aHandles.push_back(impHandle(transform(findMinX(), findMinY()), m_BmOffX, m_BmOffY)); + m_aHandles.push_back(impHandle(transform(findMaxX(), findMaxY()), m_BmOffX, m_BmOffY)); + + FreeResource(); +} + +// --------------------------------------------------------------------- + +GridWindow::~GridWindow() +{ + if( m_pNewYValues ) + delete [] m_pNewYValues; +} + +// --------------------------------------------------------------------- + +double GridWindow::findMinX() +{ + if( ! m_pXValues ) + return 0.0; + double fMin = m_pXValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pXValues[ i ] < fMin ) + fMin = m_pXValues[ i ]; + return fMin; +} + +// --------------------------------------------------------------------- + +double GridWindow::findMinY() +{ + if( ! m_pNewYValues ) + return 0.0; + double fMin = m_pNewYValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pNewYValues[ i ] < fMin ) + fMin = m_pNewYValues[ i ]; + return fMin; +} + +// --------------------------------------------------------------------- + +double GridWindow::findMaxX() +{ + if( ! m_pXValues ) + return 0.0; + double fMax = m_pXValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pXValues[ i ] > fMax ) + fMax = m_pXValues[ i ]; + return fMax; +} + +// --------------------------------------------------------------------- + +double GridWindow::findMaxY() +{ + if( ! m_pNewYValues ) + return 0.0; + double fMax = m_pNewYValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pNewYValues[ i ] > fMax ) + fMax = m_pNewYValues[ i ]; + return fMax; +} + +// --------------------------------------------------------------------- + +void GridWindow::computeExtremes() +{ + if( m_nValues && m_pXValues && m_pOrigYValues ) + { + m_fMaxX = m_fMinX = m_pXValues[0]; + m_fMaxY = m_fMinY = m_pOrigYValues[0]; + for( int i = 1; i < m_nValues; i++ ) + { + if( m_pXValues[ i ] > m_fMaxX ) + m_fMaxX = m_pXValues[ i ]; + else if( m_pXValues[ i ] < m_fMinX ) + m_fMinX = m_pXValues[ i ]; + if( m_pOrigYValues[ i ] > m_fMaxY ) + m_fMaxY = m_pOrigYValues[ i ]; + else if( m_pOrigYValues[ i ] < m_fMinY ) + m_fMinY = m_pOrigYValues[ i ]; + } + setBoundings( m_fMinX, m_fMinY, m_fMaxX, m_fMaxY ); + } +} + +// --------------------------------------------------------------------- + +Point GridWindow::transform( double x, double y ) +{ + Point aRet; + + aRet.X() = (long)( ( x - m_fMinX ) * + (double)m_aGridArea.GetWidth() / ( m_fMaxX - m_fMinX ) + + m_aGridArea.Left() ); + aRet.Y() = (long)( + m_aGridArea.Bottom() - + ( y - m_fMinY ) * + (double)m_aGridArea.GetHeight() / ( m_fMaxY - m_fMinY ) ); + return aRet; +} + +// --------------------------------------------------------------------- + +void GridWindow::transform( const Point& rOriginal, double& x, double& y ) +{ + x = ( rOriginal.X() - m_aGridArea.Left() ) * (m_fMaxX - m_fMinX) / (double)m_aGridArea.GetWidth() + m_fMinX; + y = ( m_aGridArea.Bottom() - rOriginal.Y() ) * (m_fMaxY - m_fMinY) / (double)m_aGridArea.GetHeight() + m_fMinY; +} + +// --------------------------------------------------------------------- + +void GridWindow::drawLine( double x1, double y1, double x2, double y2 ) +{ + DrawLine( transform( x1, y1 ), transform( x2, y2 ) ); +} + +// --------------------------------------------------------------------- + +void GridWindow::computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut ) +{ + // get a nice chunk size like 10, 100, 25 or such + fChunkOut = ( fMax - fMin ) / 6.0; + int logchunk = (int)std::log10( fChunkOut ); + int nChunk = (int)( fChunkOut / std::exp( (double)(logchunk-1) * M_LN10 ) ); + if( nChunk >= 75 ) + nChunk = 100; + else if( nChunk >= 35 ) + nChunk = 50; + else if ( nChunk > 20 ) + nChunk = 25; + else if ( nChunk >= 13 ) + nChunk = 20; + else if( nChunk > 5 ) + nChunk = 10; + else + nChunk = 5; + fChunkOut = (double) nChunk * exp( (double)(logchunk-1) * M_LN10 ); + // compute whole chunks fitting into fMin + nChunk = (int)( fMin / fChunkOut ); + fMinChunkOut = (double)nChunk * fChunkOut; + while( fMinChunkOut < fMin ) + fMinChunkOut += fChunkOut; +} + +// --------------------------------------------------------------------- + +void GridWindow::computeNew() +{ + if(2L == m_aHandles.size()) + { + // special case: only left and right markers + double xleft, yleft; + double xright, yright; + transform(m_aHandles[0L].maPos, xleft, yleft); + transform(m_aHandles[1L].maPos, xright, yright ); + double factor = (yright-yleft)/(xright-xleft); + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = yleft + ( m_pXValues[ i ] - xleft )*factor; + } + } + else + { + // sort markers + std::sort(m_aHandles.begin(), m_aHandles.end()); + const int nSorted = m_aHandles.size(); + int i; + + // get node arrays + double* nodex = new double[ nSorted ]; + double* nodey = new double[ nSorted ]; + + for( i = 0L; i < nSorted; i++ ) + transform( m_aHandles[i].maPos, nodex[ i ], nodey[ i ] ); + + for( i = 0; i < m_nValues; i++ ) + { + double x = m_pXValues[ i ]; + m_pNewYValues[ i ] = interpolate( x, nodex, nodey, nSorted ); + if( m_bCutValues ) + { + if( m_pNewYValues[ i ] > m_fMaxY ) + m_pNewYValues[ i ] = m_fMaxY; + else if( m_pNewYValues[ i ] < m_fMinY ) + m_pNewYValues[ i ] = m_fMinY; + } + } + + delete [] nodex; + delete [] nodey; + } +} + +// --------------------------------------------------------------------- + +double GridWindow::interpolate( + double x, + double* pNodeX, + double* pNodeY, + int nNodes ) +{ + // compute Lagrange interpolation + double ret = 0; + for( int i = 0; i < nNodes; i++ ) + { + double sum = pNodeY[ i ]; + for( int n = 0; n < nNodes; n++ ) + { + if( n != i ) + { + sum *= x - pNodeX[ n ]; + sum /= pNodeX[ i ] - pNodeX[ n ]; + } + } + ret += sum; + } + return ret; +} + +// --------------------------------------------------------------------- + +void GridWindow::setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY ) +{ + m_fMinX = fMinX; + m_fMinY = fMinY; + m_fMaxX = fMaxX; + m_fMaxY = fMaxY; + + computeChunk( m_fMinX, m_fMaxX, m_fChunkX, m_fMinChunkX ); + computeChunk( m_fMinY, m_fMaxY, m_fChunkY, m_fMinChunkY ); +} + +// --------------------------------------------------------------------- + +void GridWindow::drawGrid() +{ + char pBuf[256]; + SetLineColor( Color( COL_BLACK ) ); + // draw vertical lines + for( double fX = m_fMinChunkX; fX < m_fMaxX; fX += m_fChunkX ) + { + drawLine( fX, m_fMinY, fX, m_fMaxY ); + // draw tickmarks + Point aPt = transform( fX, m_fMinY ); + std::sprintf( pBuf, "%g", fX ); + String aMark( pBuf, gsl_getSystemTextEncoding() ); + Size aTextSize( GetTextWidth( aMark ), GetTextHeight() ); + aPt.X() -= aTextSize.Width()/2; + aPt.Y() += aTextSize.Height()/2; + DrawText( aPt, aMark ); + } + // draw horizontal lines + for( double fY = m_fMinChunkY; fY < m_fMaxY; fY += m_fChunkY ) + { + drawLine( m_fMinX, fY, m_fMaxX, fY ); + // draw tickmarks + Point aPt = transform( m_fMinX, fY ); + std::sprintf( pBuf, "%g", fY ); + String aMark( pBuf, gsl_getSystemTextEncoding() ); + Size aTextSize( GetTextWidth( aMark ), GetTextHeight() ); + aPt.X() -= aTextSize.Width() + 2; + aPt.Y() -= aTextSize.Height()/2; + DrawText( aPt, aMark ); + } + + // draw boundings + drawLine( m_fMinX, m_fMinY, m_fMaxX, m_fMinY ); + drawLine( m_fMinX, m_fMaxY, m_fMaxX, m_fMaxY ); + drawLine( m_fMinX, m_fMinY, m_fMinX, m_fMaxY ); + drawLine( m_fMaxX, m_fMinY, m_fMaxX, m_fMaxY ); +} + +// --------------------------------------------------------------------- + +void GridWindow::drawOriginal() +{ + if( m_nValues && m_pXValues && m_pOrigYValues ) + { + SetLineColor( Color( COL_RED ) ); + for( int i = 0; i < m_nValues-1; i++ ) + { + drawLine( m_pXValues[ i ], m_pOrigYValues[ i ], + m_pXValues[ i+1 ], m_pOrigYValues[ i+1 ] ); + } + } +} + +// --------------------------------------------------------------------- + +void GridWindow::drawNew() +{ + if( m_nValues && m_pXValues && m_pNewYValues ) + { + SetClipRegion( m_aGridArea ); + SetLineColor( Color( COL_YELLOW ) ); + for( int i = 0; i < m_nValues-1; i++ ) + { + drawLine( m_pXValues[ i ], m_pNewYValues[ i ], + m_pXValues[ i+1 ], m_pNewYValues[ i+1 ] ); + } + SetClipRegion(); + } +} + +// --------------------------------------------------------------------- + +void GridWindow::drawHandles() +{ + for(sal_uInt32 i(0L); i < m_aHandles.size(); i++) + { + m_aHandles[i].draw(*this, m_aMarkerBitmap); + } +} + +// --------------------------------------------------------------------- + +void GridWindow::Paint( const Rectangle& rRect ) +{ + ModalDialog::Paint( rRect ); + drawGrid(); + drawOriginal(); + drawNew(); + drawHandles(); +} + +// --------------------------------------------------------------------- + +void GridWindow::MouseMove( const MouseEvent& rEvt ) +{ + if( rEvt.GetButtons() == MOUSE_LEFT && m_nDragIndex != 0xffffffff ) + { + Point aPoint( rEvt.GetPosPixel() ); + + if( m_nDragIndex == 0L || m_nDragIndex == m_aHandles.size() - 1L) + { + aPoint.X() = m_aHandles[m_nDragIndex].maPos.X(); + } + else + { + if(aPoint.X() < m_aGridArea.Left()) + aPoint.X() = m_aGridArea.Left(); + else if(aPoint.X() > m_aGridArea.Right()) + aPoint.X() = m_aGridArea.Right(); + } + + if( aPoint.Y() < m_aGridArea.Top() ) + aPoint.Y() = m_aGridArea.Top(); + else if( aPoint.Y() > m_aGridArea.Bottom() ) + aPoint.Y() = m_aGridArea.Bottom(); + + if( aPoint != m_aHandles[m_nDragIndex].maPos ) + { + m_aHandles[m_nDragIndex].maPos = aPoint; + Invalidate( m_aGridArea ); + } + } + + ModalDialog::MouseMove( rEvt ); +} + +// --------------------------------------------------------------------- + +void GridWindow::MouseButtonUp( const MouseEvent& rEvt ) +{ + if( rEvt.GetButtons() == MOUSE_LEFT ) + { + if( m_nDragIndex != 0xffffffff ) + { + m_nDragIndex = 0xffffffff; + computeNew(); + Invalidate( m_aGridArea ); + Paint( m_aGridArea ); + } + } + + ModalDialog::MouseButtonUp( rEvt ); +} + +// --------------------------------------------------------------------- + +void GridWindow::MouseButtonDown( const MouseEvent& rEvt ) +{ + Point aPoint( rEvt.GetPosPixel() ); + sal_uInt32 nMarkerIndex = 0xffffffff; + + for(sal_uInt32 a(0L); nMarkerIndex == 0xffffffff && a < m_aHandles.size(); a++) + { + if(m_aHandles[a].isHit(*this, aPoint)) + { + nMarkerIndex = a; + } + } + + if( rEvt.GetButtons() == MOUSE_LEFT ) + { + // user wants to drag a button + if( nMarkerIndex != 0xffffffff ) + { + m_nDragIndex = nMarkerIndex; + } + } + else if( rEvt.GetButtons() == MOUSE_RIGHT ) + { + // user wants to add/delete a button + if( nMarkerIndex != 0xffffffff ) + { + if( nMarkerIndex != 0L && nMarkerIndex != m_aHandles.size() - 1L) + { + // delete marker under mouse + if( m_nDragIndex == nMarkerIndex ) + m_nDragIndex = 0xffffffff; + + m_aHandles.erase(m_aHandles.begin() + nMarkerIndex); + } + } + else + { + m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1); + m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1); + m_aHandles.push_back(impHandle(aPoint, m_BmOffX, m_BmOffY)); + } + + computeNew(); + Invalidate( m_aGridArea ); + Paint( m_aGridArea ); + } + + ModalDialog::MouseButtonDown( rEvt ); +} + +// --------------------------------------------------------------------- + +IMPL_LINK( GridWindow, ClickButtonHdl, Button*, pButton ) +{ + if( pButton == &m_aResetButton ) + { + int nType = (int)(sal_IntPtr)m_aResetTypeBox.GetEntryData( m_aResetTypeBox.GetSelectEntryPos() ); + switch( nType ) + { + case RESET_TYPE_LINEAR_ASCENDING: + { + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX); + } + } + break; + case RESET_TYPE_LINEAR_DESCENDING: + { + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = m_fMaxY - (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX); + } + } + break; + case RESET_TYPE_RESET: + { + if( m_pOrigYValues && m_pNewYValues && m_nValues ) + memcpy( m_pNewYValues, m_pOrigYValues, m_nValues*sizeof(double) ); + } + break; + case RESET_TYPE_EXPONENTIAL: + { + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)*(std::exp((m_pXValues[i]-m_fMinX)/(m_fMaxX-m_fMinX))-1.0)/(M_E-1.0); + } + } + break; + + default: + break; + } + + for(sal_uInt32 i(0L); i < m_aHandles.size(); i++) + { + // find nearest xvalue + double x, y; + transform( m_aHandles[i].maPos, x, y ); + int nIndex = 0; + double delta = std::fabs( x-m_pXValues[0] ); + for( int n = 1; n < m_nValues; n++ ) + { + if( delta > std::fabs( x - m_pXValues[ n ] ) ) + { + delta = std::fabs( x - m_pXValues[ n ] ); + nIndex = n; + } + } + if( 0 == i ) + m_aHandles[i].maPos = transform( m_fMinX, m_pNewYValues[ nIndex ] ); + else if( m_aHandles.size() - 1L == i ) + m_aHandles[i].maPos = transform( m_fMaxX, m_pNewYValues[ nIndex ] ); + else + m_aHandles[i].maPos = transform( m_pXValues[ nIndex ], m_pNewYValues[ nIndex ] ); + } + + Invalidate( m_aGridArea ); + Paint(Rectangle()); + } + return 0; +} diff --git a/extensions/source/scanner/grid.hrc b/extensions/source/scanner/grid.hrc new file mode 100644 index 000000000000..480598bf6c4f --- /dev/null +++ b/extensions/source/scanner/grid.hrc @@ -0,0 +1,42 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef GRID_HRC +#define GRID_HRC + +#define GRID_DIALOG 1100 +#define GRID_DIALOG_OK_BTN 1 +#define GRID_DIALOG_CANCEL_BTN 2 +#define GRID_DIALOG_RESET_BTN 3 +#define GRID_DIALOG_TYPE_BOX 4 +#define GRID_DIALOG_HANDLE_BMP 5 + +#define RESET_TYPE_LINEAR_ASCENDING 10 +#define RESET_TYPE_LINEAR_DESCENDING 11 +#define RESET_TYPE_RESET 12 +#define RESET_TYPE_EXPONENTIAL 13 + +#endif diff --git a/extensions/source/scanner/grid.hxx b/extensions/source/scanner/grid.hxx new file mode 100644 index 000000000000..42791f355493 --- /dev/null +++ b/extensions/source/scanner/grid.hxx @@ -0,0 +1,149 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _EXTENSIONS_SCANNER_GRID_HXX +#define _EXTENSIONS_SCANNER_GRID_HXX + +#include <vcl/window.hxx> +#ifndef _SV_BUTTON_HXX +#include <vcl/button.hxx> +#endif +#include <vcl/lstbox.hxx> +#include <vcl/dialog.hxx> + +class GridWindow : public ModalDialog +{ + // helper class for handles + struct impHandle + { + Point maPos; + sal_uInt16 mnOffX; + sal_uInt16 mnOffY; + + impHandle(const Point& rPos, sal_uInt16 nX, sal_uInt16 nY) + : maPos(rPos), mnOffX(nX), mnOffY(nY) + { + } + + bool operator<(const impHandle& rComp) const + { + return (maPos.X() < rComp.maPos.X()); + } + + void draw(Window& rWin, const BitmapEx& rBitmapEx) + { + const Point aOffset(rWin.PixelToLogic(Point(mnOffX, mnOffY))); + rWin.DrawBitmapEx(maPos - aOffset, rBitmapEx); + } + + bool isHit(Window& rWin, const Point& rPos) + { + const Point aOffset(rWin.PixelToLogic(Point(mnOffX, mnOffY))); + const Rectangle aTarget(maPos - aOffset, maPos + aOffset); + return aTarget.IsInside(rPos); + } + }; + + Rectangle m_aGridArea; + + double m_fMinX; + double m_fMinY; + double m_fMaxX; + double m_fMaxY; + + double m_fChunkX; + double m_fMinChunkX; + double m_fChunkY; + double m_fMinChunkY; + + double* m_pXValues; + double* m_pOrigYValues; + int m_nValues; + double* m_pNewYValues; + + sal_uInt16 m_BmOffX; + sal_uInt16 m_BmOffY; + + BOOL m_bCutValues; + + // stuff for handles + std::vector< impHandle > m_aHandles; + sal_uInt32 m_nDragIndex; + + BitmapEx m_aMarkerBitmap; + + OKButton m_aOKButton; + CancelButton m_aCancelButton; + + ListBox m_aResetTypeBox; + PushButton m_aResetButton; + + + Point transform( double x, double y ); + void transform( const Point& rOriginal, double& x, double& y ); + + double findMinX(); + double findMinY(); + double findMaxX(); + double findMaxY(); + + void drawGrid(); + void drawOriginal(); + void drawNew(); + void drawHandles(); + + void computeExtremes(); + void computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut ); + void computeNew(); + double interpolate( double x, double* pNodeX, double* pNodeY, int nNodes ); + + DECL_LINK( ClickButtonHdl, Button* ); + + virtual void MouseMove( const MouseEvent& ); + virtual void MouseButtonDown( const MouseEvent& ); + virtual void MouseButtonUp( const MouseEvent& ); +public: + GridWindow( double* pXValues, double* pYValues, int nValues, + Window* pParent, BOOL bCutValues = TRUE ); + ~GridWindow(); + + void setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY ); + double getMinX() { return m_fMinX; } + double getMinY() { return m_fMinY; } + double getMaxX() { return m_fMaxX; } + double getMaxY() { return m_fMaxY; } + + int countValues() { return m_nValues; } + double* getXValues() { return m_pXValues; } + double* getOrigYValues() { return m_pOrigYValues; } + double* getNewYValues() { return m_pNewYValues; } + + void drawLine( double x1, double y1, double x2, double y2 ); + + virtual void Paint( const Rectangle& rRect ); +}; + +#endif // _EXTENSIONS_SCANNER_GRID_HXX diff --git a/extensions/source/scanner/grid.src b/extensions/source/scanner/grid.src new file mode 100644 index 000000000000..e7e8128cbc84 --- /dev/null +++ b/extensions/source/scanner/grid.src @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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 <grid.hrc> + +ModalDialog GRID_DIALOG +{ + OutputSize = TRUE ; + SVLook = TRUE ; + Pos = MAP_APPFONT ( 10 , 10 ) ; + Size = MAP_APPFONT ( 300, 200 ) ; + Moveable = TRUE ; + Closeable = TRUE ; + + OKButton GRID_DIALOG_OK_BTN + { + Pos = MAP_APPFONT( 245, 5 ); + Size = MAP_APPFONT( 50, 15 ); + DefButton = TRUE; + }; + CancelButton GRID_DIALOG_CANCEL_BTN + { + Pos = MAP_APPFONT ( 245 , 25 ) ; + Size = MAP_APPFONT ( 50 , 15 ) ; + }; + ListBox GRID_DIALOG_TYPE_BOX + { + Border = TRUE ; + Dropdown = TRUE ; + Pos = MAP_APPFONT( 245, 45 ); + Size = MAP_APPFONT( 50, 130 ); + }; + PushButton GRID_DIALOG_RESET_BTN + { + Pos = MAP_APPFONT( 245, 65 ); + Size = MAP_APPFONT( 50, 15 ); + Text [ en-US ] = "Set"; + }; + Bitmap GRID_DIALOG_HANDLE_BMP + { + File = "handle.bmp"; + }; + String RESET_TYPE_LINEAR_ASCENDING + { + Text [ en-US ] = "Linear ascending"; + }; + String RESET_TYPE_LINEAR_DESCENDING + { + Text [ en-US ] = "Linear descending"; + }; + String RESET_TYPE_RESET + { + Text [ en-US ] = "Original values"; + }; + String RESET_TYPE_EXPONENTIAL + { + Text [ en-US ] = "Exponential increasing"; + }; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/source/scanner/makefile.mk b/extensions/source/scanner/makefile.mk new file mode 100644 index 000000000000..ff42864e0496 --- /dev/null +++ b/extensions/source/scanner/makefile.mk @@ -0,0 +1,100 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# 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. +# +#************************************************************************* +PRJ=..$/.. +PRJNAME=extensions +TARGET=scn +ENABLE_EXCEPTIONS=TRUE +PACKAGE=com$/sun$/star$/scanner +USE_DEFFILE=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES=\ + $(SLO)$/scnserv.obj \ + $(SLO)$/scanner.obj + +.IF "$(GUI)"=="WNT" +SLOFILES+=\ + $(SLO)$/scanwin.obj +.ENDIF + +.IF "$(GUI)"=="UNX" || "$(GUI)" =="OS2" +SLOFILES+=\ + $(SLO)$/sane.obj \ + $(SLO)$/sanedlg.obj \ + $(SLO)$/scanunx.obj \ + $(SLO)$/grid.obj + +.ENDIF + +SRS1NAME=$(TARGET) +SRC1FILES=\ + sanedlg.src \ + grid.src + +RESLIB1NAME=san +RESLIB1IMAGES=$(PRJ)$/source$/scanner +RESLIB1SRSFILES= $(SRS)$/scn.srs +RESLIB1DEPN= sanedlg.src sanedlg.hrc grid.src grid.hrc + +SHL1TARGET= $(TARGET)$(DLLPOSTFIX) +SHL1STDLIBS=\ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(COMPHELPERLIB) \ + $(VOSLIB) \ + $(SALLIB) \ + $(ONELIB) \ + $(TOOLSLIB) \ + $(VCLLIB) \ + $(SVTOOLLIB) + +.IF "$(GUI)"=="UNX" +.IF "$(OS)"!="FREEBSD" +.IF "$(OS)"!="NETBSD" +SHL1STDLIBS+=$(SVTOOLLIB) -ldl +.ENDIF +.ENDIF +.ENDIF + +SHL1DEF=$(MISC)$/$(SHL1TARGET).def +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)$/$(TARGET).lib +SHL1VERSIONMAP=$(SOLARENV)/src/component.map + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=exports.dxp + + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/extensions/source/scanner/sane.cxx b/extensions/source/scanner/sane.cxx new file mode 100644 index 000000000000..43c50e6f8451 --- /dev/null +++ b/extensions/source/scanner/sane.cxx @@ -0,0 +1,1004 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include <cstdarg> +#include <math.h> +#include <osl/file.h> +#include <tools/stream.hxx> +#include <sane.hxx> +#include <dlfcn.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sal/config.h> + +#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL +#include <stdarg.h> +#define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d ); +#else +#define dump_state( a, b, c, d ) ; +#endif +inline void dbg_msg( const char* pString, ... ) +{ +#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL + va_list ap; + va_start( ap, pString ); + vfprintf( stderr, pString, ap ); + va_end( ap ); +#else + (void)pString; +#endif +} + +#define FAIL_SHUTDOWN_STATE( x, y, z ) \ + if( x != SANE_STATUS_GOOD ) \ + { \ + dump_state( "%s returned error %d (%s)\n", \ + y, x, p_strstatus( x ) ); \ + DeInit(); \ + return z; \ + } + +#define FAIL_STATE( x, y, z ) \ + if( x != SANE_STATUS_GOOD ) \ + { \ + dump_state( "%s returned error %d (%s)\n", \ + y, x, p_strstatus( x ) ); \ + return z; \ + } + +#define DUMP_STATE( x, y ) \ + if( x != SANE_STATUS_GOOD ) \ + { \ + dump_state( "%s returned error %d (%s)\n", \ + y, x, p_strstatus( x ) ); \ + } + +#define CHECK_STATE( x, y ) \ + if( x != SANE_STATUS_GOOD ) \ + { \ + dump_state( "%s returned error %d (%s)\n", \ + y, x, p_strstatus( x ) ); \ + } \ + else + +int Sane::nRefCount = 0; +oslModule Sane::pSaneLib = 0; +SANE_Int Sane::nVersion = 0; +SANE_Device** Sane::ppDevices = 0; +int Sane::nDevices = 0; + +SANE_Status (*Sane::p_init)( SANE_Int*, + SANE_Auth_Callback ) = 0; +void (*Sane::p_exit)() = 0; +SANE_Status (*Sane::p_get_devices)( const SANE_Device***, + SANE_Bool ) = 0; +SANE_Status (*Sane::p_open)( SANE_String_Const, SANE_Handle ) = 0; +void (*Sane::p_close)( SANE_Handle ) = 0; +const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)( + SANE_Handle, SANE_Int ) = 0; +SANE_Status (*Sane::p_control_option)( SANE_Handle, SANE_Int, + SANE_Action, void*, + SANE_Int* ) = 0; +SANE_Status (*Sane::p_get_parameters)( SANE_Handle, + SANE_Parameters* ) = 0; +SANE_Status (*Sane::p_start)( SANE_Handle ) = 0; +SANE_Status (*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int, + SANE_Int* ) = 0; +void (*Sane::p_cancel)( SANE_Handle ) = 0; +SANE_Status (*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = 0; +SANE_Status (*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = 0; +SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = 0; + +static BOOL bSaneSymbolLoadFailed = FALSE; + +inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname ) +{ + oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname ); + if( ! pFunction ) + { + fprintf( stderr, "Could not load symbol %s\n", + pSymbolname ); + bSaneSymbolLoadFailed = TRUE; + } + return pFunction; +} + +SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction, + void* pData ) +{ + SANE_Status nStatus = SANE_STATUS_GOOD; + SANE_Int nInfo = 0; + + nStatus = p_control_option( maHandle, (SANE_Int)nOption, + nAction, pData, &nInfo ); + DUMP_STATE( nStatus, "sane_control_option" ); +#if OSL_DEBUG_LEVEL > 1 + if( nStatus != SANE_STATUS_GOOD ) + { + const char* pAction = "Unknown"; + switch( nAction ) + { + case SANE_ACTION_GET_VALUE: + pAction = "SANE_ACTION_GET_VALUE";break; + case SANE_ACTION_SET_VALUE: + pAction = "SANE_ACTION_SET_VALUE";break; + case SANE_ACTION_SET_AUTO: + pAction = "SANE_ACTION_SET_AUTO";break; + } + dbg_msg( "Option: \"%s\" action: %s\n", + ByteString( GetOptionName( nOption ), gsl_getSystemTextEncoding() ).GetBuffer(), + pAction ); + } +#endif +// if( nInfo & ( SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS ) ) + if( nInfo & SANE_INFO_RELOAD_OPTIONS ) + ReloadOptions(); + return nStatus; +} + +Sane::Sane() : + mppOptions( 0 ), + mnOptions( 0 ), + mnDevice( -1 ), + maHandle( 0 ) +{ + if( ! nRefCount || ! pSaneLib ) + Init(); + nRefCount++; +}; + +Sane::~Sane() +{ + if( IsOpen() ) + Close(); + nRefCount--; + if( ! nRefCount && pSaneLib ) + DeInit(); +} + +void Sane::Init() +{ + ::rtl::OUString sSaneLibName( ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ) ); + pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); + if( ! pSaneLib ) + { + sSaneLibName = ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ".1" ); + pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); + } + // try reasonable places that might not be in the library search path + if( ! pSaneLib ) + { + ::rtl::OUString sSaneLibSystemPath( ::rtl::OUString::createFromAscii( "/usr/local/lib/libsane" SAL_DLLEXTENSION ) ); + osl_getFileURLFromSystemPath( sSaneLibSystemPath.pData, &sSaneLibName.pData ); + pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); + } + + if( pSaneLib ) + { + bSaneSymbolLoadFailed = FALSE; + p_init = (SANE_Status(*)(SANE_Int*, SANE_Auth_Callback )) + LoadSymbol( "sane_init" ); + p_exit = (void(*)()) + LoadSymbol( "sane_exit" ); + p_get_devices = (SANE_Status(*)(const SANE_Device***, + SANE_Bool )) + LoadSymbol( "sane_get_devices" ); + p_open = (SANE_Status(*)(SANE_String_Const, SANE_Handle )) + LoadSymbol( "sane_open" ); + p_close = (void(*)(SANE_Handle)) + LoadSymbol( "sane_close" ); + p_get_option_descriptor = (const SANE_Option_Descriptor*(*)(SANE_Handle, + SANE_Int)) + LoadSymbol( "sane_get_option_descriptor" ); + p_control_option = (SANE_Status(*)(SANE_Handle, SANE_Int, + SANE_Action, void*, SANE_Int*)) + LoadSymbol( "sane_control_option" ); + p_get_parameters = (SANE_Status(*)(SANE_Handle,SANE_Parameters*)) + LoadSymbol( "sane_get_parameters" ); + p_start = (SANE_Status(*)(SANE_Handle)) + LoadSymbol( "sane_start" ); + p_read = (SANE_Status(*)(SANE_Handle, SANE_Byte*, + SANE_Int, SANE_Int* )) + LoadSymbol( "sane_read" ); + p_cancel = (void(*)(SANE_Handle)) + LoadSymbol( "sane_cancel" ); + p_set_io_mode = (SANE_Status(*)(SANE_Handle, SANE_Bool)) + LoadSymbol( "sane_set_io_mode" ); + p_get_select_fd = (SANE_Status(*)(SANE_Handle, SANE_Int*)) + LoadSymbol( "sane_get_select_fd" ); + p_strstatus = (SANE_String_Const(*)(SANE_Status)) + LoadSymbol( "sane_strstatus" ); + if( bSaneSymbolLoadFailed ) + DeInit(); + else + { + SANE_Status nStatus = p_init( &nVersion, 0 ); + FAIL_SHUTDOWN_STATE( nStatus, "sane_init", ); + nStatus = p_get_devices( (const SANE_Device***)&ppDevices, + SANE_FALSE ); + FAIL_SHUTDOWN_STATE( nStatus, "sane_get_devices", ); + for( nDevices = 0 ; ppDevices[ nDevices ]; nDevices++ ) ; + } + } +#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL + else + fprintf( stderr, "libsane%s could not be opened: %s\n", SAL_DLLEXTENSION, + dlerror() ); +#endif +} + +void Sane::DeInit() +{ + if( pSaneLib ) + { + p_exit(); + osl_unloadModule( pSaneLib ); + pSaneLib = 0; + } +} + +void Sane::ReloadDevices() +{ + if( IsOpen() ) + Close(); + DeInit(); + Init(); +} + +void Sane::ReloadOptions() +{ + if( ! IsOpen() ) + return; + + SANE_Option_Descriptor* pZero = (SANE_Option_Descriptor*) + p_get_option_descriptor( maHandle, 0 ); + SANE_Word pOptions[2]; + SANE_Status nStatus = p_control_option( maHandle, 0, SANE_ACTION_GET_VALUE, + (void*)pOptions, NULL ); + if( nStatus != SANE_STATUS_GOOD ) + fprintf( stderr, "Error: sane driver returned %s while reading number of options !\n", p_strstatus( nStatus ) ); + + mnOptions = pOptions[ 0 ]; + if( (size_t)pZero->size > sizeof( SANE_Word ) ) + fprintf( stderr, "driver returned numer of options with larger size tha SANE_Word !!!\n" ); + if( mppOptions ) + delete [] mppOptions; + mppOptions = (const SANE_Option_Descriptor**)new SANE_Option_Descriptor*[ mnOptions ]; + mppOptions[ 0 ] = (SANE_Option_Descriptor*)pZero; + for( int i = 1; i < mnOptions; i++ ) + mppOptions[ i ] = (SANE_Option_Descriptor*) + p_get_option_descriptor( maHandle, i ); + + CheckConsistency( NULL, TRUE ); + + maReloadOptionsLink.Call( this ); +} + +BOOL Sane::Open( const char* name ) +{ + int i; + + SANE_Status nStatus = p_open( (SANE_String_Const)name, &maHandle ); + FAIL_STATE( nStatus, "sane_open", FALSE ); + + ReloadOptions(); + + if( mnDevice == -1 ) + { + ByteString aDevice( name ); + for( i = 0; i < nDevices; i++ ) + { + if( aDevice.Equals( ppDevices[i]->name ) ) + { + mnDevice = i; + break; + } + } + } + + return TRUE; +} + +BOOL Sane::Open( int n ) +{ + if( n >= 0 && n < nDevices ) + { + mnDevice = n; + return Open( (char*)ppDevices[n]->name ); + } + return FALSE; +} + +void Sane::Close() +{ + if( maHandle ) + { + p_close( maHandle ); + delete [] mppOptions; + mppOptions = 0; + maHandle = 0; + mnDevice = -1; + } +} + +int Sane::GetOptionByName( const char* rName ) +{ + int i; + ByteString aOption( rName ); + for( i = 0; i < mnOptions; i++ ) + { + if( mppOptions[i]->name && aOption.Equals( mppOptions[i]->name ) ) + return i; + } + return -1; +} + +BOOL Sane::GetOptionValue( int n, BOOL& rRet ) +{ + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL ) + return FALSE; + SANE_Word nRet; + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, &nRet ); + if( nStatus != SANE_STATUS_GOOD ) + return FALSE; + + rRet = nRet; + return TRUE; +} + +BOOL Sane::GetOptionValue( int n, ByteString& rRet ) +{ + BOOL bSuccess = FALSE; + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING ) + return FALSE; + char* pRet = new char[mppOptions[n]->size+1]; + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet ); + if( nStatus == SANE_STATUS_GOOD ) + { + bSuccess = TRUE; + rRet = pRet; + } + delete [] pRet; + return bSuccess; +} + +BOOL Sane::GetOptionValue( int n, double& rRet, int nElement ) +{ + BOOL bSuccess = FALSE; + + if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT && + mppOptions[n]->type != SANE_TYPE_FIXED ) ) + return FALSE; + + SANE_Word* pRet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet ); + if( nStatus == SANE_STATUS_GOOD ) + { + bSuccess = TRUE; + if( mppOptions[n]->type == SANE_TYPE_INT ) + rRet = (double)pRet[ nElement ]; + else + rRet = SANE_UNFIX( pRet[nElement] ); + } + delete [] pRet; + return bSuccess; +} + +BOOL Sane::GetOptionValue( int n, double* pSet ) +{ + if( ! maHandle || ! ( mppOptions[n]->type == SANE_TYPE_FIXED || + mppOptions[n]->type == SANE_TYPE_INT ) ) + return FALSE; + + SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet ); + if( nStatus != SANE_STATUS_GOOD ) + { + delete [] pFixedSet; + return FALSE; + } + for( size_t i = 0; i <mppOptions[n]->size/sizeof(SANE_Word); i++ ) + { + if( mppOptions[n]->type == SANE_TYPE_FIXED ) + pSet[i] = SANE_UNFIX( pFixedSet[i] ); + else + pSet[i] = (double) pFixedSet[i]; + } + delete [] pFixedSet; + return TRUE; +} + +BOOL Sane::SetOptionValue( int n, BOOL bSet ) +{ + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL ) + return FALSE; + SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE; + SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nRet ); + if( nStatus != SANE_STATUS_GOOD ) + return FALSE; + return TRUE; +} + +BOOL Sane::SetOptionValue( int n, const String& rSet ) +{ + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING ) + return FALSE; + ByteString aSet( rSet, gsl_getSystemTextEncoding() ); + SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, (void*)aSet.GetBuffer() ); + if( nStatus != SANE_STATUS_GOOD ) + return FALSE; + return TRUE; +} + +BOOL Sane::SetOptionValue( int n, double fSet, int nElement ) +{ + BOOL bSuccess = FALSE; + + if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT && + mppOptions[n]->type != SANE_TYPE_FIXED ) ) + return FALSE; + + SANE_Status nStatus; + if( mppOptions[n]->size/sizeof(SANE_Word) > 1 ) + { + SANE_Word* pSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; + nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet ); + if( nStatus == SANE_STATUS_GOOD ) + { + pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ? + (SANE_Word)fSet : SANE_FIX( fSet ); + nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pSet ); + } + delete [] pSet; + } + else + { + SANE_Word nSetTo = + mppOptions[n]->type == SANE_TYPE_INT ? + (SANE_Word)fSet : SANE_FIX( fSet ); + + nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo ); + if( nStatus == SANE_STATUS_GOOD ) + bSuccess = TRUE; + } + return bSuccess; +} + +BOOL Sane::SetOptionValue( int n, double* pSet ) +{ + if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT && + mppOptions[n]->type != SANE_TYPE_FIXED ) ) + return FALSE; + SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; + for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ ) + { + if( mppOptions[n]->type == SANE_TYPE_FIXED ) + pFixedSet[i] = SANE_FIX( pSet[i] ); + else + pFixedSet[i] = (SANE_Word)pSet[i]; + } + SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet ); + delete [] pFixedSet; + if( nStatus != SANE_STATUS_GOOD ) + return FALSE; + return TRUE; +} + +enum FrameStyleType { + FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated +}; + +#define BYTE_BUFFER_SIZE 32768 + +static inline UINT8 _ReadValue( FILE* fp, int depth ) +{ + if( depth == 16 ) + { + UINT16 nWord; + // data always come in native byte order ! + // 16 bits is not really supported by backends as of now + // e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN + // against SANE documentation (xscanimage gets the same result + // as we do + fread( &nWord, 1, 2, fp ); + return (UINT8)( nWord / 256 ); + } + UINT8 nByte; + fread( &nByte, 1, 1, fp ); + return nByte; +} + +BOOL Sane::CheckConsistency( const char* pMes, BOOL bInit ) +{ + static SANE_Option_Descriptor** pDescArray = NULL; + static SANE_Option_Descriptor* pZero = NULL; + + if( bInit ) + { + pDescArray = (SANE_Option_Descriptor**)mppOptions; + if( mppOptions ) + pZero = (SANE_Option_Descriptor*)mppOptions[0]; + return TRUE; + } + + BOOL bConsistent = TRUE; + + if( pDescArray != mppOptions ) + bConsistent = FALSE; + if( pZero != mppOptions[0] ) + bConsistent = FALSE; + + if( ! bConsistent ) + dbg_msg( "Sane is not consistent. (%s)\n", pMes ); + + return bConsistent; +} + +BOOL Sane::Start( BitmapTransporter& rBitmap ) +{ + int nStream = 0, nLine = 0, i = 0; + SANE_Parameters aParams; + FrameStyleType eType = FrameStyle_Gray; + BOOL bSuccess = TRUE; + BOOL bWidthSet = FALSE; + + if( ! maHandle ) + return FALSE; + + int nWidthMM = 0; + int nHeightMM = 0; + double fTLx, fTLy, fBRx, fBRy, fResl = 0.0; + int nOption; + if( ( nOption = GetOptionByName( "tl-x" ) ) != -1 && + GetOptionValue( nOption, fTLx, 0 ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + if( ( nOption = GetOptionByName( "br-x" ) ) != -1 && + GetOptionValue( nOption, fBRx, 0 ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + nWidthMM = (int)fabs(fBRx - fTLx); + } + } + if( ( nOption = GetOptionByName( "tl-y" ) ) != -1 && + GetOptionValue( nOption, fTLy, 0 ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + if( ( nOption = GetOptionByName( "br-y" ) ) != -1 && + GetOptionValue( nOption, fBRy, 0 ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + nHeightMM = (int)fabs(fBRy - fTLy); + } + } + if( ( nOption = GetOptionByName( "resolution" ) ) != -1 ) + GetOptionValue( nOption, fResl ); + + BYTE* pBuffer = NULL; + + SANE_Status nStatus = SANE_STATUS_GOOD; + + rBitmap.lock(); + SvMemoryStream& aConverter = rBitmap.getStream(); + aConverter.Seek( 0 ); + aConverter.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + // write bitmap stream header + aConverter << 'B' << 'M'; + aConverter << (sal_uInt32) 0; + aConverter << (sal_uInt32) 0; + aConverter << (sal_uInt32) 60; + + // write BITMAPINFOHEADER + aConverter << (UINT32)40; + aConverter << (UINT32)0; // fill in width later + aConverter << (UINT32)0; // fill in height later + aConverter << (UINT16)1; + // create header for 24 bits + // correct later if necessary + aConverter << (UINT16)24; + aConverter << (UINT32)0; + aConverter << (UINT32)0; + aConverter << (UINT32)0; + aConverter << (UINT32)0; + aConverter << (UINT32)0; + aConverter << (UINT32)0; + + for( nStream=0; nStream < 3 && bSuccess ; nStream++ ) + { + nStatus = p_start( maHandle ); + DUMP_STATE( nStatus, "sane_start" ); + CheckConsistency( "sane_start" ); + if( nStatus == SANE_STATUS_GOOD ) + { + nStatus = p_get_parameters( maHandle, &aParams ); + DUMP_STATE( nStatus, "sane_get_parameters" ); + CheckConsistency( "sane_get_parameters" ); + if (nStatus != SANE_STATUS_GOOD || aParams.bytes_per_line == 0) + { + bSuccess = FALSE; + break; + } +#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL + const char* ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB", + "SANE_FRAME_RED", "SANE_FRAME_GREEN", + "SANE_FRAME_BLUE", "Unknown !!!" }; + fprintf( stderr, "Parameters for frame %d:\n", nStream ); + if( aParams.format < 0 || aParams.format > 4 ) + aParams.format = (SANE_Frame)5; + fprintf( stderr, "format: %s\n", ppFormats[ (int)aParams.format ] ); + fprintf( stderr, "last_frame: %s\n", aParams.last_frame ? "TRUE" : "FALSE" ); + fprintf( stderr, "depth: %d\n", (int)aParams.depth ); + fprintf( stderr, "pixels_per_line: %d\n", (int)aParams.pixels_per_line ); + fprintf( stderr, "bytes_per_line: %d\n", (int)aParams.bytes_per_line ); +#endif + if( ! pBuffer ) + { + pBuffer = new BYTE[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ]; + } + + if( aParams.last_frame ) + nStream=3; + + switch( aParams.format ) + { + case SANE_FRAME_GRAY: + eType = FrameStyle_Gray; + if( aParams.depth == 1 ) + eType = FrameStyle_BW; + break; + case SANE_FRAME_RGB: + eType = FrameStyle_RGB; + break; + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + eType = FrameStyle_Separated; + break; + default: + fprintf( stderr, "Warning: unknown frame style !!!\n" ); + } + + BOOL bSynchronousRead = TRUE; + + // should be fail safe, but ... ?? + nStatus = p_set_io_mode( maHandle, SANE_FALSE ); + CheckConsistency( "sane_set_io_mode" ); + if( nStatus != SANE_STATUS_GOOD ) + { + bSynchronousRead = FALSE; + nStatus = p_set_io_mode( maHandle, SANE_TRUE ); + CheckConsistency( "sane_set_io_mode" ); +#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL + if( nStatus != SANE_STATUS_GOOD ) + // what ?!? + fprintf( stderr, "Sane::Start: driver is confused\n" ); +#endif + } + + SANE_Int nLen=0; + SANE_Int fd = 0; + + if( ! bSynchronousRead ) + { + nStatus = p_get_select_fd( maHandle, &fd ); + DUMP_STATE( nStatus, "sane_get_select_fd" ); + CheckConsistency( "sane_get_select_fd" ); + if( nStatus != SANE_STATUS_GOOD ) + bSynchronousRead = TRUE; + } + FILE* pFrame = tmpfile(); + if( ! pFrame ) + { + bSuccess = FALSE; + break; + } + do { + if( ! bSynchronousRead ) + { + fd_set fdset; + struct timeval tv; + + FD_ZERO( &fdset ); + FD_SET( (int)fd, &fdset ); + tv.tv_sec = 5; + tv.tv_usec = 0; + if( select( fd+1, &fdset, NULL, NULL, &tv ) == 0 ) + fprintf( stderr, "Timout on sane_read descriptor\n" ); + } + nLen = 0; + nStatus = p_read( maHandle, pBuffer, BYTE_BUFFER_SIZE, &nLen ); + CheckConsistency( "sane_read" ); + if( nLen && ( nStatus == SANE_STATUS_GOOD || + nStatus == SANE_STATUS_EOF ) ) + { + fwrite( pBuffer, 1, nLen, pFrame ); + } + else + DUMP_STATE( nStatus, "sane_read" ); + } while( nStatus == SANE_STATUS_GOOD ); + if( nStatus != SANE_STATUS_EOF ) + { + fclose( pFrame ); + bSuccess = FALSE; + break; + } + + int nFrameLength = ftell( pFrame ); + fseek( pFrame, 0, SEEK_SET ); + UINT32 nWidth = (UINT32) aParams.pixels_per_line; + UINT32 nHeight = (UINT32) (nFrameLength / aParams.bytes_per_line); + if( ! bWidthSet ) + { + if( ! fResl ) + fResl = 300; // if all else fails that's a good guess + if( ! nWidthMM ) + nWidthMM = (int)(((double)nWidth / fResl) * 25.4); + if( ! nHeightMM ) + nHeightMM = (int)(((double)nHeight / fResl) * 25.4); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "set dimensions to (%d, %d) Pixel, (%d, %d) mm, resolution is %lg\n", (int)nWidth, (int)nHeight, (int)nWidthMM, (int)nHeightMM, fResl ); +#endif + + aConverter.Seek( 18 ); + aConverter << (UINT32)nWidth; + aConverter << (UINT32)nHeight; + aConverter.Seek( 38 ); + aConverter << (UINT32)(1000*nWidth/nWidthMM); + aConverter << (UINT32)(1000*nHeight/nHeightMM); + bWidthSet = TRUE; + } + aConverter.Seek(60); + + if( eType == FrameStyle_BW ) + { + aConverter.Seek( 10 ); + aConverter << (sal_uInt32)64; + aConverter.Seek( 28 ); + aConverter << (UINT16) 1; + aConverter.Seek( 54 ); + // write color table + aConverter << (UINT16)0xffff; + aConverter << (UINT8)0xff; + aConverter << (UINT8)0; + aConverter << (UINT32)0; + aConverter.Seek( 64 ); + } + else if( eType == FrameStyle_Gray ) + { + aConverter.Seek( 10 ); + aConverter << (sal_uInt32)1084; + aConverter.Seek( 28 ); + aConverter << (UINT16) 8; + aConverter.Seek( 54 ); + // write color table + for( nLine = 0; nLine < 256; nLine++ ) + { + aConverter << (UINT8)nLine; + aConverter << (UINT8)nLine; + aConverter << (UINT8)nLine; + aConverter << (UINT8)0; + } + aConverter.Seek( 1084 ); + } + + for( nLine = nHeight-1; + nLine >= 0; nLine-- ) + { + fseek( pFrame, nLine * aParams.bytes_per_line, SEEK_SET ); + if( eType == FrameStyle_BW || + ( eType == FrameStyle_Gray && aParams.depth == 8 ) + ) + { + fread( pBuffer, 1, aParams.bytes_per_line, pFrame ); + aConverter.Write( pBuffer, aParams.bytes_per_line ); + } + else if( eType == FrameStyle_Gray ) + { + for( i = 0; i < (aParams.pixels_per_line); i++ ) + { + UINT8 nGray = _ReadValue( pFrame, aParams.depth ); + aConverter << nGray; + } + } + else if( eType == FrameStyle_RGB ) + { + for( i = 0; i < (aParams.pixels_per_line); i++ ) + { + UINT8 nRed, nGreen, nBlue; + nRed = _ReadValue( pFrame, aParams.depth ); + nGreen = _ReadValue( pFrame, aParams.depth ); + nBlue = _ReadValue( pFrame, aParams.depth ); + aConverter << nBlue; + aConverter << nGreen; + aConverter << nRed; + } + } + else if( eType == FrameStyle_Separated ) + { + for( i = 0; i < (aParams.pixels_per_line); i++ ) + { + UINT8 nValue = _ReadValue( pFrame, aParams.depth ); + switch( aParams.format ) + { + case SANE_FRAME_RED: + aConverter.SeekRel( 2 ); + aConverter << nValue; + break; + case SANE_FRAME_GREEN: + aConverter.SeekRel( 1 ); + aConverter << nValue; + aConverter.SeekRel( 1 ); + break; + case SANE_FRAME_BLUE: + aConverter << nValue; + aConverter.SeekRel( 2 ); + break; + case SANE_FRAME_GRAY: + case SANE_FRAME_RGB: + break; + } + } + } + int nGap = aConverter.Tell() & 3; + if( nGap ) + aConverter.SeekRel( 4-nGap ); + } + fclose( pFrame ); // deletes tmpfile + if( eType != FrameStyle_Separated ) + break; + } + else + bSuccess = FALSE; + } + // get stream length + aConverter.Seek( STREAM_SEEK_TO_END ); + int nPos = aConverter.Tell(); + + aConverter.Seek( 2 ); + aConverter << (sal_uInt32) nPos+1; + aConverter.Seek( 0 ); + + rBitmap.unlock(); + + if( bSuccess ) + { + // only cancel a successful operation + // sane disrupts memory else + p_cancel( maHandle ); + CheckConsistency( "sane_cancel" ); + } + if( pBuffer ) + delete [] pBuffer; + + ReloadOptions(); + + + dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" ); + + return bSuccess; +} + +int Sane::GetRange( int n, double*& rpDouble ) +{ + if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE && + mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST ) + { + return -1; + } + + rpDouble = 0; + int nItems, i; + BOOL bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED ? TRUE : FALSE; + + dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name ); + if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE ) + { + double fMin, fMax, fQuant; + if( bIsFixed ) + { + fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min ); + fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max ); + fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant ); + } + else + { + fMin = (double)mppOptions[n]->constraint.range->min; + fMax = (double)mppOptions[n]->constraint.range->max; + fQuant = (double)mppOptions[n]->constraint.range->quant; + } + if( fQuant != 0.0 ) + { + dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n", + fMin, fQuant, fMax ); + nItems = (int)((fMax - fMin)/fQuant)+1; + rpDouble = new double[ nItems ]; + double fValue = fMin; + for( i = 0; i < nItems; i++, fValue += fQuant ) + rpDouble[i] = fValue; + rpDouble[ nItems-1 ] = fMax; + return nItems; + } + else + { + dbg_msg( "normal range [ %lg %lg ]\n", + fMin, fMax ); + rpDouble = new double[2]; + rpDouble[0] = fMin; + rpDouble[1] = fMax; + return 0; + } + } + else + { + nItems = mppOptions[n]->constraint.word_list[0]; + rpDouble = new double[nItems]; + for( i=0; i<nItems; i++ ) + { + rpDouble[i] = bIsFixed ? + SANE_UNFIX( mppOptions[n]->constraint.word_list[i+1] ) : + (double)mppOptions[n]->constraint.word_list[i+1]; + } + dbg_msg( "wordlist [ %lg ... %lg ]\n", + rpDouble[ 0 ], rpDouble[ nItems-1 ] ); + return nItems; + } +} + +static const char *ppUnits[] = { + "", + "[Pixel]", + "[Bit]", + "[mm]", + "[DPI]", + "[%]", + "[usec]" +}; + +String Sane::GetOptionUnitName( int n ) +{ + String aText; + SANE_Unit nUnit = mppOptions[n]->unit; + size_t nUnitAsSize = (size_t)nUnit; + if( nUnitAsSize > sizeof( ppUnits )/sizeof( ppUnits[0] ) ) + aText = String::CreateFromAscii( "[unknown units]" ); + else + aText = String( ppUnits[ nUnit ], gsl_getSystemTextEncoding() ); + return aText; +} + +BOOL Sane::ActivateButtonOption( int n ) +{ + SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, NULL ); + if( nStatus != SANE_STATUS_GOOD ) + return FALSE; + return TRUE; +} diff --git a/extensions/source/scanner/sane.hxx b/extensions/source/scanner/sane.hxx new file mode 100644 index 000000000000..44ce0d295f42 --- /dev/null +++ b/extensions/source/scanner/sane.hxx @@ -0,0 +1,200 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SANE_HXX +#define _SANE_HXX + +#include <osl/thread.h> +#include <osl/module.h> +#include <tools/string.hxx> +#include <vcl/bitmap.hxx> +#include <sane/sane.h> +#include <scanner.hxx> + +// --------------------- +// - BitmapTransporter - +// --------------------- + +class BitmapTransporter : public OWeakObject, AWT::XBitmap +{ + SvMemoryStream m_aStream; + vos::OMutex m_aProtector; + +public: + + BitmapTransporter(); + virtual ~BitmapTransporter(); + + + // XInterface + virtual ANY SAL_CALL queryInterface( const Type & rType ) throw( RuntimeException ); + virtual void SAL_CALL acquire() throw() { OWeakObject::acquire(); } + virtual void SAL_CALL release() throw() { OWeakObject::release(); } + + virtual AWT::Size SAL_CALL getSize() throw(); + virtual SEQ( sal_Int8 ) SAL_CALL getDIB() throw(); + virtual SEQ( sal_Int8 ) SAL_CALL getMaskDIB() throw() { return SEQ( sal_Int8 )(); } + + // Misc + void lock() { m_aProtector.acquire(); } + void unlock() { m_aProtector.release(); } + SvMemoryStream& getStream() { return m_aStream; } +}; + +// -------- +// - Sane - +// -------- + +class Sane +{ +private: + static int nRefCount; + static oslModule pSaneLib; + + static SANE_Status (*p_init)( SANE_Int*, + SANE_Auth_Callback ); + static void (*p_exit)(); + static SANE_Status (*p_get_devices)( const SANE_Device***, + SANE_Bool ); + static SANE_Status (*p_open)( SANE_String_Const, SANE_Handle ); + static void (*p_close)( SANE_Handle ); + static const SANE_Option_Descriptor* (*p_get_option_descriptor)( + SANE_Handle, SANE_Int ); + static SANE_Status (*p_control_option)( SANE_Handle, SANE_Int, + SANE_Action, void*, + SANE_Int* ); + static SANE_Status (*p_get_parameters)( SANE_Handle, + SANE_Parameters* ); + static SANE_Status (*p_start)( SANE_Handle ); + static SANE_Status (*p_read)( SANE_Handle, SANE_Byte*, SANE_Int, + SANE_Int* ); + static void (*p_cancel)( SANE_Handle ); + static SANE_Status (*p_set_io_mode)( SANE_Handle, SANE_Bool ); + static SANE_Status (*p_get_select_fd)( SANE_Handle, SANE_Int* ); + static SANE_String_Const (*p_strstatus)( SANE_Status ); + + static SANE_Int nVersion; + static SANE_Device** ppDevices; + static int nDevices; + + const SANE_Option_Descriptor** mppOptions; + int mnOptions; + int mnDevice; + SANE_Handle maHandle; + + Link maReloadOptionsLink; + + inline oslGenericFunction + LoadSymbol( const char* ); + void Init(); + void DeInit(); + + SANE_Status ControlOption( int, SANE_Action, void* ); + + BOOL CheckConsistency( const char*, BOOL bInit = FALSE ); + +public: + Sane(); + ~Sane(); + + static BOOL IsSane() + { return pSaneLib ? TRUE : FALSE; } + BOOL IsOpen() + { return maHandle ? TRUE : FALSE; } + static int CountDevices() + { return nDevices; } + static String GetName( int n ) + { return String( ppDevices[n]->name ? ppDevices[n]->name : "", osl_getThreadTextEncoding() ); } + static String GetVendor( int n ) + { return String( ppDevices[n]->vendor ? ppDevices[n]->vendor : "", osl_getThreadTextEncoding() ); } + static String GetModel( int n ) + { return String( ppDevices[n]->model ? ppDevices[n]->model : "", osl_getThreadTextEncoding() ); } + static String GetType( int n ) + { return String( ppDevices[n]->type ? ppDevices[n]->type : "", osl_getThreadTextEncoding() ); } + + String GetOptionName( int n ) + { return String( mppOptions[n]->name ? (char*)mppOptions[n]->name : "", osl_getThreadTextEncoding() ); } + String GetOptionTitle( int n ) + { return String( mppOptions[n]->title ? (char*)mppOptions[n]->title : "", osl_getThreadTextEncoding() ); } + SANE_Value_Type GetOptionType( int n ) + { return mppOptions[n]->type; } + SANE_Unit GetOptionUnit( int n ) + { return mppOptions[n]->unit; } + String GetOptionUnitName( int n ); + SANE_Int GetOptionCap( int n ) + { return mppOptions[n]->cap; } + SANE_Constraint_Type GetOptionConstraintType( int n ) + { return mppOptions[n]->constraint_type; } + const char** GetStringConstraint( int n ) + { return (const char**)mppOptions[n]->constraint.string_list; } + int GetRange( int, double*& ); + + inline int GetOptionElements( int n ); + int GetOptionByName( const char* ); + BOOL GetOptionValue( int, BOOL& ); + BOOL GetOptionValue( int, ByteString& ); + BOOL GetOptionValue( int, double&, int nElement = 0 ); + BOOL GetOptionValue( int, double* ); + + BOOL SetOptionValue( int, BOOL ); + BOOL SetOptionValue( int, const String& ); + BOOL SetOptionValue( int, double, int nElement = 0 ); + BOOL SetOptionValue( int, double* ); + + BOOL ActivateButtonOption( int ); + + int CountOptions() { return mnOptions; } + int GetDeviceNumber() { return mnDevice; } + + BOOL Open( const char* ); + BOOL Open( int ); + void Close(); + void ReloadDevices(); + void ReloadOptions(); + + BOOL Start( BitmapTransporter& ); + + inline Link SetReloadOptionsHdl( const Link& rLink ); +}; + +inline int Sane::GetOptionElements( int n ) +{ + if( mppOptions[n]->type == SANE_TYPE_FIXED || + mppOptions[n]->type == SANE_TYPE_INT ) + { + return mppOptions[n]->size/sizeof( SANE_Word ); + } + return 1; +} + +inline Link Sane::SetReloadOptionsHdl( const Link& rLink ) +{ + Link aRet = maReloadOptionsLink; + maReloadOptionsLink = rLink; + return aRet; +} + +#endif diff --git a/extensions/source/scanner/sanedlg.cxx b/extensions/source/scanner/sanedlg.cxx new file mode 100644 index 000000000000..2889257a1f1c --- /dev/null +++ b/extensions/source/scanner/sanedlg.cxx @@ -0,0 +1,1430 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" + +#include <stdio.h> +#include <stdlib.h> +#include <tools/config.hxx> + +#include <vcl/msgbox.hxx> +#include <sanedlg.hxx> +#include <sanedlg.hrc> +#include <grid.hxx> +#include <math.h> + +#define USE_SAVE_STATE +#undef SAVE_ALL_STATES + +ResId SaneResId( sal_uInt32 nID ) +{ + static ResMgr* pResMgr = ResMgr::CreateResMgr( "san" ); + return ResId( nID, *pResMgr ); +} + +SaneDlg::SaneDlg( Window* pParent, Sane& rSane ) : + ModalDialog( pParent, SaneResId( RID_SANE_DIALOG ) ), + mrSane( rSane ), + mbIsDragging( FALSE ), + mbDragDrawn( FALSE ), + maMapMode( MAP_APPFONT ), + maOKButton( this, SaneResId( RID_SCAN_OK ) ), + maCancelButton( this, SaneResId( RID_SCAN_CANCEL ) ), + maDeviceInfoButton( this, SaneResId( RID_DEVICEINFO_BTN ) ), + maPreviewButton( this, SaneResId( RID_PREVIEW_BTN ) ), + maButtonOption( this, SaneResId( RID_SCAN_BUTTON_OPTION_BTN ) ), + maOptionsTxt( this, SaneResId( RID_SCAN_OPTION_TXT ) ), + maOptionTitle( this, SaneResId( RID_SCAN_OPTIONTITLE_TXT ) ), + maOptionDescTxt( this, SaneResId( RID_SCAN_OPTION_DESC_TXT ) ), + maVectorTxt( this, SaneResId( RID_SCAN_NUMERIC_VECTOR_TXT ) ), + maScanLeftTxt( this, SaneResId( RID_SCAN_LEFT_TXT ) ), + maLeftField( this, SaneResId( RID_SCAN_LEFT_BOX ) ), + maScanTopTxt( this, SaneResId( RID_SCAN_TOP_TXT ) ), + maTopField( this, SaneResId( RID_SCAN_TOP_BOX ) ), + maRightTxt( this, SaneResId( RID_SCAN_RIGHT_TXT ) ), + maRightField( this, SaneResId( RID_SCAN_RIGHT_BOX ) ), + maBottomTxt( this, SaneResId( RID_SCAN_BOTTOM_TXT ) ), + maBottomField( this, SaneResId( RID_SCAN_BOTTOM_BOX ) ), + maDeviceBoxTxt( this, SaneResId( RID_DEVICE_BOX_TXT ) ), + maDeviceBox( this, SaneResId( RID_DEVICE_BOX ) ), + maReslTxt( this, SaneResId( RID_SCAN_RESOLUTION_TXT ) ), + maReslBox( this, SaneResId( RID_SCAN_RESOLUTION_BOX ) ), + maAdvancedTxt( this, SaneResId( RID_SCAN_ADVANCED_TXT ) ), + maAdvancedBox( this, SaneResId( RID_SCAN_ADVANCED_BOX ) ), + maVectorBox( this, SaneResId( RID_SCAN_NUMERIC_VECTOR_BOX ) ), + maQuantumRangeBox( this, SaneResId( RID_SCAN_QUANTUM_RANGE_BOX ) ), + maStringRangeBox( this, SaneResId( RID_SCAN_STRING_RANGE_BOX ) ), + maPreviewBox( this, SaneResId( RID_PREVIEW_BOX ) ), + maAreaBox( this, SaneResId( RID_SCANAREA_BOX ) ), + maBoolCheckBox( this, SaneResId( RID_SCAN_BOOL_OPTION_BOX ) ), + maStringEdit( this, SaneResId( RID_SCAN_STRING_OPTION_EDT ) ), + maNumericEdit( this, SaneResId( RID_SCAN_NUMERIC_OPTION_EDT ) ), + maOptionBox( this, SaneResId( RID_SCAN_OPTION_BOX ) ), + mpRange( 0 ) +{ + if( Sane::IsSane() ) + { + InitDevices(); // opens first sane device + DisableOption(); + InitFields(); + } + + maDeviceInfoButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) ); + maPreviewButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) ); + maButtonOption.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) ); + maDeviceBox.SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) ); + maOptionBox.SetSelectHdl( LINK( this, SaneDlg, OptionsBoxSelectHdl ) ); + maOKButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) ); + maCancelButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) ); + maBoolCheckBox.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) ); + maStringEdit.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maNumericEdit.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maVectorBox.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maReslBox.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maStringRangeBox.SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) ); + maQuantumRangeBox.SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) ); + maLeftField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maRightField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maTopField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maBottomField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) ); + maAdvancedBox.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) ); + + maOldLink = mrSane.SetReloadOptionsHdl( LINK( this, SaneDlg, ReloadSaneOptionsHdl ) ); + + maOptionBox.SetNodeBitmaps( + Bitmap( SaneResId( RID_SCAN_BITMAP_PLUS ) ), + Bitmap( SaneResId( RID_SCAN_BITMAP_MINUS ) ) + ); + maOptionBox.SetWindowBits( WB_HASLINES | + WB_HASBUTTONS | + WB_NOINITIALSELECTION | + WB_HASBUTTONSATROOT | + WB_HASLINESATROOT + ); + FreeResource(); +} + +SaneDlg::~SaneDlg() +{ +} + +short SaneDlg::Execute() +{ + if( ! Sane::IsSane() ) + { + ErrorBox aErrorBox( NULL, WB_OK | WB_DEF_OK, + String( SaneResId( RID_SANE_NOSANELIB_TXT ) ) ); + aErrorBox.Execute(); + return FALSE; + } + LoadState(); + return ModalDialog::Execute(); +} + +void SaneDlg::InitDevices() +{ + if( ! Sane::IsSane() ) + return; + + if( mrSane.IsOpen() ) + mrSane.Close(); + mrSane.ReloadDevices(); + maDeviceBox.Clear(); + for( int i = 0; i < Sane::CountDevices(); i++ ) + maDeviceBox.InsertEntry( Sane::GetName( i ) ); + if( Sane::CountDevices() ) + { + mrSane.Open( 0 ); + maDeviceBox.SelectEntry( Sane::GetName( 0 ) ); + + } +} + +void SaneDlg::InitFields() +{ + if( ! Sane::IsSane() ) + return; + + int nOption, i, nValue; + double fValue; + BOOL bSuccess = FALSE; + const char *ppSpecialOptions[] = { + "resolution", + "tl-x", + "tl-y", + "br-x", + "br-y", + "preview" + }; + + mbDragEnable = TRUE; + maReslBox.Clear(); + maMinTopLeft = Point( 0, 0 ); + maMaxBottomRight = Point( PREVIEW_WIDTH, PREVIEW_HEIGHT ); + + if( ! mrSane.IsOpen() ) + return; + + // set Resolution + nOption = mrSane.GetOptionByName( "resolution" ); + if( nOption != -1 ) + { + double fRes; + + bSuccess = mrSane.GetOptionValue( nOption, fRes ); + if( bSuccess ) + { + maReslBox.Enable( TRUE ); + + maReslBox.SetValue( (long)fRes ); + double *pDouble = NULL; + nValue = mrSane.GetRange( nOption, pDouble ); + if( nValue > -1 ) + { + if( nValue ) + { + maReslBox.SetMin( (long)pDouble[0] ); + maReslBox.SetMax( (long)pDouble[ nValue-1 ] ); + for( i=0; i<nValue; i++ ) + { + if( i == 0 || i == nValue-1 || ! ( ((int)pDouble[i]) % 20) ) + maReslBox.InsertValue( (long)pDouble[i] ); + } + } + else + { + maReslBox.SetMin( (long)pDouble[0] ); + maReslBox.SetMax( (long)pDouble[1] ); + maReslBox.InsertValue( (long)pDouble[0] ); + // mh@openoffice.org: issue 68557: Can only select 75 and 2400 dpi in Scanner dialogue + // scanner allows random setting of dpi resolution, a slider might be useful + // support that + // workaround: offer at least some more standard dpi resolution between + // min and max value + int bGot300 = 0; + for ( int nRes = (long) pDouble[0] * 2; nRes < (long) pDouble[1]; nRes = nRes * 2 ) + { + if ( !bGot300 && nRes > 300 ) { + nRes = 300; bGot300 = 1; + } + maReslBox.InsertValue(nRes); + } + maReslBox.InsertValue( (long)pDouble[1] ); + } + if( pDouble ) + delete [] pDouble; + } + else + maReslBox.Enable( FALSE ); + } + } + else + maReslBox.Enable( FALSE ); + + // set scan area + for( i = 0; i < 4; i++ ) + { + char const *pOptionName = NULL; + MetricField* pField = NULL; + switch( i ) + { + case 0: + pOptionName = "tl-x"; + pField = &maLeftField; + break; + case 1: + pOptionName = "tl-y"; + pField = &maTopField; + break; + case 2: + pOptionName = "br-x"; + pField = &maRightField; + break; + case 3: + pOptionName = "br-y"; + pField = &maBottomField; + } + nOption = pOptionName ? mrSane.GetOptionByName( pOptionName ) : -1; + bSuccess = FALSE; + if( nOption != -1 ) + { + bSuccess = mrSane.GetOptionValue( nOption, fValue, 0 ); + if( bSuccess ) + { + if( mrSane.GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + pField->SetUnit( FUNIT_MM ); + pField->SetValue( (int)fValue, FUNIT_MM ); + } + else // SANE_UNIT_PIXEL + { + pField->SetValue( (int)fValue, FUNIT_CUSTOM ); + pField->SetCustomUnitText( String::CreateFromAscii( "Pixel" ) ); + } + switch( i ) { + case 0: maTopLeft.X() = (int)fValue;break; + case 1: maTopLeft.Y() = (int)fValue;break; + case 2: maBottomRight.X() = (int)fValue;break; + case 3: maBottomRight.Y() = (int)fValue;break; + } + } + double *pDouble = NULL; + nValue = mrSane.GetRange( nOption, pDouble ); + if( nValue > -1 ) + { + if( pDouble ) + { + pField->SetMin( (long)pDouble[0] ); + if( nValue ) + pField->SetMax( (long)pDouble[ nValue-1 ] ); + else + pField->SetMax( (long)pDouble[ 1 ] ); + delete [] pDouble; + } + switch( i ) { + case 0: maMinTopLeft.X() = pField->GetMin();break; + case 1: maMinTopLeft.Y() = pField->GetMin();break; + case 2: maMaxBottomRight.X() = pField->GetMax();break; + case 3: maMaxBottomRight.Y() = pField->GetMax();break; + } + } + else + { + switch( i ) { + case 0: maMinTopLeft.X() = (int)fValue;break; + case 1: maMinTopLeft.Y() = (int)fValue;break; + case 2: maMaxBottomRight.X() = (int)fValue;break; + case 3: maMaxBottomRight.Y() = (int)fValue;break; + } + } + pField->Enable( TRUE ); + } + else + { + mbDragEnable = FALSE; + pField->SetMin( 0 ); + switch( i ) { + case 0: + maMinTopLeft.X() = 0; + maTopLeft.X() = 0; + pField->SetMax( PREVIEW_WIDTH ); + pField->SetValue( 0 ); + break; + case 1: + maMinTopLeft.Y() = 0; + maTopLeft.Y() = 0; + pField->SetMax( PREVIEW_HEIGHT ); + pField->SetValue( 0 ); + break; + case 2: + maMaxBottomRight.X() = PREVIEW_WIDTH; + maBottomRight.X() = PREVIEW_WIDTH; + pField->SetMax( PREVIEW_WIDTH ); + pField->SetValue( PREVIEW_WIDTH ); + break; + case 3: + maMaxBottomRight.Y() = PREVIEW_HEIGHT; + maBottomRight.Y() = PREVIEW_HEIGHT; + pField->SetMax( PREVIEW_HEIGHT ); + pField->SetValue( PREVIEW_HEIGHT ); + break; + } + pField->Enable( FALSE ); + } + } + maTopLeft = GetPixelPos( maTopLeft ); + maBottomRight = GetPixelPos( maBottomRight ); + maPreviewRect = Rectangle( maTopLeft, + Size( maBottomRight.X() - maTopLeft.X(), + maBottomRight.Y() - maTopLeft.Y() ) + ); + // fill OptionBox + maOptionBox.Clear(); + SvLBoxEntry* pParentEntry = 0; + BOOL bGroupRejected = FALSE; + for( i = 1; i < mrSane.CountOptions(); i++ ) + { + String aOption=mrSane.GetOptionName( i ); + BOOL bInsertAdvanced = + mrSane.GetOptionCap( i ) & SANE_CAP_ADVANCED && + ! maAdvancedBox.IsChecked() ? FALSE : TRUE; + if( mrSane.GetOptionType( i ) == SANE_TYPE_GROUP ) + { + if( bInsertAdvanced ) + { + aOption = mrSane.GetOptionTitle( i ); + pParentEntry = maOptionBox.InsertEntry( aOption ); + bGroupRejected = FALSE; + } + else + bGroupRejected = TRUE; + } + else if( aOption.Len() && + ! ( mrSane.GetOptionCap( i ) & + ( + SANE_CAP_HARD_SELECT | + SANE_CAP_INACTIVE + ) ) && + bInsertAdvanced && ! bGroupRejected ) + { + BOOL bIsSpecial = FALSE; + for( size_t n = 0; !bIsSpecial && + n < sizeof(ppSpecialOptions)/sizeof(ppSpecialOptions[0]); n++ ) + { + if( aOption.EqualsAscii( ppSpecialOptions[n] ) ) + bIsSpecial=TRUE; + } + if( ! bIsSpecial ) + { + if( pParentEntry ) + maOptionBox.InsertEntry( aOption, pParentEntry ); + else + maOptionBox.InsertEntry( aOption ); + } + } + } +} + +IMPL_LINK( SaneDlg, ClickBtnHdl, Button*, pButton ) +{ + if( mrSane.IsOpen() ) + { + if( pButton == &maDeviceInfoButton ) + { + String aString( SaneResId( RID_SANE_DEVICEINFO_TXT ) ); + String aSR( RTL_CONSTASCII_USTRINGPARAM( "%s" ) ); + aString.SearchAndReplace( aSR, Sane::GetName( mrSane.GetDeviceNumber() ) ); + aString.SearchAndReplace( aSR, Sane::GetVendor( mrSane.GetDeviceNumber() ) ); + aString.SearchAndReplace( aSR, Sane::GetModel( mrSane.GetDeviceNumber() ) ); + aString.SearchAndReplace( aSR, Sane::GetType( mrSane.GetDeviceNumber() ) ); + InfoBox aInfoBox( this, aString ); + aInfoBox.Execute(); + } + else if( pButton == &maPreviewButton ) + AcquirePreview(); + else if( pButton == &maBoolCheckBox ) + { + mrSane.SetOptionValue( mnCurrentOption, + maBoolCheckBox.IsChecked() ? + (BOOL)TRUE : (BOOL)FALSE ); + } + else if( pButton == &maButtonOption ) + { + + SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption ); + switch( nType ) + { + case SANE_TYPE_BUTTON: + mrSane.ActivateButtonOption( mnCurrentOption ); + break; + case SANE_TYPE_FIXED: + case SANE_TYPE_INT: + { + int nElements = mrSane.GetOptionElements( mnCurrentOption ); + double* x = new double[ nElements ]; + double* y = new double[ nElements ]; + for( int i = 0; i < nElements; i++ ) + x[ i ] = (double)i; + mrSane.GetOptionValue( mnCurrentOption, y ); + + GridWindow aGrid( x, y, nElements, this ); + aGrid.SetText( mrSane.GetOptionName( mnCurrentOption ) ); + aGrid.setBoundings( 0, mfMin, nElements, mfMax ); + if( aGrid.Execute() && aGrid.getNewYValues() ) + mrSane.SetOptionValue( mnCurrentOption, aGrid.getNewYValues() ); + + delete [] x; + delete [] y; + } + break; + case SANE_TYPE_BOOL: + case SANE_TYPE_STRING: + case SANE_TYPE_GROUP: + break; + } + } + else if( pButton == &maAdvancedBox ) + { + ReloadSaneOptionsHdl( NULL ); + } + } + if( pButton == &maOKButton ) + { + double fRes = (double)maReslBox.GetValue(); + SetAdjustedNumericalValue( "resolution", fRes ); + mrSane.SetReloadOptionsHdl( maOldLink ); + UpdateScanArea( TRUE ); + SaveState(); + EndDialog( mrSane.IsOpen() ? 1 : 0 ); + } + else if( pButton == &maCancelButton ) + { + mrSane.SetReloadOptionsHdl( maOldLink ); + mrSane.Close(); + EndDialog( 0 ); + } + return 0; +} + +IMPL_LINK( SaneDlg, SelectHdl, ListBox*, pListBox ) +{ + if( pListBox == &maDeviceBox && Sane::IsSane() && Sane::CountDevices() ) + { + String aNewDevice = maDeviceBox.GetSelectEntry(); + int nNumber; + if( aNewDevice.Equals( Sane::GetName( nNumber = mrSane.GetDeviceNumber() ) ) ) + { + mrSane.Close(); + mrSane.Open( nNumber ); + InitFields(); + } + } + if( mrSane.IsOpen() ) + { + if( pListBox == &maQuantumRangeBox ) + { + ByteString aValue( maQuantumRangeBox.GetSelectEntry(), osl_getThreadTextEncoding() ); + double fValue = atof( aValue.GetBuffer() ); + mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement ); + } + else if( pListBox == &maStringRangeBox ) + { + mrSane.SetOptionValue( mnCurrentOption, maStringRangeBox.GetSelectEntry() ); + } + } + return 0; +} + +IMPL_LINK( SaneDlg, OptionsBoxSelectHdl, SvTreeListBox*, pBox ) +{ + if( pBox == &maOptionBox && Sane::IsSane() ) + { + String aOption = + maOptionBox.GetEntryText( maOptionBox.FirstSelected() ); + int nOption = mrSane.GetOptionByName( ByteString( aOption, osl_getThreadTextEncoding() ).GetBuffer() ); + if( nOption != -1 && nOption != mnCurrentOption ) + { + DisableOption(); + mnCurrentOption = nOption; + maOptionTitle.SetText( mrSane.GetOptionTitle( mnCurrentOption ) ); + SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption ); + SANE_Constraint_Type nConstraint; + switch( nType ) + { + case SANE_TYPE_BOOL: EstablishBoolOption();break; + case SANE_TYPE_STRING: + nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption ); + if( nConstraint == SANE_CONSTRAINT_STRING_LIST ) + EstablishStringRange(); + else + EstablishStringOption(); + break; + case SANE_TYPE_FIXED: + case SANE_TYPE_INT: + { + nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption ); + int nElements = mrSane.GetOptionElements( mnCurrentOption ); + mnCurrentElement = 0; + if( nConstraint == SANE_CONSTRAINT_RANGE || + nConstraint == SANE_CONSTRAINT_WORD_LIST ) + EstablishQuantumRange(); + else + { + mfMin = mfMax = 0.0; + EstablishNumericOption(); + } + if( nElements > 1 ) + { + if( nElements <= 10 ) + { + maVectorBox.SetValue( 1 ); + maVectorBox.SetMin( 1 ); + maVectorBox.SetMax( + mrSane.GetOptionElements( mnCurrentOption ) ); + maVectorBox.Show( TRUE ); + maVectorTxt.Show( TRUE ); + } + else + { + DisableOption(); + // bring up dialog only on button click + EstablishButtonOption(); + } + } + } + break; + case SANE_TYPE_BUTTON: + EstablishButtonOption(); + break; + default: break; + } + } + } + return 0; +} + +IMPL_LINK( SaneDlg, ModifyHdl, Edit*, pEdit ) +{ + if( mrSane.IsOpen() ) + { + if( pEdit == &maStringEdit ) + { + mrSane.SetOptionValue( mnCurrentOption, maStringEdit.GetText() ); + } + else if( pEdit == &maReslBox ) + { + double fRes = (double)maReslBox.GetValue(); + int nOption = mrSane.GetOptionByName( "resolution" ); + if( nOption != -1 ) + { + double* pDouble = NULL; + int nValues = mrSane.GetRange( nOption, pDouble ); + if( nValues > 0 ) + { + int i; + for( i = 0; i < nValues; i++ ) + { + if( fRes == pDouble[i] ) + break; + } + if( i >= nValues ) + fRes = pDouble[0]; + } + else if( nValues == 0 ) + { + if( fRes < pDouble[ 0 ] ) + fRes = pDouble[ 0 ]; + if( fRes > pDouble[ 1 ] ) + fRes = pDouble[ 1 ]; + } + maReslBox.SetValue( (ULONG)fRes ); + } + } + else if( pEdit == &maNumericEdit ) + { + double fValue; + char pBuf[256]; + ByteString aContents( maNumericEdit.GetText(), osl_getThreadTextEncoding() ); + fValue = atof( aContents.GetBuffer() ); + if( mfMin != mfMax && ( fValue < mfMin || fValue > mfMax ) ) + { + if( fValue < mfMin ) + fValue = mfMin; + else if( fValue > mfMax ) + fValue = mfMax; + sprintf( pBuf, "%g", fValue ); + maNumericEdit.SetText( String( pBuf, osl_getThreadTextEncoding() ) ); + } + mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement ); + } + else if( pEdit == &maVectorBox ) + { + char pBuf[256]; + mnCurrentElement = maVectorBox.GetValue()-1; + double fValue; + mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement ); + sprintf( pBuf, "%g", fValue ); + String aValue( pBuf, osl_getThreadTextEncoding() ); + maNumericEdit.SetText( aValue ); + maQuantumRangeBox.SelectEntry( aValue ); + } + else if( pEdit == &maTopField ) + { + Point aPoint( 0, maTopField.GetValue() ); + aPoint = GetPixelPos( aPoint ); + maTopLeft.Y() = aPoint.Y(); + DrawDrag(); + } + else if( pEdit == &maLeftField ) + { + Point aPoint( maLeftField.GetValue(), 0 ); + aPoint = GetPixelPos( aPoint ); + maTopLeft.X() = aPoint.X(); + DrawDrag(); + } + else if( pEdit == &maBottomField ) + { + Point aPoint( 0, maBottomField.GetValue() ); + aPoint = GetPixelPos( aPoint ); + maBottomRight.Y() = aPoint.Y(); + DrawDrag(); + } + else if( pEdit == &maRightField ) + { + Point aPoint( maRightField.GetValue(), 0 ); + aPoint = GetPixelPos( aPoint ); + maBottomRight.X() = aPoint.X(); + DrawDrag(); + } + } + return 0; +} + +IMPL_LINK( SaneDlg, ReloadSaneOptionsHdl, Sane*, /*pSane*/ ) +{ + mnCurrentOption = -1; + mnCurrentElement = 0; + DisableOption(); + // #92024# preserve preview rect, should only be set + // initially or in AcquirePreview + Rectangle aPreviewRect = maPreviewRect; + InitFields(); + maPreviewRect = aPreviewRect; + Rectangle aDummyRect( Point( 0, 0 ), GetSizePixel() ); + Paint( aDummyRect ); + return 0; +} + +void SaneDlg::AcquirePreview() +{ + if( ! mrSane.IsOpen() ) + return; + + UpdateScanArea( TRUE ); + // set small resolution for preview + double fResl = (double)maReslBox.GetValue(); + SetAdjustedNumericalValue( "resolution", 30.0 ); + + int nOption = mrSane.GetOptionByName( "preview" ); + if( nOption == -1 ) + { + String aString( SaneResId( RID_SANE_NORESOLUTIONOPTION_TXT ) ); + WarningBox aBox( this, WB_OK_CANCEL | WB_DEF_OK, aString ); + if( aBox.Execute() == RET_CANCEL ) + return; + } + else + mrSane.SetOptionValue( nOption, (BOOL)TRUE ); + + BitmapTransporter aTransporter; + if( ! mrSane.Start( aTransporter ) ) + { + ErrorBox aErrorBox( this, WB_OK | WB_DEF_OK, + String( SaneResId( RID_SANE_SCANERROR_TXT ) ) ); + aErrorBox.Execute(); + } + else + { +#if OSL_DEBUG_LEVEL > 1 + aTransporter.getStream().Seek( STREAM_SEEK_TO_END ); + fprintf( stderr, "Previewbitmapstream contains %d bytes\n", (int)aTransporter.getStream().Tell() ); +#endif + aTransporter.getStream().Seek( STREAM_SEEK_TO_BEGIN ); + maPreviewBitmap.Read( aTransporter.getStream(), TRUE ); + } + + SetAdjustedNumericalValue( "resolution", fResl ); + maReslBox.SetValue( (ULONG)fResl ); + + if( mbDragEnable ) + maPreviewRect = Rectangle( maTopLeft, + Size( maBottomRight.X() - maTopLeft.X(), + maBottomRight.Y() - maTopLeft.Y() ) + ); + else + { + Size aBMSize( maPreviewBitmap.GetSizePixel() ); + if( aBMSize.Width() > aBMSize.Height() ) + { + int nVHeight = (maBottomRight.X() - maTopLeft.X()) * aBMSize.Height() / aBMSize.Width(); + maPreviewRect = Rectangle( Point( maTopLeft.X(), ( maTopLeft.Y() + maBottomRight.Y() )/2 - nVHeight/2 ), + Size( maBottomRight.X() - maTopLeft.X(), + nVHeight ) ); + } + else + { + int nVWidth = (maBottomRight.Y() - maTopLeft.Y()) * aBMSize.Width() / aBMSize.Height(); + maPreviewRect = Rectangle( Point( ( maTopLeft.X() + maBottomRight.X() )/2 - nVWidth/2, maTopLeft.Y() ), + Size( nVWidth, + maBottomRight.Y() - maTopLeft.Y() ) ); + } + } + + Paint( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); +} + +void SaneDlg::Paint( const Rectangle& rRect ) +{ + SetMapMode( maMapMode ); + SetFillColor( Color( COL_WHITE ) ); + SetLineColor( Color( COL_WHITE ) ); + DrawRect( Rectangle( Point( PREVIEW_UPPER_LEFT, PREVIEW_UPPER_TOP ), + Size( PREVIEW_WIDTH, PREVIEW_HEIGHT ) ) ); + SetMapMode( MapMode( MAP_PIXEL ) ); + // check for sane values + DrawBitmap( maPreviewRect.TopLeft(), maPreviewRect.GetSize(), + maPreviewBitmap ); + + mbDragDrawn = FALSE; + DrawDrag(); + + ModalDialog::Paint( rRect ); +} + +void SaneDlg::DisableOption() +{ + maBoolCheckBox.Show( FALSE ); + maStringEdit.Show( FALSE ); + maNumericEdit.Show( FALSE ); + maQuantumRangeBox.Show( FALSE ); + maStringRangeBox.Show( FALSE ); + maButtonOption.Show( FALSE ); + maVectorBox.Show( FALSE ); + maVectorTxt.Show( FALSE ); + maOptionDescTxt.Show( FALSE ); +} + +void SaneDlg::EstablishBoolOption() +{ + BOOL bSuccess, bValue; + + bSuccess = mrSane.GetOptionValue( mnCurrentOption, bValue ); + if( bSuccess ) + { + maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) ); + maOptionDescTxt.Show( TRUE ); + maBoolCheckBox.Check( bValue ); + maBoolCheckBox.Show( TRUE ); + } +} + +void SaneDlg::EstablishStringOption() +{ + BOOL bSuccess; + ByteString aValue; + + bSuccess = mrSane.GetOptionValue( mnCurrentOption, aValue ); + if( bSuccess ) + { + maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) ); + maOptionDescTxt.Show( TRUE ); + maStringEdit.SetText( String( aValue, osl_getThreadTextEncoding() ) ); + maStringEdit.Show( TRUE ); + } +} + +void SaneDlg::EstablishStringRange() +{ + const char** ppStrings = mrSane.GetStringConstraint( mnCurrentOption ); + maStringRangeBox.Clear(); + for( int i = 0; ppStrings[i] != 0; i++ ) + maStringRangeBox.InsertEntry( String( ppStrings[i], osl_getThreadTextEncoding() ) ); + ByteString aValue; + mrSane.GetOptionValue( mnCurrentOption, aValue ); + maStringRangeBox.SelectEntry( String( aValue, osl_getThreadTextEncoding() ) ); + maStringRangeBox.Show( TRUE ); + maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) ); + maOptionDescTxt.Show( TRUE ); +} + +void SaneDlg::EstablishQuantumRange() +{ + if( mpRange ) + { + delete [] mpRange; + mpRange = 0; + } + int nValues = mrSane.GetRange( mnCurrentOption, mpRange ); + if( nValues == 0 ) + { + mfMin = mpRange[ 0 ]; + mfMax = mpRange[ 1 ]; + delete [] mpRange; + mpRange = 0; + EstablishNumericOption(); + } + else if( nValues > 0 ) + { + char pBuf[ 256 ]; + maQuantumRangeBox.Clear(); + mfMin = mpRange[ 0 ]; + mfMax = mpRange[ nValues-1 ]; + for( int i = 0; i < nValues; i++ ) + { + sprintf( pBuf, "%g", mpRange[ i ] ); + maQuantumRangeBox.InsertEntry( String( pBuf, osl_getThreadTextEncoding() ) ); + } + double fValue; + if( mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement ) ) + { + sprintf( pBuf, "%g", fValue ); + maQuantumRangeBox.SelectEntry( String( pBuf, osl_getThreadTextEncoding() ) ); + } + maQuantumRangeBox.Show( TRUE ); + String aText( mrSane.GetOptionName( mnCurrentOption ) ); + aText += ' '; + aText += mrSane.GetOptionUnitName( mnCurrentOption ); + maOptionDescTxt.SetText( aText ); + maOptionDescTxt.Show( TRUE ); + } +} + +void SaneDlg::EstablishNumericOption() +{ + BOOL bSuccess; + double fValue; + + bSuccess = mrSane.GetOptionValue( mnCurrentOption, fValue ); + if( ! bSuccess ) + return; + + char pBuf[256]; + String aText( mrSane.GetOptionName( mnCurrentOption ) ); + aText += ' '; + aText += mrSane.GetOptionUnitName( mnCurrentOption ); + if( mfMin != mfMax ) + { + sprintf( pBuf, " < %g ; %g >", mfMin, mfMax ); + aText += String( pBuf, osl_getThreadTextEncoding() ); + } + maOptionDescTxt.SetText( aText ); + maOptionDescTxt.Show( TRUE ); + sprintf( pBuf, "%g", fValue ); + maNumericEdit.SetText( String( pBuf, osl_getThreadTextEncoding() ) ); + maNumericEdit.Show( TRUE ); +} + +void SaneDlg::EstablishButtonOption() +{ + maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) ); + maOptionDescTxt.Show( TRUE ); + maButtonOption.Show( TRUE ); +} + +#define RECT_SIZE_PIX 7 + +void SaneDlg::MouseMove( const MouseEvent& rMEvt ) +{ + if( mbIsDragging ) + { + Point aMousePos = rMEvt.GetPosPixel(); + // move into valid area + Point aLogicPos = GetLogicPos( aMousePos ); + aMousePos = GetPixelPos( aLogicPos ); + switch( meDragDirection ) + { + case TopLeft: maTopLeft = aMousePos; break; + case Top: maTopLeft.Y() = aMousePos.Y(); break; + case TopRight: + maTopLeft.Y() = aMousePos.Y(); + maBottomRight.X() = aMousePos.X(); + break; + case Right: maBottomRight.X() = aMousePos.X(); break; + case BottomRight: maBottomRight = aMousePos; break; + case Bottom: maBottomRight.Y() = aMousePos.Y(); break; + case BottomLeft: + maTopLeft.X() = aMousePos.X(); + maBottomRight.Y() = aMousePos.Y(); + break; + case Left: maTopLeft.X() = aMousePos.X(); break; + default: break; + } + int nSwap; + if( maTopLeft.X() > maBottomRight.X() ) + { + nSwap = maTopLeft.X(); + maTopLeft.X() = maBottomRight.X(); + maBottomRight.X() = nSwap; + } + if( maTopLeft.Y() > maBottomRight.Y() ) + { + nSwap = maTopLeft.Y(); + maTopLeft.Y() = maBottomRight.Y(); + maBottomRight.Y() = nSwap; + } + DrawDrag(); + UpdateScanArea( FALSE ); + } + ModalDialog::MouseMove( rMEvt ); +} + +void SaneDlg::MouseButtonDown( const MouseEvent& rMEvt ) +{ + Point aMousePixel = rMEvt.GetPosPixel(); + + if( ! mbIsDragging && mbDragEnable ) + { + int nMiddleX = ( maBottomRight.X() - maTopLeft.X() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.X(); + int nMiddleY = ( maBottomRight.Y() - maTopLeft.Y() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.Y(); + if( aMousePixel.Y() >= maTopLeft.Y() && + aMousePixel.Y() < maTopLeft.Y() + RECT_SIZE_PIX ) + { + if( aMousePixel.X() >= maTopLeft.X() && + aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX ) + { + meDragDirection = TopLeft; + aMousePixel = maTopLeft; + mbIsDragging = TRUE; + } + else if( aMousePixel.X() >= nMiddleX && + aMousePixel.X() < nMiddleX + RECT_SIZE_PIX ) + { + meDragDirection = Top; + aMousePixel.Y() = maTopLeft.Y(); + mbIsDragging = TRUE; + } + else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX && + aMousePixel.X() <= maBottomRight.X() ) + { + meDragDirection = TopRight; + aMousePixel = Point( maBottomRight.X(), maTopLeft.Y() ); + mbIsDragging = TRUE; + } + } + else if( aMousePixel.Y() >= nMiddleY && + aMousePixel.Y() < nMiddleY + RECT_SIZE_PIX ) + { + if( aMousePixel.X() >= maTopLeft.X() && + aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX ) + { + meDragDirection = Left; + aMousePixel.X() = maTopLeft.X(); + mbIsDragging = TRUE; + } + else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX && + aMousePixel.X() <= maBottomRight.X() ) + { + meDragDirection = Right; + aMousePixel.X() = maBottomRight.X(); + mbIsDragging = TRUE; + } + } + else if( aMousePixel.Y() <= maBottomRight.Y() && + aMousePixel.Y() > maBottomRight.Y() - RECT_SIZE_PIX ) + { + if( aMousePixel.X() >= maTopLeft.X() && + aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX ) + { + meDragDirection = BottomLeft; + aMousePixel = Point( maTopLeft.X(), maBottomRight.Y() ); + mbIsDragging = TRUE; + } + else if( aMousePixel.X() >= nMiddleX && + aMousePixel.X() < nMiddleX + RECT_SIZE_PIX ) + { + meDragDirection = Bottom; + aMousePixel.Y() = maBottomRight.Y(); + mbIsDragging = TRUE; + } + else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX && + aMousePixel.X() <= maBottomRight.X() ) + { + meDragDirection = BottomRight; + aMousePixel = maBottomRight; + mbIsDragging = TRUE; + } + } + } + if( mbIsDragging ) + { + SetPointerPosPixel( aMousePixel ); + DrawDrag(); + } + ModalDialog::MouseButtonDown( rMEvt ); +} + +void SaneDlg::MouseButtonUp( const MouseEvent& rMEvt ) +{ + if( mbIsDragging ) + { + UpdateScanArea( TRUE ); + } + mbIsDragging = FALSE; + + ModalDialog::MouseButtonUp( rMEvt ); +} + +void SaneDlg::DrawRectangles( Point& rUL, Point& rBR ) +{ + int nMiddleX, nMiddleY; + Point aBL, aUR; + + aUR = Point( rBR.X(), rUL.Y() ); + aBL = Point( rUL.X(), rBR.Y() ); + nMiddleX = ( rBR.X() - rUL.X() ) / 2 + rUL.X(); + nMiddleY = ( rBR.Y() - rUL.Y() ) / 2 + rUL.Y(); + + DrawLine( rUL, aBL ); + DrawLine( aBL, rBR ); + DrawLine( rBR, aUR ); + DrawLine( aUR, rUL ); + DrawRect( Rectangle( rUL, Size( RECT_SIZE_PIX,RECT_SIZE_PIX ) ) ); + DrawRect( Rectangle( aBL, Size( RECT_SIZE_PIX, -RECT_SIZE_PIX ) ) ); + DrawRect( Rectangle( rBR, Size( -RECT_SIZE_PIX, -RECT_SIZE_PIX ) ) ); + DrawRect( Rectangle( aUR, Size( -RECT_SIZE_PIX, RECT_SIZE_PIX ) ) ); + DrawRect( Rectangle( Point( nMiddleX - RECT_SIZE_PIX/2, rUL.Y() ), Size( RECT_SIZE_PIX, RECT_SIZE_PIX ) ) ); + DrawRect( Rectangle( Point( nMiddleX - RECT_SIZE_PIX/2, rBR.Y() ), Size( RECT_SIZE_PIX, -RECT_SIZE_PIX ) ) ); + DrawRect( Rectangle( Point( rUL.X(), nMiddleY - RECT_SIZE_PIX/2 ), Size( RECT_SIZE_PIX, RECT_SIZE_PIX ) ) ); + DrawRect( Rectangle( Point( rBR.X(), nMiddleY - RECT_SIZE_PIX/2 ), Size( -RECT_SIZE_PIX, RECT_SIZE_PIX ) ) ); +} + +void SaneDlg::DrawDrag() +{ + static Point aLastUL, aLastBR; + + if( ! mbDragEnable ) + return; + + RasterOp eROP = GetRasterOp(); + SetRasterOp( ROP_INVERT ); + SetMapMode( MapMode( MAP_PIXEL ) ); + + if( mbDragDrawn ) + DrawRectangles( aLastUL, aLastBR ); + + aLastUL = maTopLeft; + aLastBR = maBottomRight; + DrawRectangles( maTopLeft, maBottomRight ); + + mbDragDrawn = TRUE; + SetRasterOp( eROP ); + SetMapMode( maMapMode ); +} + +Point SaneDlg::GetPixelPos( const Point& rIn ) +{ + Point aConvert( + ( ( rIn.X() * PREVIEW_WIDTH ) / + ( maMaxBottomRight.X() - maMinTopLeft.X() ) ) + + PREVIEW_UPPER_LEFT, + ( ( rIn.Y() * PREVIEW_HEIGHT ) + / ( maMaxBottomRight.Y() - maMinTopLeft.Y() ) ) + + PREVIEW_UPPER_TOP ); + + return LogicToPixel( aConvert, maMapMode ); +} + +Point SaneDlg::GetLogicPos( const Point& rIn ) +{ + Point aConvert = PixelToLogic( rIn, maMapMode ); + aConvert.X() -= PREVIEW_UPPER_LEFT; + aConvert.Y() -= PREVIEW_UPPER_TOP; + if( aConvert.X() < 0 ) + aConvert.X() = 0; + if( aConvert.X() >= PREVIEW_WIDTH ) + aConvert.X() = PREVIEW_WIDTH-1; + if( aConvert.Y() < 0 ) + aConvert.Y() = 0; + if( aConvert.Y() >= PREVIEW_HEIGHT ) + aConvert.Y() = PREVIEW_HEIGHT-1; + + aConvert.X() *= ( maMaxBottomRight.X() - maMinTopLeft.X() ); + aConvert.X() /= PREVIEW_WIDTH; + aConvert.Y() *= ( maMaxBottomRight.Y() - maMinTopLeft.Y() ); + aConvert.Y() /= PREVIEW_HEIGHT; + return aConvert; +} + +void SaneDlg::UpdateScanArea( BOOL bSend ) +{ + if( ! mbDragEnable ) + return; + + Point aUL = GetLogicPos( maTopLeft ); + Point aBR = GetLogicPos( maBottomRight ); + + maLeftField.SetValue( aUL.X() ); + maTopField.SetValue( aUL.Y() ); + maRightField.SetValue( aBR.X() ); + maBottomField.SetValue( aBR.Y() ); + + if( ! bSend ) + return; + + if( mrSane.IsOpen() ) + { + SetAdjustedNumericalValue( "tl-x", (double)aUL.X() ); + SetAdjustedNumericalValue( "tl-y", (double)aUL.Y() ); + SetAdjustedNumericalValue( "br-x", (double)aBR.X() ); + SetAdjustedNumericalValue( "br-y", (double)aBR.Y() ); + } +} + +BOOL SaneDlg::LoadState() +{ +#ifdef USE_SAVE_STATE + int i; + + if( ! Sane::IsSane() ) + return FALSE; + + const char* pEnv = getenv("HOME"); + String aFileName( pEnv ? pEnv : "", osl_getThreadTextEncoding() ); + aFileName += String( RTL_CONSTASCII_USTRINGPARAM( "/.so_sane_state" ) ); + Config aConfig( aFileName ); + if( ! aConfig.HasGroup( "SANE" ) ) + return FALSE; + + aConfig.SetGroup( "SANE" ); + ByteString aString = aConfig.ReadKey( "SO_LastSaneDevice" ); + for( i = 0; i < Sane::CountDevices() && ! aString.Equals( ByteString( Sane::GetName( i ), osl_getThreadTextEncoding() ) ); i++ ) ; + if( i == Sane::CountDevices() ) + return FALSE; + + mrSane.Close(); + mrSane.Open( aString.GetBuffer() ); + + DisableOption(); + InitFields(); + + if( mrSane.IsOpen() ) + { + int iMax = aConfig.GetKeyCount(); + for( i = 0; i < iMax; i++ ) + { + aString = aConfig.GetKeyName( i ); + ByteString aValue = aConfig.ReadKey( i ); + int nOption = mrSane.GetOptionByName( aString.GetBuffer() ); + if( nOption != -1 ) + { + if( aValue.CompareTo( "BOOL=", 5 ) == COMPARE_EQUAL ) + { + aValue.Erase( 0, 5 ); + BOOL aBOOL = (BOOL)aValue.ToInt32(); + mrSane.SetOptionValue( nOption, aBOOL ); + } + else if( aValue.CompareTo( "STRING=", 7 ) == COMPARE_EQUAL ) + { + aValue.Erase( 0, 7 ); + mrSane.SetOptionValue( nOption, String( aValue, osl_getThreadTextEncoding() ) ); + } + else if( aValue.CompareTo( "NUMERIC=", 8 ) == COMPARE_EQUAL ) + { + aValue.Erase( 0, 8 ); + int nMax = aValue.GetTokenCount( ':' ); + double fValue=0.0; + for( int n = 0; n < nMax ; n++ ) + { + ByteString aSub = aValue.GetToken( n, ':' ); + sscanf( aSub.GetBuffer(), "%lg", &fValue ); + SetAdjustedNumericalValue( aString.GetBuffer(), fValue, n ); + } + } + } + } + } + + DisableOption(); + InitFields(); + + return TRUE; +#else + return FALSE; +#endif +} + +void SaneDlg::SaveState() +{ +#ifdef USE_SAVE_STATE + if( ! Sane::IsSane() ) + return; + + const char* pEnv = getenv( "HOME" ); + String aFileName( pEnv ? pEnv : "", osl_getThreadTextEncoding() ); + aFileName.AppendAscii( "/.so_sane_state" ); + + Config aConfig( aFileName ); + aConfig.DeleteGroup( "SANE" ); + aConfig.SetGroup( "SANE" ); + aConfig.WriteKey( "SO_LastSANEDevice", ByteString( maDeviceBox.GetSelectEntry(), RTL_TEXTENCODING_UTF8 ) ); + +#ifdef SAVE_ALL_STATES + for( int i = 1; i < mrSane.CountOptions(); i++ ) + { + String aOption=mrSane.GetOptionName( i ); + SANE_Value_Type nType = mrSane.GetOptionType( i ); + switch( nType ) + { + case SANE_TYPE_BOOL: + { + BOOL bValue; + if( mrSane.GetOptionValue( i, bValue ) ) + { + ByteString aString( "BOOL=" ); + aString += (ULONG)bValue; + aConfig.WriteKey( aOption, aString ); + } + } + break; + case SANE_TYPE_STRING: + { + String aString( "STRING=" ); + String aValue; + if( mrSane.GetOptionValue( i, aValue ) ) + { + aString += aValue; + aConfig.WriteKey( aOption, aString ); + } + } + break; + case SANE_TYPE_FIXED: + case SANE_TYPE_INT: + { + String aString( "NUMERIC=" ); + double fValue; + char buf[256]; + for( int n = 0; n < mrSane.GetOptionElements( i ); n++ ) + { + if( ! mrSane.GetOptionValue( i, fValue, n ) ) + break; + if( n > 0 ) + aString += ":"; + sprintf( buf, "%lg", fValue ); + aString += buf; + } + if( n >= mrSane.GetOptionElements( i ) ) + aConfig.WriteKey( aOption, aString ); + } + break; + default: + break; + } + } +#else + static char const* pSaveOptions[] = { + "resolution", + "tl-x", + "tl-y", + "br-x", + "br-y" + }; + for( size_t i = 0; + i < (sizeof(pSaveOptions)/sizeof(pSaveOptions[0])); + i++ ) + { + ByteString aOption = pSaveOptions[i]; + int nOption = mrSane.GetOptionByName( pSaveOptions[i] ); + if( nOption > -1 ) + { + SANE_Value_Type nType = mrSane.GetOptionType( nOption ); + switch( nType ) + { + case SANE_TYPE_BOOL: + { + BOOL bValue; + if( mrSane.GetOptionValue( nOption, bValue ) ) + { + ByteString aString( "BOOL=" ); + aString += ByteString::CreateFromInt32(bValue); + aConfig.WriteKey( aOption, aString ); + } + } + break; + case SANE_TYPE_STRING: + { + ByteString aString( "STRING=" ); + ByteString aValue; + if( mrSane.GetOptionValue( nOption, aValue ) ) + { + aString += aValue; + aConfig.WriteKey( aOption, aString ); + } + } + break; + case SANE_TYPE_FIXED: + case SANE_TYPE_INT: + { + ByteString aString( "NUMERIC=" ); + double fValue; + char buf[256]; + int n; + + for( n = 0; n < mrSane.GetOptionElements( nOption ); n++ ) + { + if( ! mrSane.GetOptionValue( nOption, fValue, n ) ) + break; + if( n > 0 ) + aString += ":"; + sprintf( buf, "%lg", fValue ); + aString += buf; + } + if( n >= mrSane.GetOptionElements( nOption ) ) + aConfig.WriteKey( aOption, aString ); + } + break; + default: + break; + } + } + } +#endif +#endif +} + +BOOL SaneDlg::SetAdjustedNumericalValue( + const char* pOption, + double fValue, + int nElement ) +{ + int nOption; + if( ! Sane::IsSane() || ! mrSane.IsOpen() || ( nOption = mrSane.GetOptionByName( pOption ) ) == -1 ) + return FALSE; + + if( nElement < 0 || nElement >= mrSane.GetOptionElements( nOption ) ) + return FALSE; + + double* pValues = NULL; + int nValues; + if( ( nValues = mrSane.GetRange( nOption, pValues ) ) < 0 ) + return FALSE; + +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "SaneDlg::SetAdjustedNumericalValue( \"%s\", %lg ) ", + pOption, fValue ); +#endif + + if( nValues ) + { + int nNearest = 0; + double fNearest = 1e6; + for( int i = 0; i < nValues; i++ ) + { + if( fabs( fValue - pValues[ i ] ) < fNearest ) + { + fNearest = fabs( fValue - pValues[ i ] ); + nNearest = i; + } + } + fValue = pValues[ nNearest ]; + } + else + { + if( fValue < pValues[0] ) + fValue = pValues[0]; + if( fValue > pValues[1] ) + fValue = pValues[1]; + } + delete [] pValues; + mrSane.SetOptionValue( nOption, fValue, nElement ); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "yields %lg\n", fValue ); +#endif + + + return TRUE; +} diff --git a/extensions/source/scanner/sanedlg.hrc b/extensions/source/scanner/sanedlg.hrc new file mode 100644 index 000000000000..ca893122c9a9 --- /dev/null +++ b/extensions/source/scanner/sanedlg.hrc @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SVT_SANEDLG_HRC +#define _SVT_SANEDLG_HRC + +#define RID_SANE_DIALOG 1000 +#define RID_SCAN_OK 1 +#define RID_SCAN_CANCEL 2 +#define RID_DEVICEINFO_BTN 3 +#define RID_PREVIEW_BOX 4 +#define RID_DEVICE_BOX_TXT 5 +#define RID_DEVICE_BOX 6 +#define RID_SCANAREA_BOX 7 +#define RID_SCAN_LEFT_TXT 8 +#define RID_SCAN_LEFT_BOX 9 +#define RID_SCAN_TOP_BOX 10 +#define RID_SCAN_TOP_TXT 11 +#define RID_SCAN_RIGHT_TXT 12 +#define RID_SCAN_RIGHT_BOX 13 +#define RID_SCAN_BOTTOM_TXT 14 +#define RID_SCAN_BOTTOM_BOX 15 +#define RID_SCAN_RESOLUTION_TXT 16 +#define RID_SCAN_RESOLUTION_BOX 17 +#define RID_PREVIEW_BTN 18 +#define RID_SCAN_OPTION_BOX 19 +#define RID_SCAN_OPTIONTITLE_TXT 20 +#define RID_SCAN_OPTION_DESC_TXT 21 +#define RID_SCAN_BOOL_OPTION_BOX 22 +#define RID_SCAN_OPTION_TXT 23 +#define RID_SCAN_STRING_OPTION_EDT 24 +#define RID_SCAN_QUANTUM_RANGE_BOX 25 +#define RID_SCAN_STRING_RANGE_BOX 26 +#define RID_SCAN_NUMERIC_OPTION_EDT 27 +#define RID_SCAN_BUTTON_OPTION_BTN 28 +#define RID_SCAN_NUMERIC_VECTOR_BOX 29 +#define RID_SCAN_NUMERIC_VECTOR_TXT 30 +#define RID_SCAN_BITMAP_PLUS 31 +#define RID_SCAN_BITMAP_MINUS 32 +#define RID_SCAN_ADVANCED_BOX 33 +#define RID_SCAN_ADVANCED_TXT 34 + +#define RID_SANE_DEVICEINFO_TXT 1001 +#define RID_SANE_SCANERROR_TXT 1002 +#define RID_SANE_NORESOLUTIONOPTION_TXT 1003 +#define RID_SANE_NOSANELIB_TXT 1004 + +#define SCAN_AREA_TOP 17 +#define SCAN_AREA_LEFT 8 +#define PREVIEW_UPPER_LEFT SCAN_AREA_LEFT +#define PREVIEW_UPPER_TOP SCAN_AREA_TOP + 80 +#define PREVIEW_WIDTH 113 +#define PREVIEW_HEIGHT 160 +#define PREVIEW_BOTTOM PREVIEW_UPPER_TOP + PREVIEW_HEIGHT +#define PREVIEW_RIGHT PREVIEW_UPPER_LEFT + PREVIEW_WIDTH +#define SECOND_COLUMN PREVIEW_WIDTH + 20 +#define THIRD_COLUMN SECOND_COLUMN + 135 + +#endif diff --git a/extensions/source/scanner/sanedlg.hxx b/extensions/source/scanner/sanedlg.hxx new file mode 100644 index 000000000000..2ea35ca33c83 --- /dev/null +++ b/extensions/source/scanner/sanedlg.hxx @@ -0,0 +1,152 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SVT_SANEDLG_HXX +#define _SVT_SANEDLG_HXX + +#include <vcl/dialog.hxx> +#include <tools/config.hxx> +#include <vcl/lstbox.hxx> +#ifndef _SV_BUTTON_HXX +#include <vcl/button.hxx> +#endif +#include <vcl/fixed.hxx> +#include <vcl/group.hxx> +#include <vcl/field.hxx> +#include <vcl/edit.hxx> +#include <svtools/svtreebx.hxx> + +#include <sane.hxx> + +class SaneDlg : public ModalDialog +{ +private: + enum DragDirection { TopLeft, Top, TopRight, Right, BottomRight, Bottom, + BottomLeft, Left }; + + Sane& mrSane; + Bitmap maPreviewBitmap; + Rectangle maPreviewRect; + Point maTopLeft, maBottomRight; + Point maMinTopLeft, maMaxBottomRight; + BOOL mbDragEnable; + BOOL mbIsDragging; + int mnDragMode; + BOOL mbDragDrawn; + DragDirection meDragDirection; + + MapMode maMapMode; + + Link maOldLink; + + OKButton maOKButton; + CancelButton maCancelButton; + PushButton maDeviceInfoButton; + PushButton maPreviewButton; + PushButton maButtonOption; + + FixedText maOptionsTxt; + FixedText maOptionTitle; + FixedText maOptionDescTxt; + FixedText maVectorTxt; + + FixedText maScanLeftTxt; + MetricField maLeftField; + FixedText maScanTopTxt; + MetricField maTopField; + FixedText maRightTxt; + MetricField maRightField; + FixedText maBottomTxt; + MetricField maBottomField; + + FixedText maDeviceBoxTxt; + ListBox maDeviceBox; + FixedText maReslTxt; + NumericBox maReslBox; + FixedText maAdvancedTxt; + CheckBox maAdvancedBox; + + NumericField maVectorBox; + ListBox maQuantumRangeBox; + ListBox maStringRangeBox; + + FixedLine maPreviewBox; + FixedLine maAreaBox; + + CheckBox maBoolCheckBox; + + Edit maStringEdit; + Edit maNumericEdit; + + SvTreeListBox maOptionBox; + + int mnCurrentOption; + int mnCurrentElement; + double* mpRange; + double mfMin, mfMax; + + DECL_LINK( ClickBtnHdl, Button* ); + DECL_LINK( SelectHdl, ListBox* ); + DECL_LINK( ModifyHdl, Edit* ); + DECL_LINK( ReloadSaneOptionsHdl, Sane* ); + DECL_LINK( OptionsBoxSelectHdl, SvTreeListBox* ); + + void SaveState(); + BOOL LoadState(); + + void InitDevices(); + void InitFields(); + void AcquirePreview(); + void DisableOption(); + void EstablishBoolOption(); + void EstablishStringOption(); + void EstablishStringRange(); + void EstablishQuantumRange(); + void EstablishNumericOption(); + void EstablishButtonOption(); + + void DrawRectangles( Point&, Point& ); + void DrawDrag(); + Point GetPixelPos( const Point& ); + Point GetLogicPos( const Point& ); + void UpdateScanArea( BOOL ); + + // helper + BOOL SetAdjustedNumericalValue( const char* pOption, double fValue, int nElement = 0 ); + + virtual void Paint( const Rectangle& ); + virtual void MouseMove( const MouseEvent& rMEvt ); + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual void MouseButtonUp( const MouseEvent& rMEvt ); +public: + SaneDlg( Window*, Sane& ); + ~SaneDlg(); + + virtual short Execute(); +}; + + +#endif diff --git a/extensions/source/scanner/sanedlg.src b/extensions/source/scanner/sanedlg.src new file mode 100644 index 000000000000..2c4cc338ab8a --- /dev/null +++ b/extensions/source/scanner/sanedlg.src @@ -0,0 +1,301 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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 <sanedlg.hrc> +ModalDialog RID_SANE_DIALOG +{ + OutputSize = TRUE ; + SVLook = TRUE ; + Pos = MAP_APPFONT ( 10 , 10 ) ; + Size = MAP_APPFONT ( THIRD_COLUMN + 60 , 268 ) ; + Moveable = TRUE ; + Closeable = TRUE ; + OKButton RID_SCAN_OK + { + Pos = MAP_APPFONT ( THIRD_COLUMN , 6 ) ; + Size = MAP_APPFONT ( 55 , 14 ) ; + DefButton = TRUE; + }; + CancelButton RID_SCAN_CANCEL + { + Pos = MAP_APPFONT ( THIRD_COLUMN , 25 ) ; + Size = MAP_APPFONT ( 55 , 14 ) ; + }; + PushButton RID_DEVICEINFO_BTN + { + Pos = MAP_APPFONT ( THIRD_COLUMN , 44 ) ; + Size = MAP_APPFONT ( 55 , 22 ) ; + Text [ en-US ] = "About\n Dev~ice" ; + }; + PushButton RID_PREVIEW_BTN + { + Pos = MAP_APPFONT ( THIRD_COLUMN , 71 ) ; + Size = MAP_APPFONT ( 55 , 22 ) ; + Text [ en-US ] = "Create\nPreview" ; + }; + FixedLine RID_PREVIEW_BOX + { + Pos = MAP_APPFONT ( PREVIEW_UPPER_LEFT - 5 , PREVIEW_UPPER_TOP - 8 ) ; + Size = MAP_APPFONT ( PREVIEW_WIDTH + 10 , 8 ) ; + Text [ en-US ] = "Preview" ; + }; + FixedLine RID_SCANAREA_BOX + { + Pos = MAP_APPFONT ( SCAN_AREA_LEFT - 5 , SCAN_AREA_TOP - 12 ) ; + Size = MAP_APPFONT ( PREVIEW_WIDTH + 10 , 8 ) ; + Text [ en-US ] = "Scan area" ; + }; + FixedText RID_SCAN_LEFT_TXT + { + Pos = MAP_APPFONT ( SCAN_AREA_LEFT , SCAN_AREA_TOP ) ; + Size = MAP_APPFONT ( 50 , 8 ) ; + Text [ en-US ] = "Left:" ; + }; + MetricField RID_SCAN_LEFT_BOX + { + Spin = TRUE ; + Repeat = TRUE ; + Border = TRUE ; + Pos = MAP_APPFONT ( SCAN_AREA_LEFT + 50 , SCAN_AREA_TOP - 2 ) ; + Size = MAP_APPFONT ( PREVIEW_WIDTH - 50 , 12 ) ; + }; + FixedText RID_SCAN_TOP_TXT + { + Pos = MAP_APPFONT ( SCAN_AREA_LEFT , SCAN_AREA_TOP + 17 ) ; + Size = MAP_APPFONT ( 50 , 8 ) ; + Text [ en-US ] = "Top:" ; + }; + MetricField RID_SCAN_TOP_BOX + { + Spin = TRUE ; + Repeat = TRUE ; + Border = TRUE ; + Pos = MAP_APPFONT ( SCAN_AREA_LEFT + 50 , SCAN_AREA_TOP + 15 ) ; + Size = MAP_APPFONT ( PREVIEW_WIDTH - 50 , 12 ) ; + }; + FixedText RID_SCAN_RIGHT_TXT + { + Pos = MAP_APPFONT ( SCAN_AREA_LEFT , SCAN_AREA_TOP + 34 ) ; + Size = MAP_APPFONT ( 50 , 8 ) ; + Text [ en-US ] = "Right:" ; + }; + MetricField RID_SCAN_RIGHT_BOX + { + Spin = TRUE ; + Repeat = TRUE ; + Border = TRUE ; + Pos = MAP_APPFONT ( SCAN_AREA_LEFT + 50 , SCAN_AREA_TOP + 32 ) ; + Size = MAP_APPFONT ( PREVIEW_WIDTH - 50 , 12 ) ; + }; + FixedText RID_SCAN_BOTTOM_TXT + { + Pos = MAP_APPFONT ( SCAN_AREA_LEFT , SCAN_AREA_TOP + 51 ) ; + Size = MAP_APPFONT ( 50 , 8 ) ; + Text [ en-US ] = "Bottom:" ; + }; + MetricField RID_SCAN_BOTTOM_BOX + { + Spin = TRUE ; + Repeat = TRUE ; + Border = TRUE ; + Pos = MAP_APPFONT ( SCAN_AREA_LEFT + 50 , SCAN_AREA_TOP + 49 ) ; + Size = MAP_APPFONT ( PREVIEW_WIDTH - 50 , 12 ) ; + }; + FixedText RID_DEVICE_BOX_TXT + { + Pos = MAP_APPFONT ( SECOND_COLUMN , 8 ) ; + Size = MAP_APPFONT ( 70 , 8 ) ; + Text [ en-US ] = "Device used:" ; + }; + ListBox RID_DEVICE_BOX + { + Border = TRUE ; + Dropdown = TRUE ; + Sort = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN + 70 , 6 ) ; + Size = MAP_APPFONT ( 60 , 80 ) ; + }; + FixedText RID_SCAN_RESOLUTION_TXT + { + Pos = MAP_APPFONT ( SECOND_COLUMN , 25 ) ; + Size = MAP_APPFONT ( 70 , 8 ) ; + Text [ en-US ] = "Resolution [~DPI]" ; + }; + NumericBox RID_SCAN_RESOLUTION_BOX + { + Dropdown = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN + 70 , 23 ) ; + Size = MAP_APPFONT ( 60 , 80 ) ; + }; + FixedText RID_SCAN_ADVANCED_TXT + { + Pos = MAP_APPFONT ( SECOND_COLUMN , 40 ) ; + Size = MAP_APPFONT ( 120 , 8 ) ; + Text [ en-US ] = "Show advanced options" ; + }; + CheckBox RID_SCAN_ADVANCED_BOX + { + Check = FALSE ; + Pos = MAP_APPFONT ( SECOND_COLUMN + 120 , 40 ) ; + Size = MAP_APPFONT ( 8 , 8 ) ; + }; + FixedText RID_SCAN_OPTION_TXT + { + Pos = MAP_APPFONT ( SECOND_COLUMN , 54 ) ; + Size = MAP_APPFONT ( 130 , 8 ) ; + Text [ en-US ] = "Options:" ; + }; + Control RID_SCAN_OPTION_BOX + { + Border = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN , 63 ) ; + Size = MAP_APPFONT ( 130 , 102 ) ; + }; + FixedText RID_SCAN_OPTIONTITLE_TXT + { + WordBreak = TRUE ; + Border = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN , 170 ) ; + Size = MAP_APPFONT ( 130 , 50 ) ; + }; + FixedText RID_SCAN_OPTION_DESC_TXT + { + Pos = MAP_APPFONT ( SECOND_COLUMN , 225 ) ; + Size = MAP_APPFONT ( 120 , 8 ) ; + }; + CheckBox RID_SCAN_BOOL_OPTION_BOX + { + Pos = MAP_APPFONT ( SECOND_COLUMN + 120 , 225 ) ; + Size = MAP_APPFONT ( 8 , 8 ) ; + }; + Edit RID_SCAN_STRING_OPTION_EDT + { + Border = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN , 234 ) ; + Size = MAP_APPFONT ( 130 , 12 ) ; + }; + ListBox RID_SCAN_QUANTUM_RANGE_BOX + { + Border = TRUE ; + Dropdown = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN , 234 ) ; + Size = MAP_APPFONT ( 130 , 80 ) ; + }; + ListBox RID_SCAN_STRING_RANGE_BOX + { + Border = TRUE ; + Dropdown = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN , 234 ) ; + Size = MAP_APPFONT ( 130 , 80 ) ; + }; + Edit RID_SCAN_NUMERIC_OPTION_EDT + { + Border = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN , 234 ) ; + Size = MAP_APPFONT ( 130 , 12 ) ; + }; + FixedText RID_SCAN_NUMERIC_VECTOR_TXT + { + Pos = MAP_APPFONT ( SECOND_COLUMN , 253 ) ; + Size = MAP_APPFONT ( 90 , 8 ) ; + Text [ en-US ] = "Vector element" ; + }; + NumericField RID_SCAN_NUMERIC_VECTOR_BOX + { + Border = TRUE ; + Spin = TRUE ; + Repeat = TRUE ; + Pos = MAP_APPFONT ( SECOND_COLUMN + 90 , 251 ) ; + Size = MAP_APPFONT ( 40 , 12 ) ; + }; + PushButton RID_SCAN_BUTTON_OPTION_BTN + { + Pos = MAP_APPFONT ( SECOND_COLUMN , 234 ) ; + Size = MAP_APPFONT ( 130 , 14 ) ; + Text [ en-US ] = "Set" ; + }; + Bitmap RID_SCAN_BITMAP_PLUS + { + File = "plus.bmp" ; + }; + Bitmap RID_SCAN_BITMAP_MINUS + { + File = "minus.bmp" ; + }; + Text [ en-US ] = "Scanner" ; +}; +String RID_SANE_DEVICEINFO_TXT +{ + Text [ en-US ] = "Device: %s\nVendor: %s\nModel: %s\nType: %s" ; +}; +String RID_SANE_SCANERROR_TXT +{ + Text [ en-US ] = "An error occurred while scanning." ; +}; +String RID_SANE_NORESOLUTIONOPTION_TXT +{ + Text [ en-US ] = "The device does not offer a preview option. Therefore, a normal scan will be used as a preview instead. This may take a considerable amount of time." ; +}; +String RID_SANE_NOSANELIB_TXT +{ + Text [ en-US ] = "The SANE interface could not be initialized. Scanning is not possible." ; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/source/scanner/scanner.cxx b/extensions/source/scanner/scanner.cxx new file mode 100644 index 000000000000..884ee866a902 --- /dev/null +++ b/extensions/source/scanner/scanner.cxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include <scanner.hxx> + +// ------------------ +// - ScannerManager - +// ------------------ + +REF( XInterface ) SAL_CALL ScannerManager_CreateInstance( const REF( com::sun::star::lang::XMultiServiceFactory )& /*rxFactory*/ ) throw ( Exception ) +{ + return *( new ScannerManager() ); +} + +// ----------------------------------------------------------------------------- + +ScannerManager::ScannerManager() : + mpData( NULL ) +{ +} + +// ----------------------------------------------------------------------------- + +ScannerManager::~ScannerManager() +{ + DestroyData(); +} + +// ----------------------------------------------------------------------------- + +ANY SAL_CALL ScannerManager::queryInterface( const Type& rType ) throw( RuntimeException ) +{ + const ANY aRet( cppu::queryInterface( rType, + static_cast< XScannerManager* >( this ), + static_cast< AWT::XBitmap* >( this ) ) ); + + return( aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ) ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ScannerManager::acquire() throw() +{ + OWeakObject::acquire(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ScannerManager::release() throw() +{ + OWeakObject::release(); +} + +// ----------------------------------------------------------------------------- + +SEQ( sal_Int8 ) SAL_CALL ScannerManager::getMaskDIB() throw() +{ + return SEQ( sal_Int8 )(); +} + +// ----------------------------------------------------------------------------- + +OUString ScannerManager::getImplementationName_Static() throw() +{ + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.scanner.ScannerManager" ) ); +} + +// ----------------------------------------------------------------------------- + +SEQ( OUString ) ScannerManager::getSupportedServiceNames_Static() throw () +{ + SEQ( OUString ) aSNS( 1 ); + + aSNS.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.scanner.ScannerManager" ) ); + + return aSNS; +} diff --git a/extensions/source/scanner/scanner.hxx b/extensions/source/scanner/scanner.hxx new file mode 100644 index 000000000000..6ca0804d1c33 --- /dev/null +++ b/extensions/source/scanner/scanner.hxx @@ -0,0 +1,115 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EXT_SCANNER_HXX +#define _EXT_SCANNER_HXX + +#include <tools/stream.hxx> +#include <vos/mutex.hxx> +#ifndef __RTL_USTRING_HXX_ +#include <rtl/ustring.hxx> +#endif +#include <cppuhelper/weak.hxx> +#include <cppuhelper/weak.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#ifndef __COM_SUN_STAR_AWT_XBITMAP_HPP +#include <com/sun/star/awt/XBitmap.hpp> +#endif +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#ifndef __COM_SUN_STAR_LANG_EVENTOBJECT_HPP +#include <com/sun/star/lang/EventObject.hpp> +#endif +#include <com/sun/star/scanner/XScannerManager.hpp> +#include <com/sun/star/scanner/ScannerException.hpp> + +using namespace rtl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::scanner; + +// ----------- +// - Defines - +// ----------- + +#define REF( _def_Obj ) Reference< _def_Obj > +#define SEQ( _def_Obj ) Sequence< _def_Obj > +#define ANY Any +#define AWT com::sun::star::awt + +// ------------------ +// - ScannerManager - +// ------------------ + +class ScannerManager : public OWeakObject, XScannerManager, AWT::XBitmap +{ +protected: + + vos::OMutex maProtector; + void* mpData; + + void DestroyData(); + +public: + + ScannerManager(); + virtual ~ScannerManager(); + + // XInterface + virtual ANY SAL_CALL queryInterface( const Type & rType ) throw( RuntimeException ); + virtual void SAL_CALL acquire() throw(); + virtual void SAL_CALL release() throw(); + + // XScannerManager + virtual SEQ( ScannerContext ) SAL_CALL getAvailableScanners() throw(); + virtual BOOL SAL_CALL configureScanner( ScannerContext& scanner_context ) throw( ScannerException ); + virtual void SAL_CALL startScan( const ScannerContext& scanner_context, const REF( com::sun::star::lang::XEventListener )& rxListener ) throw( ScannerException ); + virtual ScanError SAL_CALL getError( const ScannerContext& scanner_context ) throw( ScannerException ); + virtual REF( AWT::XBitmap ) SAL_CALL getBitmap( const ScannerContext& scanner_context ) throw( ScannerException ); + + // XBitmap + virtual AWT::Size SAL_CALL getSize() throw(); + virtual SEQ( sal_Int8 ) SAL_CALL getDIB() throw(); + virtual SEQ( sal_Int8 ) SAL_CALL getMaskDIB() throw(); + + // Misc + static OUString getImplementationName_Static() throw(); + static Sequence< OUString > getSupportedServiceNames_Static() throw(); + + void Lock() { maProtector.acquire(); } + void Unlock() { maProtector.release(); } + + void* GetData() const { return mpData; } + void SetData( void* pData ) { DestroyData(); mpData = pData; } +}; + +// ----------------------------------------------------------------------------- + +REF( XInterface ) SAL_CALL ScannerManager_CreateInstance( const REF( com::sun::star::lang::XMultiServiceFactory )& rxFactory ) throw( Exception ); + +#endif diff --git a/extensions/source/scanner/scanunx.cxx b/extensions/source/scanner/scanunx.cxx new file mode 100644 index 000000000000..b47ddb9adbea --- /dev/null +++ b/extensions/source/scanner/scanunx.cxx @@ -0,0 +1,352 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include <scanner.hxx> +#include <sanedlg.hxx> +#include <vos/thread.hxx> +#include <tools/list.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +BitmapTransporter::BitmapTransporter() +{ +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "BitmapTransporter\n" ); +#endif +} + +BitmapTransporter::~BitmapTransporter() +{ +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "~BitmapTransporter\n" ); +#endif +} + +// ----------------------------------------------------------------------------- + +ANY SAL_CALL BitmapTransporter::queryInterface( const Type& rType ) throw( RuntimeException ) +{ + const ANY aRet( cppu::queryInterface( rType, static_cast< AWT::XBitmap* >( this ) ) ); + + return( aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ) ); +} + +// ----------------------------------------------------------------------------- + +AWT::Size BitmapTransporter::getSize() throw() +{ + vos::OGuard aGuard( m_aProtector ); + int nPreviousPos = m_aStream.Tell(); + AWT::Size aRet; + + // ensure that there is at least a header + m_aStream.Seek( STREAM_SEEK_TO_END ); + int nLen = m_aStream.Tell(); + if( nLen > 15 ) + { + m_aStream.Seek( 4 ); + m_aStream >> aRet.Width >> aRet.Height; + } + else + aRet.Width = aRet.Height = 0; + + m_aStream.Seek( nPreviousPos ); + + return aRet; +} + +// ----------------------------------------------------------------------------- + +SEQ( sal_Int8 ) BitmapTransporter::getDIB() throw() +{ + vos::OGuard aGuard( m_aProtector ); + int nPreviousPos = m_aStream.Tell(); + + // create return value + m_aStream.Seek( STREAM_SEEK_TO_END ); + int nBytes = m_aStream.Tell(); + m_aStream.Seek( 0 ); + + SEQ( sal_Int8 ) aValue( nBytes ); + m_aStream.Read( aValue.getArray(), nBytes ); + m_aStream.Seek( nPreviousPos ); + + return aValue; +} + +// -------------- +// - SaneHolder - +// -------------- + +struct SaneHolder +{ + Sane m_aSane; + REF( AWT::XBitmap ) m_xBitmap; + vos::OMutex m_aProtector; + ScanError m_nError; + bool m_bBusy; +}; + +DECLARE_LIST( SaneHolderList, SaneHolder* ) + +static SaneHolderList allSanes; +static vos::OMutex aSaneProtector; + +// ----------------- +// - ScannerThread - +// ----------------- + +class ScannerThread : public vos::OThread +{ + SaneHolder* m_pHolder; + REF( com::sun::star::lang::XEventListener ) m_xListener; + ScannerManager* m_pManager; // just for the disposing call + +public: + virtual void run(); + virtual void onTerminated() { delete this; } +public: + ScannerThread( SaneHolder* pHolder, + const REF( com::sun::star::lang::XEventListener )& listener, + ScannerManager* pManager ); + virtual ~ScannerThread(); +}; + +// ----------------------------------------------------------------------------- + +ScannerThread::ScannerThread( + SaneHolder* pHolder, + const REF( com::sun::star::lang::XEventListener )& listener, + ScannerManager* pManager ) + : m_pHolder( pHolder ), m_xListener( listener ), m_pManager( pManager ) +{ +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "ScannerThread\n" ); +#endif +} + +ScannerThread::~ScannerThread() +{ +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "~ScannerThread\n" ); +#endif +} + +void ScannerThread::run() +{ + vos::OGuard aGuard( m_pHolder->m_aProtector ); + BitmapTransporter* pTransporter = new BitmapTransporter; + REF( XInterface ) aIf( static_cast< OWeakObject* >( pTransporter ) ); + + m_pHolder->m_xBitmap = REF( AWT::XBitmap )( aIf, UNO_QUERY ); + + m_pHolder->m_bBusy = true; + if( m_pHolder->m_aSane.IsOpen() ) + { + int nOption = m_pHolder->m_aSane.GetOptionByName( "preview" ); + if( nOption != -1 ) + m_pHolder->m_aSane.SetOptionValue( nOption, (BOOL)FALSE ); + + m_pHolder->m_nError = + m_pHolder->m_aSane.Start( *pTransporter ) ? + ScanError_ScanErrorNone : ScanError_ScanCanceled; + } + else + m_pHolder->m_nError = ScanError_ScannerNotAvailable; + + + REF( XInterface ) xXInterface( static_cast< OWeakObject* >( m_pManager ) ); + m_xListener->disposing( com::sun::star::lang::EventObject(xXInterface) ); + m_pHolder->m_bBusy = false; +} + +// ------------------ +// - ScannerManager - +// ------------------ + +void ScannerManager::DestroyData() +{ + // was unused, now because of i99835: "Scanning interface not SANE API compliant" + // delete all SaneHolder to get Sane Dtor called + int i; + for ( i = allSanes.Count(); i > 0; i-- ) + { + SaneHolder *pSaneHolder = allSanes.GetObject(i-1); + if ( pSaneHolder ) delete pSaneHolder; + } +} + +// ----------------------------------------------------------------------------- + +AWT::Size ScannerManager::getSize() throw() +{ + AWT::Size aRet; + aRet.Width = aRet.Height = 0; + return aRet; +} + +// ----------------------------------------------------------------------------- + +SEQ( sal_Int8 ) ScannerManager::getDIB() throw() +{ + return SEQ( sal_Int8 )(); +} + +// ----------------------------------------------------------------------------- + +SEQ( ScannerContext ) ScannerManager::getAvailableScanners() throw() +{ + vos::OGuard aGuard( aSaneProtector ); + + if( ! allSanes.Count() ) + { + SaneHolder* pSaneHolder = new SaneHolder; + pSaneHolder->m_nError = ScanError_ScanErrorNone; + pSaneHolder->m_bBusy = false; + if( Sane::IsSane() ) + allSanes.Insert( pSaneHolder ); + else + delete pSaneHolder; + } + + if( Sane::IsSane() ) + { + SEQ( ScannerContext ) aRet(1); + aRet.getArray()[0].ScannerName = ::rtl::OUString::createFromAscii( "SANE" ); + aRet.getArray()[0].InternalData = 0; + return aRet; + } + + return SEQ( ScannerContext )(); +} + +// ----------------------------------------------------------------------------- + +BOOL ScannerManager::configureScanner( ScannerContext& scanner_context ) throw( ScannerException ) +{ + vos::OGuard aGuard( aSaneProtector ); + +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "ScannerManager::configureScanner\n" ); +#endif + + if( scanner_context.InternalData < 0 || (ULONG)scanner_context.InternalData >= allSanes.Count() ) + throw ScannerException( + ::rtl::OUString::createFromAscii( "Scanner does not exist" ), + REF( XScannerManager )( this ), + ScanError_InvalidContext + ); + + SaneHolder* pHolder = allSanes.GetObject( scanner_context.InternalData ); + if( pHolder->m_bBusy ) + throw ScannerException( + ::rtl::OUString::createFromAscii( "Scanner is busy" ), + REF( XScannerManager )( this ), + ScanError_ScanInProgress + ); + + pHolder->m_bBusy = true; + SaneDlg aDlg( NULL, pHolder->m_aSane ); + BOOL bRet = (BOOL)aDlg.Execute(); + pHolder->m_bBusy = false; + + return bRet; +} + +// ----------------------------------------------------------------------------- + +void ScannerManager::startScan( const ScannerContext& scanner_context, + const REF( com::sun::star::lang::XEventListener )& listener ) throw( ScannerException ) +{ + vos::OGuard aGuard( aSaneProtector ); + +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "ScannerManager::startScan\n" ); +#endif + + if( scanner_context.InternalData < 0 || (ULONG)scanner_context.InternalData >= allSanes.Count() ) + throw ScannerException( + ::rtl::OUString::createFromAscii( "Scanner does not exist" ), + REF( XScannerManager )( this ), + ScanError_InvalidContext + ); + SaneHolder* pHolder = allSanes.GetObject( scanner_context.InternalData ); + if( pHolder->m_bBusy ) + throw ScannerException( + ::rtl::OUString::createFromAscii( "Scanner is busy" ), + REF( XScannerManager )( this ), + ScanError_ScanInProgress + ); + pHolder->m_bBusy = true; + + ScannerThread* pThread = new ScannerThread( pHolder, listener, this ); + pThread->create(); +} + +// ----------------------------------------------------------------------------- + +ScanError ScannerManager::getError( const ScannerContext& scanner_context ) throw( ScannerException ) +{ + vos::OGuard aGuard( aSaneProtector ); + + if( scanner_context.InternalData < 0 || (ULONG)scanner_context.InternalData >= allSanes.Count() ) + throw ScannerException( + ::rtl::OUString::createFromAscii( "Scanner does not exist" ), + REF( XScannerManager )( this ), + ScanError_InvalidContext + ); + + SaneHolder* pHolder = allSanes.GetObject( scanner_context.InternalData ); + + return pHolder->m_nError; +} + +// ----------------------------------------------------------------------------- + +REF( AWT::XBitmap ) ScannerManager::getBitmap( const ScannerContext& scanner_context ) throw( ScannerException ) +{ + vos::OGuard aGuard( aSaneProtector ); + + if( scanner_context.InternalData < 0 || (ULONG)scanner_context.InternalData >= allSanes.Count() ) + throw ScannerException( + ::rtl::OUString::createFromAscii( "Scanner does not exist" ), + REF( XScannerManager )( this ), + ScanError_InvalidContext + ); + SaneHolder* pHolder = allSanes.GetObject( scanner_context.InternalData ); + + vos::OGuard aProtGuard( pHolder->m_aProtector ); + + REF( AWT::XBitmap ) xRet( pHolder->m_xBitmap ); + pHolder->m_xBitmap = REF( AWT::XBitmap )(); + + return xRet; +} diff --git a/extensions/source/scanner/scanwin.cxx b/extensions/source/scanner/scanwin.cxx new file mode 100644 index 000000000000..e14fffa87d0c --- /dev/null +++ b/extensions/source/scanner/scanwin.cxx @@ -0,0 +1,1053 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/util/XCloseBroadcaster.hpp> +#include <com/sun/star/util/XCloseListener.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <cppuhelper/implbase1.hxx> +#include <comphelper/processfactory.hxx> + +#include <math.h> +#include <tools/svwin.h> +#include <tools/stream.hxx> +#include <vos/mutex.hxx> +#include <vos/module.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/sysdata.hxx> +#include <vcl/salbtype.hxx> +#include "scanner.hxx" + +#pragma warning (push,1) +#pragma warning (disable:4668) +#include "twain/twain.h" +#pragma warning (pop) + +using namespace ::com::sun::star; + +// ----------- +// - Defines - +// ----------- + +#define TWAIN_SELECT 0x00000001UL +#define TWAIN_ACQUIRE 0x00000002UL +#define TWAIN_TERMINATE 0xFFFFFFFFUL + +#define TWAIN_EVENT_NONE 0x00000000UL +#define TWAIN_EVENT_QUIT 0x00000001UL +#define TWAIN_EVENT_SCANNING 0x00000002UL +#define TWAIN_EVENT_XFER 0x00000004UL + +#define PFUNC (*pDSM) +#define PTWAINMSG MSG* +#define FIXTODOUBLE( nFix ) ((double)nFix.Whole+(double)nFix.Frac/65536.) +#define FIXTOLONG( nFix ) ((long)floor(FIXTODOUBLE(nFix)+0.5)) + +#if defined WIN +#define TWAIN_LIBNAME "TWAIN.DLL" +#define TWAIN_FUNCNAME "DSM_Entry" +#elif defined WNT +#define TWAIN_LIBNAME "TWAIN_32.DLL" +#define TWAIN_FUNCNAME "DSM_Entry" +#endif + +// -------------- +// - TwainState - +// -------------- + +enum TwainState +{ + TWAIN_STATE_NONE = 0, + TWAIN_STATE_SCANNING = 1, + TWAIN_STATE_DONE = 2, + TWAIN_STATE_CANCELED = 3 +}; + +// ------------ +// - ImpTwain - +// ------------ + +class ImpTwain : public ::cppu::WeakImplHelper1< util::XCloseListener > +{ + friend LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam ); + + uno::Reference< uno::XInterface > mxSelfRef; + uno::Reference< scanner::XScannerManager > mxMgr; + ScannerManager& mrMgr; + TW_IDENTITY aAppIdent; + TW_IDENTITY aSrcIdent; + Link aNotifyLink; + DSMENTRYPROC pDSM; + NAMESPACE_VOS( OModule )* pMod; + ULONG nCurState; + HWND hTwainWnd; + HHOOK hTwainHook; + bool mbCloseFrameOnExit; + + bool ImplHandleMsg( void* pMsg ); + void ImplCreate(); + void ImplOpenSourceManager(); + void ImplOpenSource(); + bool ImplEnableSource(); + void ImplXfer(); + void ImplFallback( ULONG nEvent ); + void ImplSendCloseEvent(); + void ImplDeregisterCloseListener(); + void ImplRegisterCloseListener(); + uno::Reference< frame::XFrame > ImplGetActiveFrame(); + uno::Reference< util::XCloseBroadcaster > ImplGetActiveFrameCloseBroadcaster(); + + DECL_LINK( ImplFallbackHdl, void* ); + DECL_LINK( ImplDestroyHdl, void* ); + + // from util::XCloseListener + virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException); + virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException); + + // from lang::XEventListener + virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException); + +public: + + ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink ); + ~ImpTwain(); + + void Destroy(); + + bool SelectSource(); + bool InitXfer(); +}; + +// --------- +// - Procs - +// --------- + +static ImpTwain* pImpTwainInstance = NULL; + +// ------------------------------------------------------------------------- + +LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 ) +{ + return DefWindowProc( hWnd, nMsg, nPar1, nPar2 ); +} + +// ------------------------------------------------------------------------- + +LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ + MSG* pMsg = (MSG*) lParam; + + if( ( nCode < 0 ) || ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || !pImpTwainInstance->ImplHandleMsg( (void*) lParam ) ) + { + return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam ); + } + else + { + pMsg->message = WM_USER; + pMsg->lParam = 0; + + return 0; + } +} + +// ----------------------------------------------------------------------------- + +// #107835# hold reference to ScannerManager, to prevent premature death +ImpTwain::ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink ) : + mrMgr( rMgr ), + mxMgr( uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( &rMgr ), uno::UNO_QUERY) ), + aNotifyLink( rNotifyLink ), + pDSM( NULL ), + pMod( NULL ), + hTwainWnd( 0 ), + hTwainHook( 0 ), + nCurState( 1 ), + mbCloseFrameOnExit( false ) +{ + // setup TWAIN window + pImpTwainInstance = this; + + aAppIdent.Id = 0; + aAppIdent.Version.MajorNum = 1; + aAppIdent.Version.MinorNum = 0; + aAppIdent.Version.Language = TWLG_USA; + aAppIdent.Version.Country = TWCY_USA; + aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR; + aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR; + aAppIdent.SupportedGroups = DG_IMAGE | DG_CONTROL; + strncpy( aAppIdent.Version.Info, "8.0", 32 ); + aAppIdent.Version.Info[32] = aAppIdent.Version.Info[33] = 0; + strncpy( aAppIdent.Manufacturer, "Sun Microsystems", 32 ); + aAppIdent.Manufacturer[32] = aAppIdent.Manufacturer[33] = 0; + strncpy( aAppIdent.ProductFamily,"Office", 32 ); + aAppIdent.ProductFamily[32] = aAppIdent.ProductFamily[33] = 0; + strncpy( aAppIdent.ProductName, "Office", 32 ); + aAppIdent.ProductName[32] = aAppIdent.ProductName[33] = 0; + + WNDCLASS aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, "TwainClass" }; + RegisterClass( &aWc ); + + hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, aWc.hInstance, 0 ); + hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, GetCurrentThreadId() ); + + // #107835# block destruction until ImplDestroyHdl is called + mxSelfRef = static_cast< ::cppu::OWeakObject* >( this ); +} + +// ----------------------------------------------------------------------------- + +ImpTwain::~ImpTwain() +{ + // are we responsible for application shutdown? + if( mbCloseFrameOnExit ) + ImplSendCloseEvent(); +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::Destroy() +{ + ImplFallback( TWAIN_EVENT_NONE ); + Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL ); +} + +// ----------------------------------------------------------------------------- + +bool ImpTwain::SelectSource() +{ + TW_UINT16 nRet = TWRC_FAILURE; + + ImplOpenSourceManager(); + + if( 3 == nCurState ) + { + TW_IDENTITY aIdent; + + aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0'; + aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING ); + nRet = PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent ); + } + + ImplFallback( TWAIN_EVENT_QUIT ); + + return( TWRC_SUCCESS == nRet ); +} + +// ----------------------------------------------------------------------------- + +bool ImpTwain::InitXfer() +{ + bool bRet = false; + + ImplOpenSourceManager(); + + if( 3 == nCurState ) + { + ImplOpenSource(); + + if( 4 == nCurState ) + bRet = ImplEnableSource(); + } + + if( !bRet ) + ImplFallback( TWAIN_EVENT_QUIT ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplOpenSourceManager() +{ + if( 1 == nCurState ) + { + pMod = new ::vos::OModule( ::rtl::OUString() ); + + if( pMod->load( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( TWAIN_LIBNAME ) ) ) ) + { + nCurState = 2; + + if( ( ( pDSM = (DSMENTRYPROC) pMod->getSymbol( String( RTL_CONSTASCII_USTRINGPARAM( TWAIN_FUNCNAME ) ) ) ) != NULL ) && + ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) ) + { + nCurState = 3; + } + } + else + { + delete pMod; + pMod = NULL; + } + } +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplOpenSource() +{ + if( 3 == nCurState ) + { + if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) && + ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) ) + { + TW_CAPABILITY aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) }; + TW_ONEVALUE* pVal = (TW_ONEVALUE*) GlobalLock( aCap.hContainer ); + + pVal->ItemType = TWTY_INT16, pVal->Item = 1; + GlobalUnlock( aCap.hContainer ); + PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap ); + GlobalFree( aCap.hContainer ); + nCurState = 4; + } + } +} + +// ----------------------------------------------------------------------------- + +bool ImpTwain::ImplEnableSource() +{ + bool bRet = false; + + if( 4 == nCurState ) + { + TW_USERINTERFACE aUI = { true, true, hTwainWnd }; + + aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING ); + nCurState = 5; + + // #107835# register as vetoable close listener, to prevent application to die under us + ImplRegisterCloseListener(); + + if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS ) + { + bRet = true; + } + else + { + nCurState = 4; + + // #107835# deregister as vetoable close listener, dialog failed + ImplDeregisterCloseListener(); + } + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +bool ImpTwain::ImplHandleMsg( void* pMsg ) +{ + TW_UINT16 nRet; + PTWAINMSG pMess = (PTWAINMSG) pMsg; + TW_EVENT aEvt = { pMess, MSG_NULL }; + + nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt ); + + if( aEvt.TWMessage != MSG_NULL ) + { + switch( aEvt.TWMessage ) + { + case MSG_XFERREADY: + { + ULONG nEvent = TWAIN_EVENT_QUIT; + + if( 5 == nCurState ) + { + nCurState = 6; + ImplXfer(); + + if( mrMgr.GetData() ) + nEvent = TWAIN_EVENT_XFER; + } + + ImplFallback( nEvent ); + } + break; + + case MSG_CLOSEDSREQ: + ImplFallback( TWAIN_EVENT_QUIT ); + break; + + default: + break; + } + } + else + nRet = TWRC_NOTDSEVENT; + + return( TWRC_DSEVENT == nRet ); +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplXfer() +{ + if( nCurState == 6 ) + { + TW_IMAGEINFO aInfo; + TW_UINT32 hDIB = 0; + long nWidth, nHeight, nXRes, nYRes; + + if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS ) + { + nWidth = aInfo.ImageWidth; + nHeight = aInfo.ImageLength; + nXRes = FIXTOLONG( aInfo.XResolution ); + nYRes = FIXTOLONG( aInfo.YResolution ); + } + else + nWidth = nHeight = nXRes = nYRes = -1L; + + switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) ) + { + case( TWRC_CANCEL ): + nCurState = 7; + break; + + case( TWRC_XFERDONE ): + { + if( hDIB ) + { + if( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) ) + { + // set resolution of bitmap + BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( (HGLOBAL) hDIB ); + static const double fFactor = 100.0 / 2.54; + + pBIH->biXPelsPerMeter = FRound( fFactor * nXRes ); + pBIH->biYPelsPerMeter = FRound( fFactor * nYRes ); + + GlobalUnlock( (HGLOBAL) hDIB ); + } + + mrMgr.SetData( (void*)(long) hDIB ); + } + else + GlobalFree( (HGLOBAL) hDIB ); + + nCurState = 7; + } + break; + + default: + break; + } + } +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplFallback( ULONG nEvent ) +{ + Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent ); +} + +// ----------------------------------------------------------------------------- + +IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData ) +{ + const ULONG nEvent = (ULONG) pData; + bool bFallback = true; + + switch( nCurState ) + { + case( 7 ): + case( 6 ): + { + TW_PENDINGXFERS aXfers; + + if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS ) + { + if( aXfers.Count != 0 ) + PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers ); + } + + nCurState = 5; + } + break; + + case( 5 ): + { + TW_USERINTERFACE aUI = { true, true, hTwainWnd }; + + PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI ); + nCurState = 4; + + // #107835# deregister as vetoable close listener + ImplDeregisterCloseListener(); + } + break; + + case( 4 ): + { + PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent ); + nCurState = 3; + } + break; + + case( 3 ): + { + PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd ); + nCurState = 2; + } + break; + + case( 2 ): + { + delete pMod; + pMod = NULL; + nCurState = 1; + } + break; + + default: + { + if( nEvent != TWAIN_EVENT_NONE ) + aNotifyLink.Call( (void*) nEvent ); + + bFallback = false; + } + break; + } + + if( bFallback ) + ImplFallback( nEvent ); + + return 0L; +} + +// ----------------------------------------------------------------------------- + +IMPL_LINK( ImpTwain, ImplDestroyHdl, void*, /*p*/ ) +{ + if( hTwainWnd ) + DestroyWindow( hTwainWnd ); + + if( hTwainHook ) + UnhookWindowsHookEx( hTwainHook ); + + // #107835# permit destruction of ourselves (normally, refcount + // should drop to zero exactly here) + mxSelfRef = NULL; + pImpTwainInstance = NULL; + + return 0L; +} + +// ----------------------------------------------------------------------------- + +uno::Reference< frame::XFrame > ImpTwain::ImplGetActiveFrame() +{ + try + { + uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); + + if( xMgr.is() ) + { + // query desktop instance + uno::Reference< frame::XDesktop > xDesktop( xMgr->createInstance( + OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ), uno::UNO_QUERY ); + + if( xDesktop.is() ) + { + // query property set from desktop, which contains the currently active frame + uno::Reference< beans::XPropertySet > xDesktopProps( xDesktop, uno::UNO_QUERY ); + + if( xDesktopProps.is() ) + { + uno::Any aActiveFrame; + + try + { + aActiveFrame = xDesktopProps->getPropertyValue( + OUString::createFromAscii( "ActiveFrame" ) ); + } + catch( const beans::UnknownPropertyException& ) + { + // property unknown. + DBG_ERROR("ImpTwain::ImplGetActiveFrame: ActiveFrame property unknown, cannot determine active frame!"); + return uno::Reference< frame::XFrame >(); + } + + uno::Reference< frame::XFrame > xActiveFrame; + + if( (aActiveFrame >>= xActiveFrame) && + xActiveFrame.is() ) + { + return xActiveFrame; + } + } + } + } + } + catch( const uno::Exception& ) + { + } + + DBG_ERROR("ImpTwain::ImplGetActiveFrame: Could not determine active frame!"); + return uno::Reference< frame::XFrame >(); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< util::XCloseBroadcaster > ImpTwain::ImplGetActiveFrameCloseBroadcaster() +{ + try + { + return uno::Reference< util::XCloseBroadcaster >( ImplGetActiveFrame(), uno::UNO_QUERY ); + } + catch( const uno::Exception& ) + { + } + + DBG_ERROR("ImpTwain::ImplGetActiveFrameCloseBroadcaster: Could determine close broadcaster on active frame!"); + return uno::Reference< util::XCloseBroadcaster >(); +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplRegisterCloseListener() +{ + try + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( ImplGetActiveFrameCloseBroadcaster() ); + + if( xCloseBroadcaster.is() ) + { + xCloseBroadcaster->addCloseListener(this); + return; // successfully registered as a close listener + } + else + { + // interface unknown. don't register, then + DBG_ERROR("ImpTwain::ImplRegisterCloseListener: XFrame has no XCloseBroadcaster!"); + return; + } + } + catch( const uno::Exception& ) + { + } + + DBG_ERROR("ImpTwain::ImplRegisterCloseListener: Could not register as close listener!"); +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplDeregisterCloseListener() +{ + try + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( + ImplGetActiveFrameCloseBroadcaster() ); + + if( xCloseBroadcaster.is() ) + { + xCloseBroadcaster->removeCloseListener(this); + return; // successfully deregistered as a close listener + } + else + { + // interface unknown. don't deregister, then + DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: XFrame has no XCloseBroadcaster!"); + return; + } + } + catch( const uno::Exception& ) + { + } + + DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: Could not deregister as close listener!"); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ImpTwain::queryClosing( const lang::EventObject& /*Source*/, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException) +{ + // shall we re-send the close query later on? + mbCloseFrameOnExit = GetsOwnership; + + // the sole purpose of this listener is to forbid closing of the listened-at frame + throw util::CloseVetoException(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ImpTwain::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) +{ + // should not happen + DBG_ERROR("ImpTwain::notifyClosing called, but we vetoed the closing before!"); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ImpTwain::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) +{ + // we're not holding any references to the frame, thus noop +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplSendCloseEvent() +{ + try + { + uno::Reference< util::XCloseable > xCloseable( ImplGetActiveFrame(), uno::UNO_QUERY ); + + if( xCloseable.is() ) + xCloseable->close( true ); + } + catch( const uno::Exception& ) + { + } + + DBG_ERROR("ImpTwain::ImplSendCloseEvent: Could not send required close broadcast!"); +} + + +// --------- +// - Twain - +// --------- + +class Twain +{ + uno::Reference< lang::XEventListener > mxListener; + uno::Reference< scanner::XScannerManager > mxMgr; + const ScannerManager* mpCurMgr; + ImpTwain* mpImpTwain; + TwainState meState; + + DECL_LINK( ImpNotifyHdl, ImpTwain* ); + +public: + + Twain(); + ~Twain(); + + bool SelectSource( ScannerManager& rMgr ); + bool PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener ); + + TwainState GetState() const { return meState; } +}; + +// ------------------------------------------------------------------------ + +Twain::Twain() : + mpCurMgr( NULL ), + mpImpTwain( NULL ), + meState( TWAIN_STATE_NONE ) +{ +} + +// ------------------------------------------------------------------------ + +Twain::~Twain() +{ + if( mpImpTwain ) + mpImpTwain->Destroy(); +} + +// ------------------------------------------------------------------------ + +bool Twain::SelectSource( ScannerManager& rMgr ) +{ + bool bRet; + + if( !mpImpTwain ) + { + // #107835# hold reference to ScannerManager, to prevent premature death + mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ), + uno::UNO_QUERY ), + + meState = TWAIN_STATE_NONE; + mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) ); + bRet = mpImpTwain->SelectSource(); + } + else + bRet = false; + + return bRet; +} + +// ------------------------------------------------------------------------ + +bool Twain::PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener ) +{ + bool bRet; + + if( !mpImpTwain ) + { + // #107835# hold reference to ScannerManager, to prevent premature death + mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ), + uno::UNO_QUERY ), + + mxListener = rxListener; + meState = TWAIN_STATE_NONE; + mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) ); + bRet = mpImpTwain->InitXfer(); + } + else + bRet = false; + + return bRet; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK( Twain, ImpNotifyHdl, ImpTwain*, nEvent ) +{ + switch( (ULONG)(void*) nEvent ) + { + case( TWAIN_EVENT_SCANNING ): + meState = TWAIN_STATE_SCANNING; + break; + + case( TWAIN_EVENT_QUIT ): + { + if( meState != TWAIN_STATE_DONE ) + meState = TWAIN_STATE_CANCELED; + + if( mpImpTwain ) + { + mpImpTwain->Destroy(); + mpImpTwain = NULL; + mpCurMgr = NULL; + } + + if( mxListener.is() ) + mxListener->disposing( lang::EventObject( mxMgr ) ); + + mxListener = NULL; + } + break; + + case( TWAIN_EVENT_XFER ): + { + if( mpImpTwain ) + { + meState = ( mpCurMgr->GetData() ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED ); + + mpImpTwain->Destroy(); + mpImpTwain = NULL; + mpCurMgr = NULL; + + if( mxListener.is() ) + mxListener->disposing( lang::EventObject( mxMgr ) ); + } + + mxListener = NULL; + } + break; + + default: + break; + } + + return 0L; +} + +// ----------- +// - statics - +// ----------- + +static Twain aTwain; + +// ------------------ +// - ScannerManager - +// ------------------ + +void ScannerManager::DestroyData() +{ + if( mpData ) + { + GlobalFree( (HGLOBAL)(long) mpData ); + mpData = NULL; + } +} + +// ----------------------------------------------------------------------------- + +AWT::Size ScannerManager::getSize() throw() +{ + AWT::Size aRet; + HGLOBAL hDIB = (HGLOBAL)(long) mpData; + + if( hDIB ) + { + BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB ); + + if( pBIH ) + { + aRet.Width = pBIH->biWidth; + aRet.Height = pBIH->biHeight; + } + else + aRet.Width = aRet.Height = 0; + + GlobalUnlock( hDIB ); + } + else + aRet.Width = aRet.Height = 0; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +SEQ( sal_Int8 ) ScannerManager::getDIB() throw() +{ + SEQ( sal_Int8 ) aRet; + + if( mpData ) + { + HGLOBAL hDIB = (HGLOBAL)(long) mpData; + const sal_uInt32 nDIBSize = GlobalSize( hDIB ); + BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB ); + + if( pBIH ) + { + sal_uInt32 nColEntries; + + switch( pBIH->biBitCount ) + { + case( 1 ): + case( 4 ): + case( 8 ): + nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : ( 1 << pBIH->biBitCount ); + break; + + case( 24 ): + nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : 0; + break; + + case( 16 ): + case( 32 ): + { + nColEntries = pBIH->biClrUsed; + + if( pBIH->biCompression == BI_BITFIELDS ) + nColEntries += 3; + } + break; + + default: + nColEntries = 0; + break; + } + + aRet = SEQ( sal_Int8 )( sizeof( BITMAPFILEHEADER ) + nDIBSize ); + + sal_Int8* pBuf = aRet.getArray(); + SvMemoryStream* pMemStm = new SvMemoryStream( (char*) pBuf, sizeof( BITMAPFILEHEADER ), STREAM_WRITE ); + + *pMemStm << 'B' << 'M' << (sal_uInt32) 0 << (sal_uInt32) 0; + *pMemStm << (sal_uInt32) ( sizeof( BITMAPFILEHEADER ) + pBIH->biSize + ( nColEntries * sizeof( RGBQUAD ) ) ); + + delete pMemStm; + memcpy( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize ); + } + + GlobalUnlock( hDIB ); + DestroyData(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +SEQ( ScannerContext ) SAL_CALL ScannerManager::getAvailableScanners() throw() +{ + vos::OGuard aGuard( maProtector ); + SEQ( ScannerContext ) aRet( 1 ); + + aRet.getArray()[0].ScannerName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ); + aRet.getArray()[0].InternalData = 0; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +BOOL SAL_CALL ScannerManager::configureScanner( ScannerContext& rContext ) + throw( ScannerException ) +{ + vos::OGuard aGuard( maProtector ); + uno::Reference< XScannerManager > xThis( this ); + + if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) ) + throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext ); + + DestroyData(); + + return aTwain.SelectSource( *this ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ScannerManager::startScan( const ScannerContext& rContext, const uno::Reference< lang::XEventListener >& rxListener ) + throw( ScannerException ) +{ + vos::OGuard aGuard( maProtector ); + uno::Reference< XScannerManager > xThis( this ); + + if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) ) + throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext ); + + DestroyData(); + aTwain.PerformTransfer( *this, rxListener ); +} + +// ----------------------------------------------------------------------------- + +ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext ) + throw( ScannerException ) +{ + vos::OGuard aGuard( maProtector ); + uno::Reference< XScannerManager > xThis( this ); + + if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) ) + throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext ); + + return( ( aTwain.GetState() == TWAIN_STATE_CANCELED ) ? ScanError_ScanCanceled : ScanError_ScanErrorNone ); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< awt::XBitmap > SAL_CALL ScannerManager::getBitmap( const ScannerContext& /*rContext*/ ) + throw( ScannerException ) +{ + vos::OGuard aGuard( maProtector ); + return uno::Reference< awt::XBitmap >( this ); +} diff --git a/extensions/source/scanner/scnserv.cxx b/extensions/source/scanner/scnserv.cxx new file mode 100644 index 000000000000..e7c125fe1cae --- /dev/null +++ b/extensions/source/scanner/scnserv.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include <osl/diagnose.h> +#include <cppuhelper/factory.hxx> +#include <uno/mapping.hxx> +#include "scanner.hxx" + +#include <com/sun/star/registry/XRegistryKey.hpp> + +using namespace com::sun::star::registry; + +// ------------------------------------------ +// - component_getImplementationEnvironment - +// ------------------------------------------ + +extern "C" void SAL_CALL component_getImplementationEnvironment( const sal_Char** ppEnvTypeName, uno_Environment** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +// ----------------------- +// - component_writeInfo - +// ----------------------- + +extern "C" sal_Bool SAL_CALL component_writeInfo( void* /*pServiceManager*/, void* pRegistryKey ) +{ + sal_Bool bRet = sal_False; + + if( pRegistryKey ) + { + try + { + ::rtl::OUString aImplName( '/' ); + + aImplName += ScannerManager::getImplementationName_Static(); + aImplName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/UNO/SERVICES/" ) ); + aImplName += ScannerManager::getImplementationName_Static(); + + REF( XRegistryKey ) xNewKey1( static_cast< XRegistryKey* >( pRegistryKey )->createKey( aImplName ) ); + + bRet = sal_True; + } + catch( InvalidRegistryException& ) + { + OSL_ENSURE( sal_False, "### InvalidRegistryException!" ); + } + } + + return bRet; +} + +// ------------------------ +// - component_getFactory - +// ------------------------ + +extern "C" void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /*pRegistryKey*/ ) +{ + REF( ::com::sun::star::lang::XSingleServiceFactory ) xFactory; + void* pRet = 0; + + if( ::rtl::OUString::createFromAscii( pImplName ) == ScannerManager::getImplementationName_Static() ) + { + xFactory = REF( ::com::sun::star::lang::XSingleServiceFactory )( ::cppu::createSingleFactory( + static_cast< ::com::sun::star::lang::XMultiServiceFactory* >( pServiceManager ), + ScannerManager::getImplementationName_Static(), + ScannerManager_CreateInstance, + ScannerManager::getSupportedServiceNames_Static() ) ); + } + + if( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} diff --git a/extensions/source/scanner/twain.cxx b/extensions/source/scanner/twain.cxx new file mode 100644 index 000000000000..b11f2725501e --- /dev/null +++ b/extensions/source/scanner/twain.cxx @@ -0,0 +1,532 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" + +#include <string.h> +#include <math.h> + +#if defined( WNT ) || defined (WIN) +#include <tools/svwin.h> +#endif +#ifdef OS2 +#include <svpm.h> +#endif // OS2 +#include <vos/module.hxx> +#include <tools/stream.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/sysdata.hxx> +#include "twain.hxx" + +// ----------- +// - Defines - +// ----------- + +#define PFUNC (*pDSM) +#define FIXTODOUBLE( nFix ) ((double)nFix.Whole+(double)nFix.Frac/65536.) +#define FIXTOLONG( nFix ) ((long)floor(FIXTODOUBLE(nFix)+0.5)) + +#if defined WIN +#define TWAIN_LIBNAME "TWAIN.DLL" +#define TWAIN_FUNCNAME "DSM_Entry" +#elif defined WNT +#define TWAIN_LIBNAME "TWAIN_32.DLL" +#define TWAIN_FUNCNAME "DSM_Entry" +#elif defined OS2 +#define TWAIN_LIBNAME "twain" +#define TWAIN_FUNCNAME "DSM_ENTRY" +#endif + +// ----------- +// - Statics - +// ----------- + +static ImpTwain* pImpTwainInstance = NULL; + +// --------- +// - Procs - +// --------- + +#ifdef OS2 + + #define PTWAINMSG QMSG* + + MRESULT EXPENTRY TwainWndProc( HWND hWnd, ULONG nMsg, MPARAM nParam1, MPARAM nParam2 ) + { + return (MRESULT) TRUE; + } + + +#else // OS2 + + #define PTWAINMSG MSG* + + // ------------------------------------------------------------------------- + + LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 ) + { + return DefWindowProc( hWnd, nMsg, nPar1, nPar2 ); + } + + // ------------------------------------------------------------------------- + + LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam ) + { + MSG* pMsg = (MSG*) lParam; + + if( ( nCode < 0 ) || + ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || + !pImpTwainInstance->ImplHandleMsg( (void*) lParam ) ) + { + return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam ); + } + else + { + pMsg->message = WM_USER; + pMsg->lParam = 0; + + return 0; + } + } + +#endif // OS2 + +// ------------ +// - ImpTwain - +// ------------ + +ImpTwain::ImpTwain( const Link& rNotifyLink ) : + aNotifyLink ( rNotifyLink ), + pDSM ( NULL ), + pMod ( NULL ), + hTwainWnd ( 0 ), + hTwainHook ( 0 ), + nCurState ( 1 ) +{ + pImpTwainInstance = this; + + aAppIdent.Id = 0; + aAppIdent.Version.MajorNum = 1; + aAppIdent.Version.MinorNum = 0; + aAppIdent.Version.Language = TWLG_USA; + aAppIdent.Version.Country = TWCY_USA; + aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR; + aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR; + aAppIdent.SupportedGroups = DG_IMAGE | DG_CONTROL; + strcpy( aAppIdent.Version.Info, "6.0" ); + strcpy( aAppIdent.Manufacturer, "Sun Microsystems"); + strcpy( aAppIdent.ProductFamily,"Office"); + strcpy( aAppIdent.ProductName, "Office"); + +#ifdef OS2 + + hAB = Sysdepen::GethAB(); + ImplFallback( TWAIN_EVENT_QUIT ); + // hTwainWnd = WinCreateWindow( HWND_DESKTOP, WC_FRAME, "dummy", 0, 0, 0, 0, 0, HWND_DESKTOP, HWND_BOTTOM, 0, 0, 0 ); + +#else + + HWND hParentWnd = HWND_DESKTOP; + WNDCLASS aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ), + NULL, NULL, NULL, NULL, "TwainClass" }; + + RegisterClass( &aWc ); + hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, hParentWnd, NULL, aWc.hInstance, 0 ); + hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, GetCurrentThreadId() ); + +#endif +} + +// ----------------------------------------------------------------------------- + +ImpTwain::~ImpTwain() +{ +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::Destroy() +{ + ImplFallback( TWAIN_EVENT_NONE ); + Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL ); +} + +// ----------------------------------------------------------------------------- + +BOOL ImpTwain::SelectSource() +{ + TW_UINT16 nRet = TWRC_FAILURE; + + if( !!aBitmap ) + aBitmap = Bitmap(); + + ImplOpenSourceManager(); + + if( 3 == nCurState ) + { + TW_IDENTITY aIdent; + + aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0'; + aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING ); + nRet = PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent ); + } + + ImplFallback( TWAIN_EVENT_QUIT ); + + return( nRet == TWRC_SUCCESS || nRet == TWRC_CANCEL ); +} + +// ----------------------------------------------------------------------------- + +BOOL ImpTwain::InitXfer() +{ + BOOL bRet = FALSE; + + if( !!aBitmap ) + aBitmap = Bitmap(); + + ImplOpenSourceManager(); + + if( 3 == nCurState ) + { + ImplOpenSource(); + + if( 4 == nCurState ) + bRet = ImplEnableSource(); + } + + if( !bRet ) + ImplFallback( TWAIN_EVENT_QUIT ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +Bitmap ImpTwain::GetXferBitmap() +{ + Bitmap aRet( aBitmap ); + aBitmap = Bitmap(); + return aRet; +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplOpenSourceManager() +{ + if( 1 == nCurState ) + { + pMod = new NAMESPACE_VOS( OModule )(); + + if( pMod->load( TWAIN_LIBNAME ) ) + { + nCurState = 2; + + if( ( ( pDSM = (DSMENTRYPROC) pMod->getSymbol( TWAIN_FUNCNAME ) ) != NULL ) && + ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) ) + { + nCurState = 3; + } + } + else + { + delete pMod; + pMod = NULL; + } + } +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplOpenSource() +{ + if( 3 == nCurState ) + { + if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) && + ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) ) + { +#ifdef OS2 + + // negotiate capabilities + +#else + + TW_CAPABILITY aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) }; + TW_ONEVALUE* pVal = (TW_ONEVALUE*) GlobalLock( aCap.hContainer ); + + pVal->ItemType = TWTY_INT16, pVal->Item = 1; + GlobalUnlock( aCap.hContainer ); + PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap ); + GlobalFree( aCap.hContainer ); +#endif + + nCurState = 4; + } + } +} + +// ----------------------------------------------------------------------------- + +BOOL ImpTwain::ImplEnableSource() +{ + BOOL bRet = FALSE; + + if( 4 == nCurState ) + { + TW_USERINTERFACE aUI = { TRUE, TRUE, hTwainWnd }; + + aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING ); + nCurState = 5; + + if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS ) + bRet = TRUE; + else + nCurState = 4; + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL ImpTwain::ImplHandleMsg( void* pMsg ) +{ + TW_UINT16 nRet; + PTWAINMSG pMess = (PTWAINMSG) pMsg; + TW_EVENT aEvt = { pMess, MSG_NULL }; + + nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt ); + + if( aEvt.TWMessage != MSG_NULL ) + { + switch( aEvt.TWMessage ) + { + case MSG_XFERREADY: + { + ULONG nEvent = TWAIN_EVENT_QUIT; + + if( 5 == nCurState ) + { + nCurState = 6; + ImplXfer(); + + if( !!aBitmap ) + nEvent = TWAIN_EVENT_XFER; + } + + ImplFallback( nEvent ); + } + break; + + case MSG_CLOSEDSREQ: + ImplFallback( TWAIN_EVENT_QUIT ); + break; + + default: + break; + } + } + else + nRet = TWRC_NOTDSEVENT; + + return( TWRC_DSEVENT == nRet ); +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplXfer() +{ + if( nCurState == 6 ) + { + TW_IMAGEINFO aInfo; + TW_UINT32 hDIB = 0; + long nWidth = aInfo.ImageWidth; + long nHeight = aInfo.ImageLength; + long nXRes = FIXTOLONG( aInfo.XResolution ); + long nYRes = FIXTOLONG( aInfo.YResolution ); + + if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS ) + { + nWidth = aInfo.ImageWidth; + nHeight = aInfo.ImageLength; + nXRes = FIXTOLONG( aInfo.XResolution ); + nYRes = FIXTOLONG( aInfo.YResolution ); + } + else + nWidth = nHeight = nXRes = nYRes = -1L; + + switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) ) + { + case( TWRC_CANCEL ): + nCurState = 7; + break; + + case( TWRC_XFERDONE ): + { +#ifdef OS2 + + // get OS/2-Bitmap + +#else // OS2 + const ULONG nSize = GlobalSize( (HGLOBAL) hDIB ); + char* pBuf = (char*) GlobalLock( (HGLOBAL) hDIB ); + + if( pBuf ) + { + SvMemoryStream aMemStm; + aMemStm.SetBuffer( pBuf, nSize, FALSE, nSize ); + aBitmap.Read( aMemStm, FALSE ); + GlobalUnlock( (HGLOBAL) hDIB ); + } + + GlobalFree( (HGLOBAL) hDIB ); +#endif // OS2 + + // set resolution of bitmap if neccessary + if ( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) ) + { + const MapMode aMapMode( MAP_100TH_INCH, Point(), Fraction( 100, nXRes ), Fraction( 100, nYRes ) ); + aBitmap.SetPrefMapMode( aMapMode ); + aBitmap.SetPrefSize( Size( nWidth, nHeight ) ); + } + + nCurState = 7; + } + break; + + default: + break; + } + } +} + +// ----------------------------------------------------------------------------- + +void ImpTwain::ImplFallback( ULONG nEvent ) +{ + Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent ); +} + +// ----------------------------------------------------------------------------- + +IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData ) +{ + const ULONG nEvent = (ULONG) pData; + BOOL bFallback = TRUE; + + switch( nCurState ) + { + case( 7 ): + case( 6 ): + { + TW_PENDINGXFERS aXfers; + + if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS ) + { + if( aXfers.Count != 0 ) + PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers ); + } + + nCurState = 5; + } + break; + + case( 5 ): + { + TW_USERINTERFACE aUI = { TRUE, TRUE, hTwainWnd }; + + PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI ); + nCurState = 4; + } + break; + + case( 4 ): + { + PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent ); + nCurState = 3; + } + break; + + case( 3 ): + { + PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd ); + nCurState = 2; + } + break; + + case( 2 ): + { + delete pMod; + pMod = NULL; + nCurState = 1; + } + break; + + default: + { + if( nEvent != TWAIN_EVENT_NONE ) + aNotifyLink.Call( (void*) nEvent ); + + bFallback = FALSE; + } + break; + } + + if( bFallback ) + ImplFallback( nEvent ); + + return 0L; +} + +// ----------------------------------------------------------------------------- + +IMPL_LINK( ImpTwain, ImplDestroyHdl, void*, p ) +{ +#ifdef OS2 + + if( hWndTwain ) + WinDestroyWindow( hWndTwain ); + + // unset hook + +#else + + if( hTwainWnd ) + DestroyWindow( hTwainWnd ); + + if( hTwainHook ) + UnhookWindowsHookEx( hTwainHook ); + +#endif + + delete this; + pImpTwainInstance = NULL; + + return 0L; +} diff --git a/extensions/source/scanner/twain.hxx b/extensions/source/scanner/twain.hxx new file mode 100644 index 000000000000..7599f86d7813 --- /dev/null +++ b/extensions/source/scanner/twain.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _TWAIN_HXX +#define _TWAIN_HXX + +#include <vos/module.hxx> +#include <vcl/bitmap.hxx> +#include "twain/twain.h" + + +// ----------- +// - Defines - +// ----------- + +#define TWAIN_SELECT 0x00000001UL +#define TWAIN_ACQUIRE 0x00000002UL +#define TWAIN_TERMINATE 0xFFFFFFFFUL + +#define TWAIN_EVENT_NONE 0x00000000UL +#define TWAIN_EVENT_QUIT 0x00000001UL +#define TWAIN_EVENT_SCANNING 0x00000002UL +#define TWAIN_EVENT_XFER 0x00000004UL + +// ------------ +// - ImpTwain - +// ------------ + +class ImpTwain +{ + TW_IDENTITY aAppIdent; + TW_IDENTITY aSrcIdent; + Link aNotifyLink; + Bitmap aBitmap; + DSMENTRYPROC pDSM; + NAMESPACE_VOS( OModule )* pMod; + ULONG nCurState; + + void ImplCreate(); + void ImplOpenSourceManager(); + void ImplOpenSource(); + BOOL ImplEnableSource(); + void ImplXfer(); + void ImplFallback( ULONG nEvent ); + + DECL_LINK( ImplFallbackHdl, void* ); + DECL_LINK( ImplDestroyHdl, void* ); + +public: + + BOOL ImplHandleMsg( void* pMsg ); + +#ifdef OS2 + HAB hAB; + HWND hTwainWnd; + long hTwainHook; +#else + HWND hTwainWnd; + HHOOK hTwainHook; +#endif + +public: + + ImpTwain( const Link& rNotifyLink ); + ~ImpTwain(); + + void Destroy(); + + BOOL SelectSource(); + BOOL InitXfer(); + Bitmap GetXferBitmap(); +}; + +#endif // _TWAIN_HXX |