xref: /trunk/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