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