xref: /AOO41X/main/extensions/source/scanner/sanedlg.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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