summaryrefslogtreecommitdiff
path: root/extensions/source/scanner
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/source/scanner')
-rw-r--r--extensions/source/scanner/exports.dxp3
-rw-r--r--extensions/source/scanner/grid.cxx608
-rw-r--r--extensions/source/scanner/grid.hrc42
-rw-r--r--extensions/source/scanner/grid.hxx149
-rw-r--r--extensions/source/scanner/grid.src112
-rw-r--r--extensions/source/scanner/makefile.mk100
-rw-r--r--extensions/source/scanner/sane.cxx1004
-rw-r--r--extensions/source/scanner/sane.hxx200
-rw-r--r--extensions/source/scanner/sanedlg.cxx1430
-rw-r--r--extensions/source/scanner/sanedlg.hrc82
-rw-r--r--extensions/source/scanner/sanedlg.hxx152
-rw-r--r--extensions/source/scanner/sanedlg.src301
-rw-r--r--extensions/source/scanner/scanner.cxx103
-rw-r--r--extensions/source/scanner/scanner.hxx115
-rw-r--r--extensions/source/scanner/scanunx.cxx352
-rw-r--r--extensions/source/scanner/scanwin.cxx1053
-rw-r--r--extensions/source/scanner/scnserv.cxx104
-rw-r--r--extensions/source/scanner/twain.cxx532
-rw-r--r--extensions/source/scanner/twain.hxx98
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