xref: /AOO41X/main/extensions/source/scanner/sanedlg.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <tools/config.hxx>
34 
35 #include <vcl/msgbox.hxx>
36 #include <sanedlg.hxx>
37 #include <sanedlg.hrc>
38 #include <grid.hxx>
39 #include <math.h>
40 
41 #define USE_SAVE_STATE
42 #undef  SAVE_ALL_STATES
43 
44 ResId SaneResId( sal_uInt32 nID )
45 {
46 	static ResMgr* pResMgr = ResMgr::CreateResMgr( "san" );
47 	return ResId( nID, *pResMgr );
48 }
49 
50 SaneDlg::SaneDlg( Window* pParent, Sane& rSane ) :
51 		ModalDialog( pParent, SaneResId( RID_SANE_DIALOG ) ),
52 		mrSane( rSane ),
53 		mbIsDragging( sal_False ),
54 		mbDragDrawn( sal_False ),
55 		maMapMode( MAP_APPFONT ),
56 		maOKButton( this, SaneResId( RID_SCAN_OK ) ),
57 		maCancelButton( this, SaneResId( RID_SCAN_CANCEL ) ),
58 		maDeviceInfoButton( this, SaneResId( RID_DEVICEINFO_BTN ) ),
59 		maPreviewButton( this, SaneResId( RID_PREVIEW_BTN ) ),
60 		maButtonOption( this, SaneResId( RID_SCAN_BUTTON_OPTION_BTN ) ),
61 		maOptionsTxt( this, SaneResId( RID_SCAN_OPTION_TXT ) ),
62 		maOptionTitle( this, SaneResId( RID_SCAN_OPTIONTITLE_TXT ) ),
63 		maOptionDescTxt( this, SaneResId( RID_SCAN_OPTION_DESC_TXT ) ),
64 		maVectorTxt( this, SaneResId( RID_SCAN_NUMERIC_VECTOR_TXT ) ),
65 		maScanLeftTxt( this, SaneResId( RID_SCAN_LEFT_TXT ) ),
66 		maLeftField( this, SaneResId( RID_SCAN_LEFT_BOX ) ),
67 		maScanTopTxt( this, SaneResId( RID_SCAN_TOP_TXT ) ),
68 		maTopField( this, SaneResId( RID_SCAN_TOP_BOX ) ),
69 		maRightTxt( this, SaneResId( RID_SCAN_RIGHT_TXT ) ),
70 		maRightField( this, SaneResId( RID_SCAN_RIGHT_BOX ) ),
71 		maBottomTxt( this, SaneResId( RID_SCAN_BOTTOM_TXT ) ),
72 		maBottomField( this, SaneResId( RID_SCAN_BOTTOM_BOX ) ),
73 		maDeviceBoxTxt( this, SaneResId( RID_DEVICE_BOX_TXT ) ),
74 		maDeviceBox( this, SaneResId( RID_DEVICE_BOX ) ),
75 		maReslTxt( this, SaneResId( RID_SCAN_RESOLUTION_TXT ) ),
76 		maReslBox( this, SaneResId( RID_SCAN_RESOLUTION_BOX ) ),
77 		maAdvancedTxt( this, SaneResId( RID_SCAN_ADVANCED_TXT ) ),
78 		maAdvancedBox( this, SaneResId( RID_SCAN_ADVANCED_BOX ) ),
79 		maVectorBox( this, SaneResId( RID_SCAN_NUMERIC_VECTOR_BOX ) ),
80 		maQuantumRangeBox( this, SaneResId( RID_SCAN_QUANTUM_RANGE_BOX ) ),
81 		maStringRangeBox( this, SaneResId( RID_SCAN_STRING_RANGE_BOX ) ),
82 		maPreviewBox( this, SaneResId( RID_PREVIEW_BOX ) ),
83 		maAreaBox( this, SaneResId( RID_SCANAREA_BOX ) ),
84 		maBoolCheckBox( this, SaneResId( RID_SCAN_BOOL_OPTION_BOX ) ),
85 		maStringEdit( this, SaneResId( RID_SCAN_STRING_OPTION_EDT ) ),
86 		maNumericEdit( this, SaneResId( RID_SCAN_NUMERIC_OPTION_EDT ) ),
87 		maOptionBox( this, SaneResId( RID_SCAN_OPTION_BOX ) ),
88 		mpRange( 0 )
89 {
90 	if( Sane::IsSane() )
91 	{
92 		InitDevices(); // opens first sane device
93 		DisableOption();
94 		InitFields();
95 	}
96 
97 	maDeviceInfoButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
98 	maPreviewButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
99 	maButtonOption.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
100 	maDeviceBox.SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) );
101 	maOptionBox.SetSelectHdl( LINK( this, SaneDlg, OptionsBoxSelectHdl ) );
102 	maOKButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
103 	maCancelButton.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
104 	maBoolCheckBox.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
105 	maStringEdit.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
106 	maNumericEdit.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
107 	maVectorBox.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
108 	maReslBox.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
109 	maStringRangeBox.SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) );
110 	maQuantumRangeBox.SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) );
111 	maLeftField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
112 	maRightField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
113 	maTopField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
114 	maBottomField.SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
115 	maAdvancedBox.SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
116 
117 	maOldLink = mrSane.SetReloadOptionsHdl( LINK( this, SaneDlg, ReloadSaneOptionsHdl ) );
118 
119 	maOptionBox.SetNodeBitmaps(
120 		Bitmap( SaneResId( RID_SCAN_BITMAP_PLUS ) ),
121 		Bitmap( SaneResId( RID_SCAN_BITMAP_MINUS ) )
122 		);
123 	maOptionBox.SetStyle( maOptionBox.GetStyle()|
124                           WB_HASLINES           |
125 						  WB_HASBUTTONS         |
126 						  WB_NOINITIALSELECTION |
127 						  WB_HASBUTTONSATROOT   |
128 						  WB_HASLINESATROOT
129 						);
130 	FreeResource();
131 }
132 
133 SaneDlg::~SaneDlg()
134 {
135 }
136 
137 short SaneDlg::Execute()
138 {
139 	if( ! Sane::IsSane() )
140 	{
141 		ErrorBox aErrorBox( NULL, WB_OK | WB_DEF_OK,
142 							String( SaneResId( RID_SANE_NOSANELIB_TXT ) ) );
143 		aErrorBox.Execute();
144 		return sal_False;
145 	}
146 	LoadState();
147 	return ModalDialog::Execute();
148 }
149 
150 void SaneDlg::InitDevices()
151 {
152 	if( ! Sane::IsSane() )
153 		return;
154 
155 	if( mrSane.IsOpen() )
156 		mrSane.Close();
157 	mrSane.ReloadDevices();
158 	maDeviceBox.Clear();
159 	for( int i = 0; i < Sane::CountDevices(); i++ )
160 		maDeviceBox.InsertEntry( Sane::GetName( i ) );
161 	if( Sane::CountDevices() )
162 	{
163 		mrSane.Open( 0 );
164 		maDeviceBox.SelectEntry( Sane::GetName( 0 ) );
165 
166 	}
167 }
168 
169 void SaneDlg::InitFields()
170 {
171 	if( ! Sane::IsSane() )
172 		return;
173 
174 	int nOption, i, nValue;
175 	double fValue;
176 	sal_Bool bSuccess = sal_False;
177 	const char *ppSpecialOptions[] = {
178 		"resolution",
179 		"tl-x",
180 		"tl-y",
181 		"br-x",
182 		"br-y",
183 		"preview"
184 	};
185 
186     mbDragEnable = sal_True;
187 	maReslBox.Clear();
188 	maMinTopLeft = Point( 0, 0 );
189 	maMaxBottomRight = Point( PREVIEW_WIDTH,  PREVIEW_HEIGHT );
190 
191 	if( ! mrSane.IsOpen() )
192 		return;
193 
194 	// set Resolution
195 	nOption = mrSane.GetOptionByName( "resolution" );
196 	if( nOption != -1 )
197 	{
198 		double fRes;
199 
200 		bSuccess = mrSane.GetOptionValue( nOption, fRes );
201 		if( bSuccess )
202 		{
203 			maReslBox.Enable( sal_True );
204 
205 			maReslBox.SetValue( (long)fRes );
206 			double *pDouble = NULL;
207 			nValue = mrSane.GetRange( nOption, pDouble );
208 			if( nValue > -1 )
209 			{
210 				if( nValue )
211 				{
212 					maReslBox.SetMin( (long)pDouble[0] );
213 					maReslBox.SetMax( (long)pDouble[ nValue-1 ] );
214 					for( i=0; i<nValue; i++ )
215 					{
216 						if( i == 0 || i == nValue-1 || ! ( ((int)pDouble[i]) % 20) )
217 							maReslBox.InsertValue( (long)pDouble[i] );
218 					}
219 				}
220 				else
221 				{
222 					maReslBox.SetMin( (long)pDouble[0] );
223 					maReslBox.SetMax( (long)pDouble[1] );
224 					maReslBox.InsertValue( (long)pDouble[0] );
225 					// mh@openoffice.org: issue 68557: Can only select 75 and 2400 dpi in Scanner dialogue
226 					// scanner allows random setting of dpi resolution, a slider might be useful
227 					// support that
228 					// workaround: offer at least some more standard dpi resolution between
229 					// min and max value
230 					int bGot300 = 0;
231 					for ( int nRes = (long) pDouble[0] * 2; nRes < (long) pDouble[1]; nRes = nRes * 2 )
232 					{
233 						if ( !bGot300 && nRes > 300 ) {
234 							nRes = 300; bGot300 = 1;
235 						}
236 						maReslBox.InsertValue(nRes);
237 					}
238 					maReslBox.InsertValue( (long)pDouble[1] );
239 				}
240 				if( pDouble )
241 					delete [] pDouble;
242 			}
243 			else
244 				maReslBox.Enable( sal_False );
245 		}
246 	}
247 	else
248 		maReslBox.Enable( sal_False );
249 
250 	// set scan area
251 	for( i = 0; i < 4; i++ )
252 	{
253 		char const *pOptionName = NULL;
254 		MetricField* pField = NULL;
255 		switch( i )
256 		{
257 			case 0:
258 				pOptionName = "tl-x";
259 				pField = &maLeftField;
260 				break;
261 			case 1:
262 				pOptionName = "tl-y";
263 				pField = &maTopField;
264 				break;
265 			case 2:
266 				pOptionName = "br-x";
267 				pField = &maRightField;
268 				break;
269 			case 3:
270 				pOptionName = "br-y";
271 				pField = &maBottomField;
272 		}
273 		nOption = pOptionName ? mrSane.GetOptionByName( pOptionName ) : -1;
274 		bSuccess = sal_False;
275 		if( nOption != -1 )
276 		{
277 			bSuccess = mrSane.GetOptionValue( nOption, fValue, 0 );
278 			if( bSuccess )
279 			{
280 				if( mrSane.GetOptionUnit( nOption ) == SANE_UNIT_MM )
281 				{
282 					pField->SetUnit( FUNIT_MM );
283 					pField->SetValue( (int)fValue, FUNIT_MM );
284 				}
285 				else // SANE_UNIT_PIXEL
286 				{
287 					pField->SetValue( (int)fValue, FUNIT_CUSTOM );
288 					pField->SetCustomUnitText( String::CreateFromAscii( "Pixel" ) );
289 				}
290 				switch( i ) {
291 					case 0: maTopLeft.X() = (int)fValue;break;
292 					case 1:	maTopLeft.Y() = (int)fValue;break;
293 					case 2:	maBottomRight.X() = (int)fValue;break;
294 					case 3: maBottomRight.Y() = (int)fValue;break;
295 				}
296 			}
297 			double *pDouble = NULL;
298 			nValue = mrSane.GetRange( nOption, pDouble );
299 			if( nValue > -1 )
300 			{
301 				if( pDouble )
302 				{
303 					pField->SetMin( (long)pDouble[0] );
304 					if( nValue )
305 						pField->SetMax( (long)pDouble[ nValue-1 ] );
306 					else
307 						pField->SetMax( (long)pDouble[ 1 ] );
308 					delete [] pDouble;
309 				}
310 				switch( i ) {
311 					case 0: maMinTopLeft.X() = pField->GetMin();break;
312 					case 1: maMinTopLeft.Y() = pField->GetMin();break;
313 					case 2: maMaxBottomRight.X() = pField->GetMax();break;
314 					case 3: maMaxBottomRight.Y() = pField->GetMax();break;
315 				}
316 			}
317 			else
318 			{
319 				switch( i ) {
320 					case 0: maMinTopLeft.X() = (int)fValue;break;
321 					case 1: maMinTopLeft.Y() = (int)fValue;break;
322 					case 2: maMaxBottomRight.X() = (int)fValue;break;
323 					case 3: maMaxBottomRight.Y() = (int)fValue;break;
324 				}
325 			}
326 			pField->Enable( sal_True );
327 		}
328 		else
329         {
330             mbDragEnable = sal_False;
331             pField->SetMin( 0 );
332             switch( i ) {
333                 case 0:
334                     maMinTopLeft.X() = 0;
335                     maTopLeft.X() = 0;
336                     pField->SetMax( PREVIEW_WIDTH );
337                     pField->SetValue( 0 );
338                     break;
339                 case 1:
340                     maMinTopLeft.Y() = 0;
341                     maTopLeft.Y() = 0;
342                     pField->SetMax( PREVIEW_HEIGHT );
343                     pField->SetValue( 0 );
344                     break;
345                 case 2:
346                     maMaxBottomRight.X() = PREVIEW_WIDTH;
347                     maBottomRight.X() = PREVIEW_WIDTH;
348                     pField->SetMax( PREVIEW_WIDTH );
349                     pField->SetValue( PREVIEW_WIDTH );
350                     break;
351                 case 3:
352                     maMaxBottomRight.Y() = PREVIEW_HEIGHT;
353                     maBottomRight.Y() = PREVIEW_HEIGHT;
354                     pField->SetMax( PREVIEW_HEIGHT );
355                     pField->SetValue( PREVIEW_HEIGHT );
356                     break;
357             }
358 			pField->Enable( sal_False );
359         }
360 	}
361 	maTopLeft = GetPixelPos( maTopLeft );
362 	maBottomRight = GetPixelPos( maBottomRight );
363 	maPreviewRect = Rectangle( maTopLeft,
364 							   Size( maBottomRight.X() - maTopLeft.X(),
365 									 maBottomRight.Y() - maTopLeft.Y() )
366 							   );
367 	// fill OptionBox
368 	maOptionBox.Clear();
369 	SvLBoxEntry* pParentEntry = 0;
370 	sal_Bool bGroupRejected = sal_False;
371 	for( i = 1; i < mrSane.CountOptions(); i++ )
372 	{
373 		String aOption=mrSane.GetOptionName( i );
374 		sal_Bool bInsertAdvanced =
375 			mrSane.GetOptionCap( i ) & SANE_CAP_ADVANCED &&
376 			! maAdvancedBox.IsChecked() ? sal_False : sal_True;
377 		if( mrSane.GetOptionType( i ) == SANE_TYPE_GROUP )
378 		{
379 			if( bInsertAdvanced )
380 			{
381 				aOption = mrSane.GetOptionTitle( i );
382 				pParentEntry = maOptionBox.InsertEntry( aOption );
383 				bGroupRejected = sal_False;
384 			}
385 			else
386 				bGroupRejected = sal_True;
387 		}
388 		else if( aOption.Len() &&
389 				 ! ( mrSane.GetOptionCap( i ) &
390 					 (
391 						 SANE_CAP_HARD_SELECT |
392 						 SANE_CAP_INACTIVE
393 						 ) ) &&
394 				 bInsertAdvanced && ! bGroupRejected )
395 		{
396 			sal_Bool bIsSpecial = sal_False;
397 			for( size_t n = 0; !bIsSpecial &&
398 					 n < sizeof(ppSpecialOptions)/sizeof(ppSpecialOptions[0]); n++ )
399 			{
400 				if( aOption.EqualsAscii( ppSpecialOptions[n] ) )
401 					bIsSpecial=sal_True;
402 			}
403 			if( ! bIsSpecial )
404 			{
405 				if( pParentEntry )
406 					maOptionBox.InsertEntry( aOption, pParentEntry );
407 				else
408 					maOptionBox.InsertEntry( aOption );
409 			}
410 		}
411 	}
412 }
413 
414 IMPL_LINK( SaneDlg, ClickBtnHdl, Button*, pButton )
415 {
416 	if( mrSane.IsOpen() )
417 	{
418 		if( pButton == &maDeviceInfoButton )
419 		{
420 			String aString( SaneResId( RID_SANE_DEVICEINFO_TXT ) );
421 			String aSR( RTL_CONSTASCII_USTRINGPARAM( "%s" ) );
422 			aString.SearchAndReplace( aSR, Sane::GetName( mrSane.GetDeviceNumber() ) );
423 			aString.SearchAndReplace( aSR, Sane::GetVendor( mrSane.GetDeviceNumber() ) );
424 			aString.SearchAndReplace( aSR, Sane::GetModel( mrSane.GetDeviceNumber() ) );
425 			aString.SearchAndReplace( aSR, Sane::GetType( mrSane.GetDeviceNumber() ) );
426 			InfoBox aInfoBox( this, aString );
427 			aInfoBox.Execute();
428 		}
429 		else if( pButton == &maPreviewButton )
430 			AcquirePreview();
431 		else if( pButton == &maBoolCheckBox )
432 		{
433 			mrSane.SetOptionValue( mnCurrentOption,
434 								   maBoolCheckBox.IsChecked() ?
435 								   (sal_Bool)sal_True : (sal_Bool)sal_False );
436 		}
437 		else if( pButton == &maButtonOption )
438 		{
439 
440 			SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption );
441             switch( nType )
442             {
443                 case SANE_TYPE_BUTTON:
444                     mrSane.ActivateButtonOption( mnCurrentOption );
445                     break;
446                 case SANE_TYPE_FIXED:
447                 case SANE_TYPE_INT:
448                 {
449 					int nElements = mrSane.GetOptionElements( mnCurrentOption );
450                     double* x = new double[ nElements ];
451                     double* y = new double[ nElements ];
452                     for( int i = 0; i < nElements; i++ )
453                         x[ i ] = (double)i;
454                     mrSane.GetOptionValue( mnCurrentOption, y );
455 
456                     GridWindow aGrid( x, y, nElements, this );
457                     aGrid.SetText( mrSane.GetOptionName( mnCurrentOption ) );
458                     aGrid.setBoundings( 0, mfMin, nElements, mfMax );
459                     if( aGrid.Execute() && aGrid.getNewYValues() )
460                         mrSane.SetOptionValue( mnCurrentOption, aGrid.getNewYValues() );
461 
462                     delete [] x;
463                     delete [] y;
464                 }
465                 break;
466                 case SANE_TYPE_BOOL:
467                 case SANE_TYPE_STRING:
468                 case SANE_TYPE_GROUP:
469                     break;
470             }
471 		}
472 		else if( pButton == &maAdvancedBox )
473 		{
474 			ReloadSaneOptionsHdl( NULL );
475 		}
476 	}
477 	if( pButton == &maOKButton )
478 	{
479 		double fRes = (double)maReslBox.GetValue();
480 		SetAdjustedNumericalValue( "resolution", fRes );
481 		mrSane.SetReloadOptionsHdl( maOldLink );
482 		UpdateScanArea( sal_True );
483 		SaveState();
484 		EndDialog( mrSane.IsOpen() ? 1 : 0 );
485 	}
486 	else if( pButton == &maCancelButton )
487 	{
488 		mrSane.SetReloadOptionsHdl( maOldLink );
489 		mrSane.Close();
490 		EndDialog( 0 );
491 	}
492 	return 0;
493 }
494 
495 IMPL_LINK( SaneDlg, SelectHdl, ListBox*, pListBox )
496 {
497 	if( pListBox == &maDeviceBox && Sane::IsSane() && Sane::CountDevices() )
498 	{
499 		String aNewDevice = maDeviceBox.GetSelectEntry();
500 		int nNumber;
501 		if( aNewDevice.Equals( Sane::GetName( nNumber = mrSane.GetDeviceNumber() ) ) )
502 		{
503 			mrSane.Close();
504 			mrSane.Open( nNumber );
505 			InitFields();
506 		}
507 	}
508 	if( mrSane.IsOpen() )
509 	{
510 		if( pListBox == &maQuantumRangeBox )
511 		{
512 			ByteString aValue( maQuantumRangeBox.GetSelectEntry(), osl_getThreadTextEncoding() );
513 			double fValue = atof( aValue.GetBuffer() );
514 			mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement );
515 		}
516 		else if( pListBox == &maStringRangeBox )
517 		{
518 			mrSane.SetOptionValue( mnCurrentOption, maStringRangeBox.GetSelectEntry() );
519 		}
520 	}
521 	return 0;
522 }
523 
524 IMPL_LINK( SaneDlg, OptionsBoxSelectHdl, SvTreeListBox*, pBox )
525 {
526 	if( pBox == &maOptionBox && Sane::IsSane() )
527 	{
528 		String aOption =
529 			maOptionBox.GetEntryText( maOptionBox.FirstSelected() );
530 		int nOption = mrSane.GetOptionByName( ByteString( aOption, osl_getThreadTextEncoding() ).GetBuffer() );
531 		if( nOption != -1 && nOption != mnCurrentOption )
532 		{
533 			DisableOption();
534 			mnCurrentOption = nOption;
535 			maOptionTitle.SetText( mrSane.GetOptionTitle( mnCurrentOption ) );
536 			SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption );
537 			SANE_Constraint_Type nConstraint;
538 			switch( nType )
539 			{
540 				case SANE_TYPE_BOOL:	EstablishBoolOption();break;
541 				case SANE_TYPE_STRING:
542 					nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption );
543 					if( nConstraint == SANE_CONSTRAINT_STRING_LIST )
544 						EstablishStringRange();
545 					else
546 						EstablishStringOption();
547 					break;
548 				case SANE_TYPE_FIXED:
549 				case SANE_TYPE_INT:
550 				{
551 					nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption );
552 					int nElements = mrSane.GetOptionElements( mnCurrentOption );
553 					mnCurrentElement = 0;
554                     if( nConstraint == SANE_CONSTRAINT_RANGE ||
555                         nConstraint == SANE_CONSTRAINT_WORD_LIST )
556                         EstablishQuantumRange();
557                     else
558                     {
559                         mfMin = mfMax = 0.0;
560                         EstablishNumericOption();
561                     }
562 					if( nElements > 1 )
563 					{
564 						if( nElements <= 10 )
565 						{
566 							maVectorBox.SetValue( 1 );
567 							maVectorBox.SetMin( 1 );
568 							maVectorBox.SetMax(
569 								mrSane.GetOptionElements( mnCurrentOption ) );
570 							maVectorBox.Show( sal_True );
571 							maVectorTxt.Show( sal_True );
572 						}
573 						else
574 						{
575                             DisableOption();
576                             // bring up dialog only on button click
577                             EstablishButtonOption();
578 						}
579 					}
580 				}
581 				break;
582 				case SANE_TYPE_BUTTON:
583 					EstablishButtonOption();
584 					break;
585 				default: break;
586 			}
587 		}
588 	}
589 	return 0;
590 }
591 
592 IMPL_LINK( SaneDlg, ModifyHdl, Edit*, pEdit )
593 {
594 	if( mrSane.IsOpen() )
595 	{
596 		if( pEdit == &maStringEdit )
597 		{
598 			mrSane.SetOptionValue( mnCurrentOption, maStringEdit.GetText() );
599 		}
600 		else if( pEdit == &maReslBox )
601 		{
602 			double fRes = (double)maReslBox.GetValue();
603 			int nOption = mrSane.GetOptionByName( "resolution" );
604 			if( nOption != -1 )
605 			{
606 				double* pDouble = NULL;
607 				int nValues = mrSane.GetRange( nOption, pDouble );
608 				if( nValues > 0 )
609 				{
610 					int i;
611 					for( i = 0; i < nValues; i++ )
612 					{
613 						if( fRes == pDouble[i] )
614 							break;
615 					}
616 					if( i >= nValues )
617 						fRes = pDouble[0];
618 				}
619 				else if( nValues == 0 )
620 				{
621 					if( fRes < pDouble[ 0 ] )
622 						fRes = pDouble[ 0 ];
623 					if( fRes > pDouble[ 1 ] )
624 						fRes = pDouble[ 1 ];
625 				}
626 				maReslBox.SetValue( (sal_uLong)fRes );
627 			}
628 		}
629 		else if( pEdit == &maNumericEdit )
630 		{
631 			double fValue;
632 			char pBuf[256];
633 			ByteString aContents( maNumericEdit.GetText(), osl_getThreadTextEncoding() );
634 			fValue = atof( aContents.GetBuffer() );
635 			if( mfMin != mfMax && ( fValue < mfMin || fValue > mfMax ) )
636 			{
637 				if( fValue < mfMin )
638 					fValue = mfMin;
639 				else if( fValue > mfMax )
640 				fValue = mfMax;
641 				sprintf( pBuf, "%g", fValue );
642 				maNumericEdit.SetText( String( pBuf, osl_getThreadTextEncoding() ) );
643 			}
644 			mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement );
645 		}
646 		else if( pEdit == &maVectorBox )
647 		{
648 			char pBuf[256];
649 			mnCurrentElement = maVectorBox.GetValue()-1;
650 			double fValue;
651 			mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement );
652 			sprintf( pBuf, "%g", fValue );
653 			String aValue( pBuf, osl_getThreadTextEncoding() );
654 			maNumericEdit.SetText( aValue );
655 			maQuantumRangeBox.SelectEntry( aValue );
656 		}
657 		else if( pEdit == &maTopField )
658 		{
659 			Point aPoint( 0, maTopField.GetValue() );
660 			aPoint = GetPixelPos( aPoint );
661 			maTopLeft.Y() = aPoint.Y();
662 			DrawDrag();
663 		}
664 		else if( pEdit == &maLeftField )
665 		{
666 			Point aPoint( maLeftField.GetValue(), 0 );
667 			aPoint = GetPixelPos( aPoint );
668 			maTopLeft.X() = aPoint.X();
669 			DrawDrag();
670 		}
671 		else if( pEdit == &maBottomField )
672 		{
673 			Point aPoint( 0, maBottomField.GetValue() );
674 			aPoint = GetPixelPos( aPoint );
675 			maBottomRight.Y() = aPoint.Y();
676 			DrawDrag();
677 		}
678 		else if( pEdit == &maRightField )
679 		{
680 			Point aPoint( maRightField.GetValue(), 0 );
681 			aPoint = GetPixelPos( aPoint );
682 			maBottomRight.X() = aPoint.X();
683 			DrawDrag();
684 		}
685 	}
686 	return 0;
687 }
688 
689 IMPL_LINK( SaneDlg, ReloadSaneOptionsHdl, Sane*, /*pSane*/ )
690 {
691  	mnCurrentOption = -1;
692  	mnCurrentElement = 0;
693  	DisableOption();
694     // #92024# preserve preview rect, should only be set
695     // initially or in AcquirePreview
696     Rectangle aPreviewRect = maPreviewRect;
697 	InitFields();
698     maPreviewRect = aPreviewRect;
699 	Rectangle aDummyRect( Point( 0, 0 ), GetSizePixel() );
700 	Paint( aDummyRect );
701 	return 0;
702 }
703 
704 void SaneDlg::AcquirePreview()
705 {
706 	if( ! mrSane.IsOpen() )
707 		return;
708 
709 	UpdateScanArea( sal_True );
710 	// set small resolution for preview
711 	double fResl = (double)maReslBox.GetValue();
712 	SetAdjustedNumericalValue( "resolution", 30.0 );
713 
714 	int nOption = mrSane.GetOptionByName( "preview" );
715 	if( nOption == -1 )
716 	{
717 		String aString( SaneResId( RID_SANE_NORESOLUTIONOPTION_TXT ) );
718 		WarningBox aBox( this, WB_OK_CANCEL | WB_DEF_OK, aString );
719 		if( aBox.Execute() == RET_CANCEL )
720 			return;
721 	}
722 	else
723 		mrSane.SetOptionValue( nOption, (sal_Bool)sal_True );
724 
725 	BitmapTransporter aTransporter;
726 	if( ! mrSane.Start( aTransporter ) )
727 	{
728 		ErrorBox aErrorBox( this, WB_OK | WB_DEF_OK,
729 							String( SaneResId( RID_SANE_SCANERROR_TXT ) ) );
730 		aErrorBox.Execute();
731 	}
732 	else
733 	{
734 #if OSL_DEBUG_LEVEL > 1
735 		aTransporter.getStream().Seek( STREAM_SEEK_TO_END );
736 		fprintf( stderr, "Previewbitmapstream contains %d bytes\n", (int)aTransporter.getStream().Tell() );
737 #endif
738 		aTransporter.getStream().Seek( STREAM_SEEK_TO_BEGIN );
739 		maPreviewBitmap.Read( aTransporter.getStream(), sal_True );
740 	}
741 
742 	SetAdjustedNumericalValue( "resolution", fResl );
743 	maReslBox.SetValue( (sal_uLong)fResl );
744 
745     if( mbDragEnable )
746         maPreviewRect = Rectangle( maTopLeft,
747                                    Size( maBottomRight.X() - maTopLeft.X(),
748                                          maBottomRight.Y() - maTopLeft.Y() )
749                                    );
750     else
751     {
752         Size aBMSize( maPreviewBitmap.GetSizePixel() );
753         if( aBMSize.Width() > aBMSize.Height() )
754         {
755             int nVHeight = (maBottomRight.X() - maTopLeft.X()) * aBMSize.Height() / aBMSize.Width();
756             maPreviewRect = Rectangle( Point( maTopLeft.X(), ( maTopLeft.Y() + maBottomRight.Y() )/2 - nVHeight/2 ),
757                                        Size( maBottomRight.X() - maTopLeft.X(),
758                                              nVHeight ) );
759         }
760         else
761         {
762             int nVWidth = (maBottomRight.Y() - maTopLeft.Y()) * aBMSize.Width() / aBMSize.Height();
763             maPreviewRect = Rectangle( Point( ( maTopLeft.X() + maBottomRight.X() )/2 - nVWidth/2, maTopLeft.Y() ),
764                                        Size( nVWidth,
765                                              maBottomRight.Y() - maTopLeft.Y() ) );
766         }
767     }
768 
769 	Paint( Rectangle( Point( 0, 0 ), GetSizePixel() ) );
770 }
771 
772 void SaneDlg::Paint( const Rectangle& rRect )
773 {
774 	SetMapMode( maMapMode );
775 	SetFillColor( Color( COL_WHITE ) );
776 	SetLineColor( Color( COL_WHITE ) );
777 	DrawRect( Rectangle( Point( PREVIEW_UPPER_LEFT, PREVIEW_UPPER_TOP ),
778 						 Size( PREVIEW_WIDTH, PREVIEW_HEIGHT ) ) );
779 	SetMapMode( MapMode( MAP_PIXEL ) );
780 	// check for sane values
781 	DrawBitmap( maPreviewRect.TopLeft(), maPreviewRect.GetSize(),
782 				maPreviewBitmap );
783 
784 	mbDragDrawn = sal_False;
785 	DrawDrag();
786 
787 	ModalDialog::Paint( rRect );
788 }
789 
790 void SaneDlg::DisableOption()
791 {
792 	maBoolCheckBox.Show( sal_False );
793 	maStringEdit.Show( sal_False );
794 	maNumericEdit.Show( sal_False );
795 	maQuantumRangeBox.Show( sal_False );
796 	maStringRangeBox.Show( sal_False );
797 	maButtonOption.Show( sal_False );
798 	maVectorBox.Show( sal_False );
799 	maVectorTxt.Show( sal_False );
800 	maOptionDescTxt.Show( sal_False );
801 }
802 
803 void SaneDlg::EstablishBoolOption()
804 {
805 	sal_Bool bSuccess, bValue;
806 
807 	bSuccess = mrSane.GetOptionValue( mnCurrentOption, bValue );
808 	if( bSuccess )
809 	{
810 		maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) );
811 		maOptionDescTxt.Show( sal_True );
812 		maBoolCheckBox.Check( bValue );
813 		maBoolCheckBox.Show( sal_True );
814 	}
815 }
816 
817 void SaneDlg::EstablishStringOption()
818 {
819 	sal_Bool bSuccess;
820 	ByteString aValue;
821 
822 	bSuccess = mrSane.GetOptionValue( mnCurrentOption, aValue );
823 	if( bSuccess )
824 	{
825 		maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) );
826 		maOptionDescTxt.Show( sal_True );
827 		maStringEdit.SetText( String( aValue, osl_getThreadTextEncoding() ) );
828 		maStringEdit.Show( sal_True );
829 	}
830 }
831 
832 void SaneDlg::EstablishStringRange()
833 {
834 	const char** ppStrings = mrSane.GetStringConstraint( mnCurrentOption );
835 	maStringRangeBox.Clear();
836 	for( int i = 0; ppStrings[i] != 0; i++ )
837 		maStringRangeBox.InsertEntry( String( ppStrings[i], osl_getThreadTextEncoding() ) );
838 	ByteString aValue;
839 	mrSane.GetOptionValue( mnCurrentOption, aValue );
840 	maStringRangeBox.SelectEntry( String( aValue, osl_getThreadTextEncoding() ) );
841 	maStringRangeBox.Show( sal_True );
842 	maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) );
843 	maOptionDescTxt.Show( sal_True );
844 }
845 
846 void SaneDlg::EstablishQuantumRange()
847 {
848 	if( mpRange )
849 	{
850 		delete [] mpRange;
851 		mpRange = 0;
852 	}
853 	int nValues = mrSane.GetRange( mnCurrentOption, mpRange );
854 	if( nValues == 0 )
855 	{
856 		mfMin = mpRange[ 0 ];
857 		mfMax = mpRange[ 1 ];
858 		delete [] mpRange;
859 		mpRange = 0;
860 		EstablishNumericOption();
861 	}
862 	else if( nValues > 0 )
863 	{
864 		char pBuf[ 256 ];
865 		maQuantumRangeBox.Clear();
866 		mfMin = mpRange[ 0 ];
867 		mfMax = mpRange[ nValues-1 ];
868 		for( int i = 0; i < nValues; i++ )
869 		{
870 			sprintf( pBuf, "%g", mpRange[ i ] );
871 			maQuantumRangeBox.InsertEntry( String( pBuf, osl_getThreadTextEncoding() ) );
872 		}
873 		double fValue;
874 		if( mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement ) )
875 		{
876 			sprintf( pBuf, "%g", fValue );
877 			maQuantumRangeBox.SelectEntry( String( pBuf, osl_getThreadTextEncoding() ) );
878 		}
879 		maQuantumRangeBox.Show( sal_True );
880 		String aText( mrSane.GetOptionName( mnCurrentOption ) );
881 		aText += ' ';
882 		aText += mrSane.GetOptionUnitName( mnCurrentOption );
883 		maOptionDescTxt.SetText( aText );
884 		maOptionDescTxt.Show( sal_True );
885 	}
886 }
887 
888 void SaneDlg::EstablishNumericOption()
889 {
890 	sal_Bool bSuccess;
891 	double fValue;
892 
893 	bSuccess = mrSane.GetOptionValue( mnCurrentOption, fValue );
894 	if( ! bSuccess )
895 		return;
896 
897 	char pBuf[256];
898 	String aText( mrSane.GetOptionName( mnCurrentOption ) );
899 	aText += ' ';
900 	aText += mrSane.GetOptionUnitName( mnCurrentOption );
901 	if( mfMin != mfMax )
902 	{
903 		sprintf( pBuf, " < %g ; %g >", mfMin, mfMax );
904 		aText += String( pBuf, osl_getThreadTextEncoding() );
905 	}
906 	maOptionDescTxt.SetText( aText );
907 	maOptionDescTxt.Show( sal_True );
908 	sprintf( pBuf, "%g", fValue );
909 	maNumericEdit.SetText( String( pBuf, osl_getThreadTextEncoding() ) );
910 	maNumericEdit.Show( sal_True );
911 }
912 
913 void SaneDlg::EstablishButtonOption()
914 {
915 	maOptionDescTxt.SetText( mrSane.GetOptionName( mnCurrentOption ) );
916 	maOptionDescTxt.Show( sal_True );
917 	maButtonOption.Show( sal_True );
918 }
919 
920 #define RECT_SIZE_PIX 7
921 
922 void SaneDlg::MouseMove( const MouseEvent& rMEvt )
923 {
924 	if( mbIsDragging )
925 	{
926 		Point aMousePos = rMEvt.GetPosPixel();
927 		// move into valid area
928 		Point aLogicPos = GetLogicPos( aMousePos );
929 		aMousePos = GetPixelPos( aLogicPos );
930 		switch( meDragDirection )
931 		{
932 			case TopLeft:		maTopLeft = aMousePos; break;
933 			case Top:			maTopLeft.Y() = aMousePos.Y(); break;
934 			case TopRight:
935 				maTopLeft.Y() = aMousePos.Y();
936 				maBottomRight.X() = aMousePos.X();
937 				break;
938 			case Right:			maBottomRight.X() = aMousePos.X(); break;
939 			case BottomRight:	maBottomRight = aMousePos; break;
940 			case Bottom:		maBottomRight.Y() = aMousePos.Y(); break;
941 			case BottomLeft:
942 				maTopLeft.X() = aMousePos.X();
943 				maBottomRight.Y() = aMousePos.Y();
944 				break;
945 			case Left:			maTopLeft.X() = aMousePos.X(); break;
946 			default: break;
947 		}
948 		int nSwap;
949 		if( maTopLeft.X() > maBottomRight.X() )
950 		{
951 			nSwap = maTopLeft.X();
952 			maTopLeft.X() = maBottomRight.X();
953 			maBottomRight.X() = nSwap;
954 		}
955 		if( maTopLeft.Y() > maBottomRight.Y() )
956 		{
957 			nSwap = maTopLeft.Y();
958 			maTopLeft.Y() = maBottomRight.Y();
959 			maBottomRight.Y() = nSwap;
960 		}
961 		DrawDrag();
962 		UpdateScanArea( sal_False );
963 	}
964 	ModalDialog::MouseMove( rMEvt );
965 }
966 
967 void SaneDlg::MouseButtonDown( const MouseEvent& rMEvt )
968 {
969 	Point aMousePixel = rMEvt.GetPosPixel();
970 
971 	if( ! mbIsDragging  && mbDragEnable )
972 	{
973 		int nMiddleX = ( maBottomRight.X() - maTopLeft.X() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.X();
974 		int nMiddleY = ( maBottomRight.Y() - maTopLeft.Y() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.Y();
975 		if( aMousePixel.Y() >= maTopLeft.Y() &&
976 			aMousePixel.Y() < maTopLeft.Y() + RECT_SIZE_PIX )
977 		{
978 			if( aMousePixel.X() >= maTopLeft.X() &&
979 				aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
980 			{
981 				meDragDirection = TopLeft;
982 				aMousePixel = maTopLeft;
983 				mbIsDragging = sal_True;
984 			}
985 			else if( aMousePixel.X() >= nMiddleX &&
986 					 aMousePixel.X() < nMiddleX + RECT_SIZE_PIX )
987 			{
988 				meDragDirection = Top;
989 				aMousePixel.Y() = maTopLeft.Y();
990 				mbIsDragging = sal_True;
991 			}
992 			else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
993 					 aMousePixel.X() <= maBottomRight.X() )
994 			{
995 				meDragDirection = TopRight;
996 				aMousePixel = Point( maBottomRight.X(), maTopLeft.Y() );
997 				mbIsDragging = sal_True;
998 			}
999 		}
1000 		else if( aMousePixel.Y() >= nMiddleY &&
1001 				 aMousePixel.Y() < nMiddleY + RECT_SIZE_PIX )
1002 		{
1003 			if( aMousePixel.X() >= maTopLeft.X() &&
1004 				aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1005 			{
1006 				meDragDirection = Left;
1007 				aMousePixel.X() = maTopLeft.X();
1008 				mbIsDragging = sal_True;
1009 			}
1010 			else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1011 					 aMousePixel.X() <= maBottomRight.X() )
1012 			{
1013 				meDragDirection = Right;
1014 				aMousePixel.X() = maBottomRight.X();
1015 				mbIsDragging = sal_True;
1016 			}
1017 		}
1018 		else if( aMousePixel.Y() <= maBottomRight.Y() &&
1019 				 aMousePixel.Y() > maBottomRight.Y() - RECT_SIZE_PIX )
1020 		{
1021 			if( aMousePixel.X() >= maTopLeft.X() &&
1022 				aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1023 			{
1024 				meDragDirection = BottomLeft;
1025 				aMousePixel = Point( maTopLeft.X(), maBottomRight.Y() );
1026 				mbIsDragging = sal_True;
1027 			}
1028 			else if( aMousePixel.X() >= nMiddleX &&
1029 					 aMousePixel.X() < nMiddleX + RECT_SIZE_PIX )
1030 			{
1031 				meDragDirection = Bottom;
1032 				aMousePixel.Y() = maBottomRight.Y();
1033 				mbIsDragging = sal_True;
1034 			}
1035 			else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1036 					 aMousePixel.X() <= maBottomRight.X() )
1037 			{
1038 				meDragDirection = BottomRight;
1039 				aMousePixel = maBottomRight;
1040 				mbIsDragging = sal_True;
1041 			}
1042 		}
1043 	}
1044 	if( mbIsDragging )
1045 	{
1046 		SetPointerPosPixel( aMousePixel );
1047 		DrawDrag();
1048 	}
1049 	ModalDialog::MouseButtonDown( rMEvt );
1050 }
1051 
1052 void SaneDlg::MouseButtonUp( const MouseEvent& rMEvt )
1053 {
1054 	if( mbIsDragging )
1055 	{
1056 		UpdateScanArea( sal_True );
1057 	}
1058 	mbIsDragging = sal_False;
1059 
1060 	ModalDialog::MouseButtonUp( rMEvt );
1061 }
1062 
1063 void SaneDlg::DrawRectangles( Point& rUL, Point& rBR )
1064 {
1065 	int nMiddleX, nMiddleY;
1066 	Point aBL, aUR;
1067 
1068 	aUR = Point( rBR.X(), rUL.Y() );
1069 	aBL = Point( rUL.X(), rBR.Y() );
1070 	nMiddleX = ( rBR.X() - rUL.X() ) / 2 + rUL.X();
1071 	nMiddleY = ( rBR.Y() - rUL.Y() ) / 2 + rUL.Y();
1072 
1073 	DrawLine( rUL, aBL );
1074 	DrawLine( aBL, rBR );
1075 	DrawLine( rBR, aUR );
1076 	DrawLine( aUR, rUL );
1077 	DrawRect( Rectangle( rUL, Size( RECT_SIZE_PIX,RECT_SIZE_PIX ) ) );
1078 	DrawRect( Rectangle( aBL, Size( RECT_SIZE_PIX, -RECT_SIZE_PIX ) ) );
1079 	DrawRect( Rectangle( rBR, Size( -RECT_SIZE_PIX, -RECT_SIZE_PIX ) ) );
1080 	DrawRect( Rectangle( aUR, Size( -RECT_SIZE_PIX, RECT_SIZE_PIX ) ) );
1081 	DrawRect( Rectangle( Point( nMiddleX - RECT_SIZE_PIX/2, rUL.Y() ), Size( RECT_SIZE_PIX, RECT_SIZE_PIX ) ) );
1082 	DrawRect( Rectangle( Point( nMiddleX - RECT_SIZE_PIX/2, rBR.Y() ), Size( RECT_SIZE_PIX, -RECT_SIZE_PIX ) ) );
1083 	DrawRect( Rectangle( Point( rUL.X(), nMiddleY - RECT_SIZE_PIX/2 ), Size( RECT_SIZE_PIX, RECT_SIZE_PIX ) ) );
1084 	DrawRect( Rectangle( Point( rBR.X(), nMiddleY - RECT_SIZE_PIX/2 ), Size( -RECT_SIZE_PIX, RECT_SIZE_PIX ) ) );
1085 }
1086 
1087 void SaneDlg::DrawDrag()
1088 {
1089 	static Point aLastUL, aLastBR;
1090 
1091     if( ! mbDragEnable )
1092         return;
1093 
1094 	RasterOp eROP = GetRasterOp();
1095 	SetRasterOp( ROP_INVERT );
1096 	SetMapMode( MapMode( MAP_PIXEL ) );
1097 
1098 	if( mbDragDrawn )
1099 		DrawRectangles( aLastUL, aLastBR );
1100 
1101 	aLastUL = maTopLeft;
1102 	aLastBR = maBottomRight;
1103 	DrawRectangles( maTopLeft, maBottomRight );
1104 
1105 	mbDragDrawn = sal_True;
1106 	SetRasterOp( eROP );
1107 	SetMapMode( maMapMode );
1108 }
1109 
1110 Point SaneDlg::GetPixelPos( const Point& rIn )
1111 {
1112 	Point aConvert(
1113 		( ( rIn.X() * PREVIEW_WIDTH ) /
1114 		  ( maMaxBottomRight.X() - maMinTopLeft.X() ) )
1115 		+ PREVIEW_UPPER_LEFT,
1116 		( ( rIn.Y() * PREVIEW_HEIGHT )
1117 		  / ( maMaxBottomRight.Y() - maMinTopLeft.Y() ) )
1118 		+ PREVIEW_UPPER_TOP );
1119 
1120 	return LogicToPixel( aConvert, maMapMode );
1121 }
1122 
1123 Point SaneDlg::GetLogicPos( const Point& rIn )
1124 {
1125 	Point aConvert = PixelToLogic( rIn, maMapMode );
1126 	aConvert.X() -= PREVIEW_UPPER_LEFT;
1127 	aConvert.Y() -= PREVIEW_UPPER_TOP;
1128 	if( aConvert.X() < 0 )
1129 		aConvert.X() = 0;
1130 	if( aConvert.X() >= PREVIEW_WIDTH )
1131 		aConvert.X() = PREVIEW_WIDTH-1;
1132 	if( aConvert.Y() < 0 )
1133 		aConvert.Y() = 0;
1134 	if( aConvert.Y() >= PREVIEW_HEIGHT )
1135 		aConvert.Y() = PREVIEW_HEIGHT-1;
1136 
1137 	aConvert.X() *= ( maMaxBottomRight.X() - maMinTopLeft.X() );
1138 	aConvert.X() /= PREVIEW_WIDTH;
1139 	aConvert.Y() *= ( maMaxBottomRight.Y() - maMinTopLeft.Y() );
1140 	aConvert.Y() /= PREVIEW_HEIGHT;
1141 	return aConvert;
1142 }
1143 
1144 void SaneDlg::UpdateScanArea( sal_Bool bSend )
1145 {
1146     if( ! mbDragEnable )
1147         return;
1148 
1149 	Point aUL = GetLogicPos( maTopLeft );
1150 	Point aBR = GetLogicPos( maBottomRight );
1151 
1152 	maLeftField.SetValue( aUL.X() );
1153 	maTopField.SetValue( aUL.Y() );
1154 	maRightField.SetValue( aBR.X() );
1155 	maBottomField.SetValue( aBR.Y() );
1156 
1157 	if( ! bSend )
1158 		return;
1159 
1160 	if( mrSane.IsOpen() )
1161 	{
1162 		SetAdjustedNumericalValue( "tl-x", (double)aUL.X() );
1163 		SetAdjustedNumericalValue( "tl-y", (double)aUL.Y() );
1164 		SetAdjustedNumericalValue( "br-x", (double)aBR.X() );
1165 		SetAdjustedNumericalValue( "br-y", (double)aBR.Y() );
1166 	}
1167 }
1168 
1169 sal_Bool SaneDlg::LoadState()
1170 {
1171 #ifdef USE_SAVE_STATE
1172 	int i;
1173 
1174 	if( ! Sane::IsSane() )
1175 		return sal_False;
1176 
1177 	const char* pEnv = getenv("HOME");
1178 	String aFileName( pEnv ? pEnv : "", osl_getThreadTextEncoding() );
1179 	aFileName += String( RTL_CONSTASCII_USTRINGPARAM( "/.so_sane_state" ) );
1180 	Config aConfig( aFileName );
1181 	if( ! aConfig.HasGroup( "SANE" ) )
1182 		return sal_False;
1183 
1184 	aConfig.SetGroup( "SANE" );
1185 	ByteString aString = aConfig.ReadKey( "SO_LastSaneDevice" );
1186 	for( i = 0; i < Sane::CountDevices() && ! aString.Equals( ByteString( Sane::GetName( i ), osl_getThreadTextEncoding() ) ); i++ ) ;
1187 	if( i == Sane::CountDevices() )
1188 		return sal_False;
1189 
1190 	mrSane.Close();
1191 	mrSane.Open( aString.GetBuffer() );
1192 
1193 	DisableOption();
1194 	InitFields();
1195 
1196 	if( mrSane.IsOpen() )
1197 	{
1198 		int iMax = aConfig.GetKeyCount();
1199 		for( i = 0; i < iMax; i++ )
1200 		{
1201 			aString = aConfig.GetKeyName( i );
1202 			ByteString aValue = aConfig.ReadKey( i );
1203 			int nOption = mrSane.GetOptionByName( aString.GetBuffer() );
1204 			if( nOption != -1 )
1205 			{
1206 				if( aValue.CompareTo( "BOOL=", 5 ) == COMPARE_EQUAL )
1207 				{
1208 					aValue.Erase( 0, 5 );
1209 					sal_Bool aBOOL = (sal_Bool)aValue.ToInt32();
1210 					mrSane.SetOptionValue( nOption, aBOOL );
1211 				}
1212 				else if( aValue.CompareTo( "STRING=", 7 ) == COMPARE_EQUAL )
1213 				{
1214 					aValue.Erase( 0, 7 );
1215 					mrSane.SetOptionValue( nOption, String( aValue, osl_getThreadTextEncoding() ) );
1216 				}
1217 				else if( aValue.CompareTo( "NUMERIC=", 8 ) == COMPARE_EQUAL )
1218 				{
1219 					aValue.Erase( 0, 8 );
1220 					int nMax = aValue.GetTokenCount( ':' );
1221 					double fValue=0.0;
1222 					for( int n = 0; n < nMax ; n++ )
1223 					{
1224 						ByteString aSub = aValue.GetToken( n, ':' );
1225 						sscanf( aSub.GetBuffer(), "%lg", &fValue );
1226 						SetAdjustedNumericalValue( aString.GetBuffer(), fValue, n );
1227 					}
1228 				}
1229 			}
1230 		}
1231 	}
1232 
1233 	DisableOption();
1234 	InitFields();
1235 
1236 	return sal_True;
1237 #else
1238 	return sal_False;
1239 #endif
1240 }
1241 
1242 void SaneDlg::SaveState()
1243 {
1244 #ifdef USE_SAVE_STATE
1245 	if( ! Sane::IsSane() )
1246 		return;
1247 
1248 	const char* pEnv = getenv( "HOME" );
1249 	String aFileName( pEnv ? pEnv : "", osl_getThreadTextEncoding() );
1250 	aFileName.AppendAscii( "/.so_sane_state" );
1251 
1252 	Config aConfig( aFileName );
1253 	aConfig.DeleteGroup( "SANE" );
1254 	aConfig.SetGroup( "SANE" );
1255 	aConfig.WriteKey( "SO_LastSANEDevice", ByteString( maDeviceBox.GetSelectEntry(), RTL_TEXTENCODING_UTF8 ) );
1256 
1257 #ifdef SAVE_ALL_STATES
1258 	for( int i = 1; i < mrSane.CountOptions(); i++ )
1259 	{
1260 		String aOption=mrSane.GetOptionName( i );
1261 		SANE_Value_Type nType = mrSane.GetOptionType( i );
1262 		switch( nType )
1263 		{
1264 			case SANE_TYPE_BOOL:
1265 			{
1266 				sal_Bool bValue;
1267 				if( mrSane.GetOptionValue( i, bValue ) )
1268 				{
1269 					ByteString aString( "BOOL=" );
1270 					aString += (sal_uLong)bValue;
1271 					aConfig.WriteKey( aOption, aString );
1272 				}
1273 			}
1274 			break;
1275 			case SANE_TYPE_STRING:
1276 			{
1277 				String aString( "STRING=" );
1278 				String aValue;
1279 				if( mrSane.GetOptionValue( i, aValue ) )
1280 				{
1281 					aString += aValue;
1282 					aConfig.WriteKey( aOption, aString );
1283 				}
1284 			}
1285 			break;
1286 			case SANE_TYPE_FIXED:
1287 			case SANE_TYPE_INT:
1288 			{
1289 				String aString( "NUMERIC=" );
1290 				double fValue;
1291 				char buf[256];
1292 				for( int n = 0; n < mrSane.GetOptionElements( i ); n++ )
1293 				{
1294 					if( ! mrSane.GetOptionValue( i, fValue, n ) )
1295 						break;
1296 					if( n > 0 )
1297 						aString += ":";
1298 					sprintf( buf, "%lg", fValue );
1299 					aString += buf;
1300 				}
1301 				if( n >= mrSane.GetOptionElements( i ) )
1302 					aConfig.WriteKey( aOption, aString );
1303 			}
1304 			break;
1305 			default:
1306 				break;
1307 		}
1308  	}
1309 #else
1310 	static char const* pSaveOptions[] = {
1311 		"resolution",
1312 		"tl-x",
1313 		"tl-y",
1314 		"br-x",
1315 		"br-y"
1316 	};
1317 	for( size_t i = 0;
1318 		 i < (sizeof(pSaveOptions)/sizeof(pSaveOptions[0]));
1319 		 i++ )
1320 	{
1321 		ByteString aOption = pSaveOptions[i];
1322 		int nOption = mrSane.GetOptionByName( pSaveOptions[i] );
1323 		if( nOption > -1 )
1324 		{
1325 			SANE_Value_Type nType = mrSane.GetOptionType( nOption );
1326 			switch( nType )
1327 			{
1328 				case SANE_TYPE_BOOL:
1329 				{
1330 					sal_Bool bValue;
1331 					if( mrSane.GetOptionValue( nOption, bValue ) )
1332 					{
1333 						ByteString aString( "BOOL=" );
1334 						aString += ByteString::CreateFromInt32(bValue);
1335 						aConfig.WriteKey( aOption, aString );
1336 					}
1337 				}
1338 				break;
1339 				case SANE_TYPE_STRING:
1340 				{
1341 					ByteString aString( "STRING=" );
1342 					ByteString aValue;
1343 					if( mrSane.GetOptionValue( nOption, aValue ) )
1344 					{
1345 						aString += aValue;
1346 						aConfig.WriteKey( aOption, aString );
1347 					}
1348 				}
1349 				break;
1350 				case SANE_TYPE_FIXED:
1351 				case SANE_TYPE_INT:
1352 				{
1353 					ByteString aString( "NUMERIC=" );
1354 					double fValue;
1355 					char buf[256];
1356 					int n;
1357 
1358 					for( n = 0; n < mrSane.GetOptionElements( nOption ); n++ )
1359 					{
1360 						if( ! mrSane.GetOptionValue( nOption, fValue, n ) )
1361 							break;
1362 						if( n > 0 )
1363 							aString += ":";
1364 						sprintf( buf, "%lg", fValue );
1365 						aString += buf;
1366 					}
1367 					if( n >= mrSane.GetOptionElements( nOption ) )
1368 						aConfig.WriteKey( aOption, aString );
1369 				}
1370 				break;
1371 				default:
1372 					break;
1373 			}
1374 		}
1375 	}
1376 #endif
1377 #endif
1378 }
1379 
1380 sal_Bool SaneDlg::SetAdjustedNumericalValue(
1381 	const char* pOption,
1382 	double fValue,
1383 	int nElement )
1384 {
1385 	int nOption;
1386 	if( ! Sane::IsSane() || ! mrSane.IsOpen() || ( nOption = mrSane.GetOptionByName( pOption ) ) == -1 )
1387 		return sal_False;
1388 
1389 	if( nElement < 0 || nElement >= mrSane.GetOptionElements( nOption ) )
1390 		return sal_False;
1391 
1392 	double* pValues = NULL;
1393 	int nValues;
1394 	if( ( nValues = mrSane.GetRange( nOption, pValues ) ) < 0 )
1395 		return sal_False;
1396 
1397 #if OSL_DEBUG_LEVEL > 1
1398 	fprintf( stderr, "SaneDlg::SetAdjustedNumericalValue( \"%s\", %lg ) ",
1399 			 pOption, fValue );
1400 #endif
1401 
1402 	if( nValues )
1403 	{
1404 		int nNearest = 0;
1405 		double fNearest = 1e6;
1406 		for( int i = 0; i < nValues; i++ )
1407 		{
1408 			if( fabs( fValue - pValues[ i ] ) < fNearest )
1409 			{
1410 				fNearest = fabs( fValue - pValues[ i ] );
1411 				nNearest = i;
1412 			}
1413 		}
1414 		fValue = pValues[ nNearest ];
1415 	}
1416 	else
1417 	{
1418 		if( fValue < pValues[0] )
1419 			fValue = pValues[0];
1420 		if( fValue > pValues[1] )
1421 			fValue = pValues[1];
1422 	}
1423 	delete [] pValues;
1424 	mrSane.SetOptionValue( nOption, fValue, nElement );
1425 #if OSL_DEBUG_LEVEL > 1
1426 	fprintf( stderr, "yields %lg\n", fValue );
1427 #endif
1428 
1429 
1430 	return sal_True;
1431 }
1432