1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <o3tl/sprintf.hxx>
22 #include <tools/config.hxx>
23 #include <unotools/resmgr.hxx>
24 #include <vcl/bitmapex.hxx>
25 #include <vcl/customweld.hxx>
26 #include <vcl/dibtools.hxx>
27 #include <vcl/lineinfo.hxx>
28 #include <vcl/weld.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/event.hxx>
31 #include "sanedlg.hxx"
34 #include <sal/macros.h>
35 #include <sal/log.hxx>
36 #include <rtl/strbuf.hxx>
38 #include <strings.hrc>
40 #define PREVIEW_WIDTH 113
41 #define PREVIEW_HEIGHT 160
43 #define RECT_SIZE_PIX 7
47 void DrawRect(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
49 tools::Rectangle
aRect(rRect
);
50 rRenderContext
.SetFillColor(COL_BLACK
);
51 rRenderContext
.SetLineColor();
52 rRenderContext
.DrawRect(aRect
);
54 aRect
.AdjustRight(-2);
55 aRect
.AdjustBottom(-2);
56 rRenderContext
.SetFillColor();
57 rRenderContext
.SetLineColor(COL_WHITE
);
58 rRenderContext
.DrawRect(aRect
);
61 void DrawRectangles(vcl::RenderContext
& rRenderContext
, Point
const & rUL
, Point
const & rBR
)
63 Point
aUR(rBR
.X(), rUL
.Y());
64 Point
aBL(rUL
.X(), rBR
.Y());
65 int nMiddleX
= (rBR
.X() - rUL
.X()) / 2 + rUL
.X();
66 int nMiddleY
= (rBR
.Y() - rUL
.Y()) / 2 + rUL
.Y();
68 rRenderContext
.SetLineColor(COL_WHITE
);
69 rRenderContext
.DrawLine(rUL
, aBL
);
70 rRenderContext
.DrawLine(aBL
, rBR
);
71 rRenderContext
.DrawLine(rBR
, aUR
);
72 rRenderContext
.DrawLine(aUR
, rUL
);
74 rRenderContext
.SetLineColor(COL_BLACK
);
75 LineInfo
aInfo(LineStyle::Dash
, 1);
79 rRenderContext
.DrawLine(rUL
, aBL
, aInfo
);
80 rRenderContext
.DrawLine(aBL
, rBR
, aInfo
);
81 rRenderContext
.DrawLine(rBR
, aUR
, aInfo
);
82 rRenderContext
.DrawLine(aUR
, rUL
, aInfo
);
84 Size
aSize(RECT_SIZE_PIX
, RECT_SIZE_PIX
);
85 DrawRect(rRenderContext
, tools::Rectangle(rUL
, aSize
));
86 DrawRect(rRenderContext
, tools::Rectangle(Point(aBL
.X(), aBL
.Y() - RECT_SIZE_PIX
), aSize
));
87 DrawRect(rRenderContext
, tools::Rectangle(Point(rBR
.X() - RECT_SIZE_PIX
, rBR
.Y() - RECT_SIZE_PIX
), aSize
));
88 DrawRect(rRenderContext
, tools::Rectangle(Point(aUR
.X() - RECT_SIZE_PIX
, aUR
.Y()), aSize
));
89 DrawRect(rRenderContext
, tools::Rectangle(Point(nMiddleX
- RECT_SIZE_PIX
/ 2, rUL
.Y()), aSize
));
90 DrawRect(rRenderContext
, tools::Rectangle(Point(nMiddleX
- RECT_SIZE_PIX
/ 2, rBR
.Y() - RECT_SIZE_PIX
), aSize
));
91 DrawRect(rRenderContext
, tools::Rectangle(Point(rUL
.X(), nMiddleY
- RECT_SIZE_PIX
/ 2), aSize
));
92 DrawRect(rRenderContext
, tools::Rectangle(Point(rBR
.X() - RECT_SIZE_PIX
, nMiddleY
- RECT_SIZE_PIX
/ 2), aSize
));
97 class ScanPreview
: public weld::CustomWidgetController
100 enum DragDirection
{ TopLeft
, Top
, TopRight
, Right
, BottomRight
, Bottom
,
103 BitmapEx maPreviewBitmapEx
;
104 tools::Rectangle maPreviewRect
;
105 Point maTopLeft
, maBottomRight
;
106 Point maMinTopLeft
, maMaxBottomRight
;
107 SaneDlg
* mpParentDialog
;
108 DragDirection meDragDirection
;
114 : maMaxBottomRight(PREVIEW_WIDTH
, PREVIEW_HEIGHT
)
115 , mpParentDialog(nullptr)
116 , meDragDirection(TopLeft
)
117 , mbDragEnable(false)
118 , mbIsDragging(false)
122 void Init(SaneDlg
*pParent
)
124 mpParentDialog
= pParent
;
127 void ResetForNewScanner()
130 maBottomRight
= Point();
131 maMinTopLeft
= Point();
132 maMaxBottomRight
= Point(PREVIEW_WIDTH
, PREVIEW_HEIGHT
);
142 mbDragEnable
= false;
145 bool IsDragEnabled() const
150 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
;
151 virtual bool MouseButtonDown(const MouseEvent
& rMEvt
) override
;
152 virtual bool MouseMove(const MouseEvent
& rMEvt
) override
;
153 virtual bool MouseButtonUp(const MouseEvent
& rMEvt
) override
;
154 Point
GetPixelPos(const Point
& rIn
) const;
155 Point
GetLogicPos(const Point
& rIn
) const;
157 void GetPreviewLogicRect(Point
& rTopLeft
, Point
&rBottomRight
) const
159 rTopLeft
= GetLogicPos(maTopLeft
);
160 rBottomRight
= GetLogicPos(maBottomRight
);
162 void GetMaxLogicRect(Point
& rTopLeft
, Point
&rBottomRight
) const
164 rTopLeft
= maMinTopLeft
;
165 rBottomRight
= maMaxBottomRight
;
168 void ChangePreviewLogicTopLeftY(tools::Long Y
)
171 aPoint
= GetPixelPos(aPoint
);
172 maTopLeft
.setY( aPoint
.Y() );
174 void ChangePreviewLogicTopLeftX(tools::Long X
)
177 aPoint
= GetPixelPos(aPoint
);
178 maTopLeft
.setX( aPoint
.X() );
180 void ChangePreviewLogicBottomRightY(tools::Long Y
)
183 aPoint
= GetPixelPos(aPoint
);
184 maBottomRight
.setY( aPoint
.Y() );
186 void ChangePreviewLogicBottomRightX(tools::Long X
)
189 aPoint
= GetPixelPos(aPoint
);
190 maBottomRight
.setX( aPoint
.X() );
192 void SetPreviewLogicRect(const Point
& rTopLeft
, const Point
&rBottomRight
)
194 maTopLeft
= GetPixelPos(rTopLeft
);
195 maBottomRight
= GetPixelPos(rBottomRight
);
196 maPreviewRect
= tools::Rectangle(maTopLeft
,
197 Size(maBottomRight
.X() - maTopLeft
.X(),
198 maBottomRight
.Y() - maTopLeft
.Y()));
200 void SetPreviewMaxRect(const Point
& rTopLeft
, const Point
&rBottomRight
)
202 maMinTopLeft
= rTopLeft
;
203 maMaxBottomRight
= rBottomRight
;
205 void DrawDrag(vcl::RenderContext
& rRenderContext
);
206 void UpdatePreviewBounds();
207 void SetBitmap(SvStream
&rStream
)
209 ReadDIBBitmapEx(maPreviewBitmapEx
, rStream
, true);
211 virtual void SetDrawingArea(weld::DrawingArea
* pDrawingArea
) override
213 Size
aSize(pDrawingArea
->get_ref_device().LogicToPixel(Size(PREVIEW_WIDTH
, PREVIEW_HEIGHT
), MapMode(MapUnit::MapAppFont
)));
214 aSize
.setWidth(aSize
.getWidth()+1);
215 aSize
.setHeight(aSize
.getHeight()+1);
216 pDrawingArea
->set_size_request(aSize
.Width(), aSize
.Height());
217 CustomWidgetController::SetDrawingArea(pDrawingArea
);
218 SetOutputSizePixel(aSize
);
222 SaneDlg::SaneDlg(weld::Window
* pParent
, Sane
& rSane
, bool bScanEnabled
)
223 : GenericDialogController(pParent
, u
"modules/scanner/ui/sanedialog.ui"_ustr
, u
"SaneDialog"_ustr
)
226 , mbScanEnabled(bScanEnabled
)
228 , mnCurrentElement(0)
232 , mxCancelButton(m_xBuilder
->weld_button(u
"cancel"_ustr
))
233 , mxDeviceInfoButton(m_xBuilder
->weld_button(u
"deviceInfoButton"_ustr
))
234 , mxPreviewButton(m_xBuilder
->weld_button(u
"previewButton"_ustr
))
235 , mxScanButton(m_xBuilder
->weld_button(u
"ok"_ustr
))
236 , mxButtonOption(m_xBuilder
->weld_button(u
"optionsButton"_ustr
))
237 , mxOptionTitle(m_xBuilder
->weld_label(u
"optionTitleLabel"_ustr
))
238 , mxOptionDescTxt(m_xBuilder
->weld_label(u
"optionsDescLabel"_ustr
))
239 , mxVectorTxt(m_xBuilder
->weld_label(u
"vectorLabel"_ustr
))
240 , mxLeftField(m_xBuilder
->weld_metric_spin_button(u
"leftSpinbutton"_ustr
, FieldUnit::PIXEL
))
241 , mxTopField(m_xBuilder
->weld_metric_spin_button(u
"topSpinbutton"_ustr
, FieldUnit::PIXEL
))
242 , mxRightField(m_xBuilder
->weld_metric_spin_button(u
"rightSpinbutton"_ustr
, FieldUnit::PIXEL
))
243 , mxBottomField(m_xBuilder
->weld_metric_spin_button(u
"bottomSpinbutton"_ustr
, FieldUnit::PIXEL
))
244 , mxDeviceBox(m_xBuilder
->weld_combo_box(u
"deviceCombobox"_ustr
))
245 , mxReslBox(m_xBuilder
->weld_combo_box(u
"reslCombobox"_ustr
))
246 , mxAdvancedBox(m_xBuilder
->weld_check_button(u
"advancedCheckbutton"_ustr
))
247 , mxVectorBox(m_xBuilder
->weld_spin_button(u
"vectorSpinbutton"_ustr
))
248 , mxQuantumRangeBox(m_xBuilder
->weld_combo_box(u
"quantumRangeCombobox"_ustr
))
249 , mxStringRangeBox(m_xBuilder
->weld_combo_box(u
"stringRangeCombobox"_ustr
))
250 , mxBoolCheckBox(m_xBuilder
->weld_check_button(u
"boolCheckbutton"_ustr
))
251 , mxStringEdit(m_xBuilder
->weld_entry(u
"stringEntry"_ustr
))
252 , mxNumericEdit(m_xBuilder
->weld_entry(u
"numericEntry"_ustr
))
253 , mxOptionBox(m_xBuilder
->weld_tree_view(u
"optionSvTreeListBox"_ustr
))
254 , mxPreview(new ScanPreview
)
255 , mxPreviewWnd(new weld::CustomWeld(*m_xBuilder
, u
"preview"_ustr
, *mxPreview
))
257 Size
aSize(mxOptionBox
->get_approximate_digit_width() * 32, mxOptionBox
->get_height_rows(8));
258 mxOptionTitle
->set_size_request(aSize
.Width(), aSize
.Height() / 2);
259 mxOptionBox
->set_size_request(aSize
.Width(), aSize
.Height());
260 mxPreview
->Init(this);
263 InitDevices(); // opens first sane device
268 mxDeviceInfoButton
->connect_clicked( LINK( this, SaneDlg
, ClickBtnHdl
) );
269 mxPreviewButton
->connect_clicked( LINK( this, SaneDlg
, ClickBtnHdl
) );
270 mxScanButton
->connect_clicked( LINK( this, SaneDlg
, ClickBtnHdl
) );
271 mxButtonOption
->connect_clicked( LINK( this, SaneDlg
, ClickBtnHdl
) );
272 mxDeviceBox
->connect_changed( LINK( this, SaneDlg
, SelectHdl
) );
273 mxOptionBox
->connect_selection_changed(LINK(this, SaneDlg
, OptionsBoxSelectHdl
));
274 mxCancelButton
->connect_clicked( LINK( this, SaneDlg
, ClickBtnHdl
) );
275 mxBoolCheckBox
->connect_toggled( LINK( this, SaneDlg
, ToggleBtnHdl
) );
276 mxStringEdit
->connect_changed( LINK( this, SaneDlg
, ModifyHdl
) );
277 mxNumericEdit
->connect_changed( LINK( this, SaneDlg
, ModifyHdl
) );
278 mxVectorBox
->connect_changed( LINK( this, SaneDlg
, ModifyHdl
) );
279 mxReslBox
->connect_changed( LINK( this, SaneDlg
, ValueModifyHdl
) );
280 mxStringRangeBox
->connect_changed( LINK( this, SaneDlg
, SelectHdl
) );
281 mxQuantumRangeBox
->connect_changed( LINK( this, SaneDlg
, SelectHdl
) );
282 mxLeftField
->connect_value_changed( LINK( this, SaneDlg
, MetricValueModifyHdl
) );
283 mxRightField
->connect_value_changed( LINK( this, SaneDlg
, MetricValueModifyHdl
) );
284 mxTopField
->connect_value_changed( LINK( this, SaneDlg
, MetricValueModifyHdl
) );
285 mxBottomField
->connect_value_changed( LINK( this, SaneDlg
, MetricValueModifyHdl
) );
286 mxAdvancedBox
->connect_toggled( LINK( this, SaneDlg
, ToggleBtnHdl
) );
288 maOldLink
= mrSane
.SetReloadOptionsHdl( LINK( this, SaneDlg
, ReloadSaneOptionsHdl
) );
293 mrSane
.SetReloadOptionsHdl(maOldLink
);
298 OUString
SaneResId(TranslateId aID
)
300 return Translate::get(aID
, Translate::Create("pcr"));
309 std::unique_ptr
<weld::MessageDialog
> xErrorBox(Application::CreateMessageDialog(mpParent
,
310 VclMessageType::Warning
, VclButtonsType::Ok
,
311 SaneResId(STR_COULD_NOT_BE_INIT
)));
316 return GenericDialogController::run();
319 void SaneDlg::InitDevices()
321 if( ! Sane::IsSane() )
324 if( mrSane
.IsOpen() )
326 mrSane
.ReloadDevices();
327 mxDeviceBox
->clear();
328 for (int i
= 0; i
< Sane::CountDevices(); ++i
)
329 mxDeviceBox
->append_text(Sane::GetName(i
));
330 if( Sane::CountDevices() )
333 mxDeviceBox
->set_active(0);
337 void SaneDlg::InitFields()
339 if( ! Sane::IsSane() )
342 int nOption
, i
, nValue
;
344 const char *ppSpecialOptions
[] = {
353 mxPreview
->EnableDrag();
355 Point aTopLeft
, aBottomRight
;
356 mxPreview
->GetPreviewLogicRect(aTopLeft
, aBottomRight
);
357 Point aMinTopLeft
, aMaxBottomRight
;
358 mxPreview
->GetMaxLogicRect(aMinTopLeft
, aMaxBottomRight
);
359 mxScanButton
->set_visible( mbScanEnabled
);
361 if( ! mrSane
.IsOpen() )
365 nOption
= mrSane
.GetOptionByName( "resolution" );
370 if( mrSane
.GetOptionValue( nOption
, fRes
) )
372 mxReslBox
->set_sensitive(true);
374 mxReslBox
->set_entry_text(OUString::number(static_cast<sal_uInt32
>(fRes
)));
375 std::unique_ptr
<double[]> pDouble
;
376 nValue
= mrSane
.GetRange( nOption
, pDouble
);
382 for( i
=0; i
<nValue
; i
++ )
384 if( i
== 0 || i
== nValue
-1 || ! ( static_cast<int>(pDouble
[i
]) % 20) )
385 mxReslBox
->append_text(OUString::number(static_cast<sal_uInt32
>(pDouble
[i
])));
390 mxReslBox
->append_text(OUString::number(static_cast<sal_uInt32
>(pDouble
[0])));
391 // Can only select 75 and 2400 dpi in Scanner dialogue
392 // scanner allows random setting of dpi resolution, a slider might be useful
394 // workaround: offer at least some more standard dpi resolution between
397 for (sal_uInt32 nRes
= static_cast<sal_uInt32
>(pDouble
[0]) * 2; nRes
< static_cast<sal_uInt32
>(pDouble
[1]); nRes
= nRes
* 2)
399 if ( !bGot300
&& nRes
> 300 ) {
400 nRes
= 300; bGot300
= 1;
402 mxReslBox
->append_text(OUString::number(nRes
));
404 mxReslBox
->append_text(OUString::number(static_cast<sal_uInt32
>(pDouble
[1])));
408 mxReslBox
->set_sensitive( false );
412 mxReslBox
->set_sensitive( false );
415 for( i
= 0; i
< 4; i
++ )
417 char const *pOptionName
= nullptr;
418 weld::MetricSpinButton
* pField
= nullptr;
422 pOptionName
= "tl-x";
423 pField
= mxLeftField
.get();
426 pOptionName
= "tl-y";
427 pField
= mxTopField
.get();
430 pOptionName
= "br-x";
431 pField
= mxRightField
.get();
434 pOptionName
= "br-y";
435 pField
= mxBottomField
.get();
437 nOption
= pOptionName
? mrSane
.GetOptionByName( pOptionName
) : -1;
440 if( mrSane
.GetOptionValue( nOption
, fValue
) )
442 if( mrSane
.GetOptionUnit( nOption
) == SANE_UNIT_MM
)
444 pField
->set_unit( FieldUnit::MM
);
445 pField
->set_value( static_cast<int>(fValue
), FieldUnit::MM
);
447 else // SANE_UNIT_PIXEL
449 pField
->set_unit( FieldUnit::PIXEL
);
450 pField
->set_value( static_cast<int>(fValue
), FieldUnit::PIXEL
);
453 case 0: aTopLeft
.setX( static_cast<int>(fValue
) );break;
454 case 1: aTopLeft
.setY( static_cast<int>(fValue
) );break;
455 case 2: aBottomRight
.setX( static_cast<int>(fValue
) );break;
456 case 3: aBottomRight
.setY( static_cast<int>(fValue
) );break;
459 std::unique_ptr
<double[]> pDouble
;
460 nValue
= mrSane
.GetRange( nOption
, pDouble
);
465 pField
->set_min( static_cast<tools::Long
>(pDouble
[0]), FieldUnit::NONE
);
467 pField
->set_max( static_cast<tools::Long
>(pDouble
[ nValue
-1 ]), FieldUnit::NONE
);
469 pField
->set_max( static_cast<tools::Long
>(pDouble
[ 1 ]), FieldUnit::NONE
);
472 case 0: aMinTopLeft
.setX( pField
->get_min(FieldUnit::NONE
) );break;
473 case 1: aMinTopLeft
.setY( pField
->get_min(FieldUnit::NONE
) );break;
474 case 2: aMaxBottomRight
.setX( pField
->get_max(FieldUnit::NONE
) );break;
475 case 3: aMaxBottomRight
.setY( pField
->get_max(FieldUnit::NONE
) );break;
481 case 0: aMinTopLeft
.setX( static_cast<int>(fValue
) );break;
482 case 1: aMinTopLeft
.setY( static_cast<int>(fValue
) );break;
483 case 2: aMaxBottomRight
.setX( static_cast<int>(fValue
) );break;
484 case 3: aMaxBottomRight
.setY( static_cast<int>(fValue
) );break;
487 pField
->set_sensitive(true);
491 mxPreview
->DisableDrag();
492 pField
->set_min( 0, FieldUnit::NONE
);
495 aMinTopLeft
.setX( 0 );
497 pField
->set_max( PREVIEW_WIDTH
, FieldUnit::NONE
);
498 pField
->set_value( 0, FieldUnit::NONE
);
501 aMinTopLeft
.setY( 0 );
503 pField
->set_max( PREVIEW_HEIGHT
, FieldUnit::NONE
);
504 pField
->set_value( 0, FieldUnit::NONE
);
507 aMaxBottomRight
.setX( PREVIEW_WIDTH
);
508 aBottomRight
.setX( PREVIEW_WIDTH
);
509 pField
->set_max( PREVIEW_WIDTH
, FieldUnit::NONE
);
510 pField
->set_value( PREVIEW_WIDTH
, FieldUnit::NONE
);
513 aMaxBottomRight
.setY( PREVIEW_HEIGHT
);
514 aBottomRight
.setY( PREVIEW_HEIGHT
);
515 pField
->set_max( PREVIEW_HEIGHT
, FieldUnit::NONE
);
516 pField
->set_value( PREVIEW_HEIGHT
, FieldUnit::NONE
);
519 pField
->set_sensitive(false);
523 mxPreview
->SetPreviewMaxRect(aMinTopLeft
, aMaxBottomRight
);
524 mxPreview
->SetPreviewLogicRect(aTopLeft
, aBottomRight
);
525 mxPreview
->Invalidate();
528 mxOptionBox
->clear();
529 std::unique_ptr
<weld::TreeIter
> xParentEntry(mxOptionBox
->make_iterator());
530 bool bGroupRejected
= false;
531 for( i
= 1; i
< mrSane
.CountOptions(); i
++ )
533 OUString aOption
=mrSane
.GetOptionName( i
);
534 bool bInsertAdvanced
=
535 (mrSane
.GetOptionCap( i
) & SANE_CAP_ADVANCED
) == 0 ||
536 mxAdvancedBox
->get_active();
537 if( mrSane
.GetOptionType( i
) == SANE_TYPE_GROUP
)
539 if( bInsertAdvanced
)
541 aOption
= mrSane
.GetOptionTitle( i
);
542 mxOptionBox
->append(xParentEntry
.get());
543 mxOptionBox
->set_text(*xParentEntry
, aOption
, 0);
544 bGroupRejected
= false;
547 bGroupRejected
= true;
549 else if( !aOption
.isEmpty() &&
550 ! ( mrSane
.GetOptionCap( i
) &
552 SANE_CAP_HARD_SELECT
|
555 bInsertAdvanced
&& ! bGroupRejected
)
557 bool bIsSpecial
= false;
558 for( size_t n
= 0; !bIsSpecial
&&
559 n
< SAL_N_ELEMENTS(ppSpecialOptions
); n
++ )
561 if( aOption
== OUString::createFromAscii(ppSpecialOptions
[n
]) )
567 mxOptionBox
->append(xParentEntry
.get(), aOption
);
569 mxOptionBox
->append_text(aOption
);
575 IMPL_LINK( SaneDlg
, ClickBtnHdl
, weld::Button
&, rButton
, void )
577 if( mrSane
.IsOpen() )
579 if( &rButton
== mxDeviceInfoButton
.get() )
581 OUString
aString(SaneResId(STR_DEVICE_DESC
));
582 aString
= aString
.replaceFirst( "%s", Sane::GetName( mrSane
.GetDeviceNumber() ) );
583 aString
= aString
.replaceFirst( "%s", Sane::GetVendor( mrSane
.GetDeviceNumber() ) );
584 aString
= aString
.replaceFirst( "%s", Sane::GetModel( mrSane
.GetDeviceNumber() ) );
585 aString
= aString
.replaceFirst( "%s", Sane::GetType( mrSane
.GetDeviceNumber() ) );
586 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xDialog
.get(),
587 VclMessageType::Info
, VclButtonsType::Ok
,
591 else if( &rButton
== mxPreviewButton
.get() )
593 else if( &rButton
== mxButtonOption
.get() )
596 SANE_Value_Type nType
= mrSane
.GetOptionType( mnCurrentOption
);
599 case SANE_TYPE_BUTTON
:
600 mrSane
.ActivateButtonOption( mnCurrentOption
);
602 case SANE_TYPE_FIXED
:
605 int nElements
= mrSane
.GetOptionElements( mnCurrentOption
);
606 std::unique_ptr
<double[]> x(new double[ nElements
]);
607 std::unique_ptr
<double[]> y(new double[ nElements
]);
608 for( int i
= 0; i
< nElements
; i
++ )
609 x
[ i
] = static_cast<double>(i
);
610 mrSane
.GetOptionValue( mnCurrentOption
, y
.get() );
612 GridDialog
aGrid(m_xDialog
.get(), x
.get(), y
.get(), nElements
);
613 aGrid
.set_title( mrSane
.GetOptionName( mnCurrentOption
) );
614 aGrid
.setBoundings( 0, mfMin
, nElements
, mfMax
);
615 if (aGrid
.run() && aGrid
.getNewYValues())
616 mrSane
.SetOptionValue( mnCurrentOption
, aGrid
.getNewYValues() );
620 case SANE_TYPE_STRING
:
621 case SANE_TYPE_GROUP
:
626 if (&rButton
== mxScanButton
.get())
628 double fRes
= static_cast<double>(mxReslBox
->get_active_text().toUInt32());
629 SetAdjustedNumericalValue( "resolution", fRes
);
630 UpdateScanArea(true);
632 m_xDialog
->response(mrSane
.IsOpen() ? RET_OK
: RET_CANCEL
);
633 doScan
= mrSane
.IsOpen();
635 else if( &rButton
== mxCancelButton
.get() )
638 m_xDialog
->response(RET_CANCEL
);
642 IMPL_LINK( SaneDlg
, ToggleBtnHdl
, weld::Toggleable
&, rButton
, void )
644 if( mrSane
.IsOpen() )
646 if( &rButton
== mxBoolCheckBox
.get() )
648 mrSane
.SetOptionValue( mnCurrentOption
,
649 mxBoolCheckBox
->get_active() );
651 else if( &rButton
== mxAdvancedBox
.get() )
653 ReloadSaneOptionsHdl( mrSane
);
658 IMPL_LINK( SaneDlg
, SelectHdl
, weld::ComboBox
&, rListBox
, void )
660 if( &rListBox
== mxDeviceBox
.get() && Sane::IsSane() && Sane::CountDevices() )
662 int nNewNumber
= mxDeviceBox
->get_active();
663 int nOldNumber
= mrSane
.GetDeviceNumber();
664 if (nNewNumber
!= nOldNumber
)
667 mrSane
.Open(nNewNumber
);
668 mxPreview
->ResetForNewScanner();
672 if( mrSane
.IsOpen() )
674 if( &rListBox
== mxQuantumRangeBox
.get() )
676 double fValue
= mxQuantumRangeBox
->get_active_text().toDouble();
677 mrSane
.SetOptionValue(mnCurrentOption
, fValue
, mnCurrentElement
);
679 else if( &rListBox
== mxStringRangeBox
.get() )
681 mrSane
.SetOptionValue(mnCurrentOption
, mxStringRangeBox
->get_active_text());
686 IMPL_LINK_NOARG(SaneDlg
, OptionsBoxSelectHdl
, weld::TreeView
&, void)
691 OUString aOption
= mxOptionBox
->get_selected_text();
692 int nOption
= mrSane
.GetOptionByName(OUStringToOString(aOption
,
693 osl_getThreadTextEncoding()).getStr());
694 if( nOption
== -1 || nOption
== mnCurrentOption
)
698 mnCurrentOption
= nOption
;
699 mxOptionTitle
->set_label(mrSane
.GetOptionTitle(mnCurrentOption
));
700 SANE_Value_Type nType
= mrSane
.GetOptionType( mnCurrentOption
);
701 SANE_Constraint_Type nConstraint
;
704 case SANE_TYPE_BOOL
: EstablishBoolOption();break;
705 case SANE_TYPE_STRING
:
706 nConstraint
= mrSane
.GetOptionConstraintType( mnCurrentOption
);
707 if( nConstraint
== SANE_CONSTRAINT_STRING_LIST
)
708 EstablishStringRange();
710 EstablishStringOption();
712 case SANE_TYPE_FIXED
:
715 nConstraint
= mrSane
.GetOptionConstraintType( mnCurrentOption
);
716 int nElements
= mrSane
.GetOptionElements( mnCurrentOption
);
717 mnCurrentElement
= 0;
718 if( nConstraint
== SANE_CONSTRAINT_RANGE
||
719 nConstraint
== SANE_CONSTRAINT_WORD_LIST
)
720 EstablishQuantumRange();
724 EstablishNumericOption();
728 if( nElements
<= 10 )
730 mxVectorBox
->set_range(1, mrSane
.GetOptionElements(mnCurrentOption
));
731 mxVectorBox
->set_value(1);
738 // bring up dialog only on button click
739 EstablishButtonOption();
744 case SANE_TYPE_BUTTON
:
745 EstablishButtonOption();
751 IMPL_LINK(SaneDlg
, ModifyHdl
, weld::Entry
&, rEdit
, void)
753 if( !mrSane
.IsOpen() )
756 if (&rEdit
== mxStringEdit
.get())
758 mrSane
.SetOptionValue( mnCurrentOption
, mxStringEdit
->get_text() );
760 else if (&rEdit
== mxNumericEdit
.get())
762 double fValue
= mxNumericEdit
->get_text().toDouble();
763 if( mfMin
!= mfMax
&& ( fValue
< mfMin
|| fValue
> mfMax
) )
768 else if( fValue
> mfMax
)
770 o3tl::sprintf( pBuf
, "%g", fValue
);
771 mxNumericEdit
->set_text( OUString( pBuf
, strlen(pBuf
), osl_getThreadTextEncoding() ) );
773 mrSane
.SetOptionValue( mnCurrentOption
, fValue
, mnCurrentElement
);
775 else if (&rEdit
== mxVectorBox
.get())
777 mnCurrentElement
= mxVectorBox
->get_value() - 1;
779 if( mrSane
.GetOptionValue( mnCurrentOption
, fValue
, mnCurrentElement
))
782 o3tl::sprintf( pBuf
, "%g", fValue
);
783 OUString
aValue( pBuf
, strlen(pBuf
), osl_getThreadTextEncoding() );
784 mxNumericEdit
->set_text( aValue
);
785 mxQuantumRangeBox
->set_active_text( aValue
);
790 IMPL_LINK(SaneDlg
, ValueModifyHdl
, weld::ComboBox
&, rEdit
, void)
792 if( !mrSane
.IsOpen() )
795 if (&rEdit
!= mxReslBox
.get())
798 double fRes
= static_cast<double>(mxReslBox
->get_active_text().toUInt32());
799 int nOption
= mrSane
.GetOptionByName( "resolution" );
803 std::unique_ptr
<double[]> pDouble
;
804 int nValues
= mrSane
.GetRange( nOption
, pDouble
);
808 for( i
= 0; i
< nValues
; i
++ )
810 if( fRes
== pDouble
[i
] )
816 else if( nValues
== 0 )
818 if( fRes
< pDouble
[ 0 ] )
820 if( fRes
> pDouble
[ 1 ] )
823 mxReslBox
->set_entry_text(OUString::number(static_cast<sal_uInt32
>(fRes
)));
826 IMPL_LINK(SaneDlg
, MetricValueModifyHdl
, weld::MetricSpinButton
&, rEdit
, void)
828 if( !mrSane
.IsOpen() )
831 if (&rEdit
== mxTopField
.get())
833 mxPreview
->ChangePreviewLogicTopLeftY(mxTopField
->get_value(FieldUnit::NONE
));
834 mxPreview
->Invalidate();
836 else if (&rEdit
== mxLeftField
.get())
838 mxPreview
->ChangePreviewLogicTopLeftX(mxLeftField
->get_value(FieldUnit::NONE
));
839 mxPreview
->Invalidate();
841 else if (&rEdit
== mxBottomField
.get())
843 mxPreview
->ChangePreviewLogicBottomRightY(mxBottomField
->get_value(FieldUnit::NONE
));
844 mxPreview
->Invalidate();
846 else if (&rEdit
== mxRightField
.get())
848 mxPreview
->ChangePreviewLogicBottomRightX(mxRightField
->get_value(FieldUnit::NONE
));
849 mxPreview
->Invalidate();
853 IMPL_LINK_NOARG( SaneDlg
, ReloadSaneOptionsHdl
, Sane
&, void )
855 mnCurrentOption
= -1;
856 mnCurrentElement
= 0;
859 mxPreview
->Invalidate();
862 void SaneDlg::AcquirePreview()
864 if( ! mrSane
.IsOpen() )
867 UpdateScanArea( true );
868 // set small resolution for preview
869 double fResl
= static_cast<double>(mxReslBox
->get_active_text().toUInt32());
870 SetAdjustedNumericalValue( "resolution", 30.0 );
872 int nOption
= mrSane
.GetOptionByName( "preview" );
875 OUString
aString(SaneResId(STR_SLOW_PREVIEW
));
876 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(m_xDialog
.get(),
877 VclMessageType::Warning
, VclButtonsType::OkCancel
,
879 if (xBox
->run() == RET_CANCEL
)
883 mrSane
.SetOptionValue( nOption
, true );
885 rtl::Reference
<BitmapTransporter
> xTransporter(new BitmapTransporter
);
886 if (!mrSane
.Start(*xTransporter
))
888 std::unique_ptr
<weld::MessageDialog
> xErrorBox(Application::CreateMessageDialog(m_xDialog
.get(),
889 VclMessageType::Warning
, VclButtonsType::Ok
,
890 SaneResId(STR_ERROR_SCAN
)));
895 #if OSL_DEBUG_LEVEL > 0
896 SAL_INFO("extensions.scanner", "Previewbitmapstream contains " << xTransporter
->getStream().TellEnd() << "bytes");
898 xTransporter
->getStream().Seek( STREAM_SEEK_TO_BEGIN
);
899 mxPreview
->SetBitmap(xTransporter
->getStream());
902 SetAdjustedNumericalValue( "resolution", fResl
);
903 mxReslBox
->set_entry_text(OUString::number(static_cast<sal_uInt32
>(fResl
)));
905 mxPreview
->UpdatePreviewBounds();
906 mxPreview
->Invalidate();
909 void ScanPreview::UpdatePreviewBounds()
913 maPreviewRect
= tools::Rectangle( maTopLeft
,
914 Size( maBottomRight
.X() - maTopLeft
.X(),
915 maBottomRight
.Y() - maTopLeft
.Y() )
920 Size
aBMSize( maPreviewBitmapEx
.GetSizePixel() );
921 if( aBMSize
.Width() > aBMSize
.Height() && aBMSize
.Width() )
923 int nVHeight
= (maBottomRight
.X() - maTopLeft
.X()) * aBMSize
.Height() / aBMSize
.Width();
924 maPreviewRect
= tools::Rectangle( Point( maTopLeft
.X(), ( maTopLeft
.Y() + maBottomRight
.Y() )/2 - nVHeight
/2 ),
925 Size( maBottomRight
.X() - maTopLeft
.X(),
928 else if (aBMSize
.Height())
930 int nVWidth
= (maBottomRight
.Y() - maTopLeft
.Y()) * aBMSize
.Width() / aBMSize
.Height();
931 maPreviewRect
= tools::Rectangle( Point( ( maTopLeft
.X() + maBottomRight
.X() )/2 - nVWidth
/2, maTopLeft
.Y() ),
933 maBottomRight
.Y() - maTopLeft
.Y() ) );
938 void ScanPreview::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
940 rRenderContext
.SetMapMode(MapMode(MapUnit::MapAppFont
));
941 rRenderContext
.SetFillColor(COL_WHITE
);
942 rRenderContext
.SetLineColor(COL_WHITE
);
943 rRenderContext
.DrawRect(tools::Rectangle(Point(0, 0),
944 Size(PREVIEW_WIDTH
, PREVIEW_HEIGHT
)));
945 rRenderContext
.SetMapMode(MapMode(MapUnit::MapPixel
));
946 // check for sane values
947 rRenderContext
.DrawBitmapEx(maPreviewRect
.TopLeft(), maPreviewRect
.GetSize(), maPreviewBitmapEx
);
949 DrawDrag(rRenderContext
);
952 void SaneDlg::DisableOption()
954 mxBoolCheckBox
->hide();
955 mxStringEdit
->hide();
956 mxNumericEdit
->hide();
957 mxQuantumRangeBox
->hide();
958 mxStringRangeBox
->hide();
959 mxButtonOption
->hide();
962 mxOptionDescTxt
->hide();
965 void SaneDlg::EstablishBoolOption()
967 bool bSuccess
, bValue
;
969 bSuccess
= mrSane
.GetOptionValue( mnCurrentOption
, bValue
);
972 mxBoolCheckBox
->set_label( mrSane
.GetOptionName( mnCurrentOption
) );
973 mxBoolCheckBox
->set_active( bValue
);
974 mxBoolCheckBox
->show();
978 void SaneDlg::EstablishStringOption()
983 bSuccess
= mrSane
.GetOptionValue( mnCurrentOption
, aValue
);
986 mxOptionDescTxt
->set_label( mrSane
.GetOptionName( mnCurrentOption
) );
987 mxOptionDescTxt
->show();
988 mxStringEdit
->set_text(OStringToOUString(aValue
, osl_getThreadTextEncoding()));
989 mxStringEdit
->show();
993 void SaneDlg::EstablishStringRange()
995 const char** ppStrings
= mrSane
.GetStringConstraint( mnCurrentOption
);
996 mxStringRangeBox
->clear();
997 for( int i
= 0; ppStrings
[i
] != nullptr; i
++ )
998 mxStringRangeBox
->append_text( OUString( ppStrings
[i
], strlen(ppStrings
[i
]), osl_getThreadTextEncoding() ) );
1000 mrSane
.GetOptionValue( mnCurrentOption
, aValue
);
1001 mxStringRangeBox
->set_active_text(OStringToOUString(aValue
, osl_getThreadTextEncoding()));
1002 mxStringRangeBox
->show();
1003 mxOptionDescTxt
->set_label( mrSane
.GetOptionName( mnCurrentOption
) );
1004 mxOptionDescTxt
->show();
1007 void SaneDlg::EstablishQuantumRange()
1010 int nValues
= mrSane
.GetRange( mnCurrentOption
, mpRange
);
1013 mfMin
= mpRange
[ 0 ];
1014 mfMax
= mpRange
[ 1 ];
1016 EstablishNumericOption();
1018 else if( nValues
> 0 )
1021 mxQuantumRangeBox
->clear();
1022 mfMin
= mpRange
[ 0 ];
1023 mfMax
= mpRange
[ nValues
-1 ];
1024 for( int i
= 0; i
< nValues
; i
++ )
1026 o3tl::sprintf( pBuf
, "%g", mpRange
[ i
] );
1027 mxQuantumRangeBox
->append_text( OUString( pBuf
, strlen(pBuf
), osl_getThreadTextEncoding() ) );
1030 if( mrSane
.GetOptionValue( mnCurrentOption
, fValue
, mnCurrentElement
) )
1032 o3tl::sprintf( pBuf
, "%g", fValue
);
1033 mxQuantumRangeBox
->set_active_text( OUString( pBuf
, strlen(pBuf
), osl_getThreadTextEncoding() ) );
1035 mxQuantumRangeBox
->show();
1036 OUString aText
= mrSane
.GetOptionName( mnCurrentOption
) + " "
1037 + mrSane
.GetOptionUnitName( mnCurrentOption
);
1038 mxOptionDescTxt
->set_label(aText
);
1039 mxOptionDescTxt
->show();
1043 void SaneDlg::EstablishNumericOption()
1048 bSuccess
= mrSane
.GetOptionValue( mnCurrentOption
, fValue
);
1053 OUString aText
= mrSane
.GetOptionName( mnCurrentOption
) + " "
1054 + mrSane
.GetOptionUnitName( mnCurrentOption
);
1055 if( mfMin
!= mfMax
)
1057 o3tl::sprintf( pBuf
, " < %g ; %g >", mfMin
, mfMax
);
1058 aText
+= OUString( pBuf
, strlen(pBuf
), osl_getThreadTextEncoding() );
1060 mxOptionDescTxt
->set_label( aText
);
1061 mxOptionDescTxt
->show();
1062 o3tl::sprintf( pBuf
, "%g", fValue
);
1063 mxNumericEdit
->set_text( OUString( pBuf
, strlen(pBuf
), osl_getThreadTextEncoding() ) );
1064 mxNumericEdit
->show();
1067 void SaneDlg::EstablishButtonOption()
1069 mxOptionDescTxt
->set_label(mrSane
.GetOptionName(mnCurrentOption
));
1070 mxOptionDescTxt
->show();
1071 mxButtonOption
->show();
1074 bool ScanPreview::MouseMove(const MouseEvent
& rMEvt
)
1079 Point aMousePos
= rMEvt
.GetPosPixel();
1080 // move into valid area
1081 Point aLogicPos
= GetLogicPos( aMousePos
);
1082 aMousePos
= GetPixelPos( aLogicPos
);
1083 switch( meDragDirection
)
1085 case TopLeft
: maTopLeft
= aMousePos
; break;
1086 case Top
: maTopLeft
.setY( aMousePos
.Y() ); break;
1088 maTopLeft
.setY( aMousePos
.Y() );
1089 maBottomRight
.setX( aMousePos
.X() );
1091 case Right
: maBottomRight
.setX( aMousePos
.X() ); break;
1092 case BottomRight
: maBottomRight
= aMousePos
; break;
1093 case Bottom
: maBottomRight
.setY( aMousePos
.Y() ); break;
1095 maTopLeft
.setX( aMousePos
.X() );
1096 maBottomRight
.setY( aMousePos
.Y() );
1098 case Left
: maTopLeft
.setX( aMousePos
.X() ); break;
1102 if( maTopLeft
.X() > maBottomRight
.X() )
1104 nSwap
= maTopLeft
.X();
1105 maTopLeft
.setX( maBottomRight
.X() );
1106 maBottomRight
.setX( nSwap
);
1108 if( maTopLeft
.Y() > maBottomRight
.Y() )
1110 nSwap
= maTopLeft
.Y();
1111 maTopLeft
.setY( maBottomRight
.Y() );
1112 maBottomRight
.setY( nSwap
);
1115 mpParentDialog
->UpdateScanArea(false);
1119 bool ScanPreview::MouseButtonDown( const MouseEvent
& rMEvt
)
1121 if (!mbIsDragging
&& mbDragEnable
)
1123 Point aMousePixel
= rMEvt
.GetPosPixel();
1125 int nMiddleX
= ( maBottomRight
.X() - maTopLeft
.X() ) / 2 - RECT_SIZE_PIX
/2 + maTopLeft
.X();
1126 int nMiddleY
= ( maBottomRight
.Y() - maTopLeft
.Y() ) / 2 - RECT_SIZE_PIX
/2 + maTopLeft
.Y();
1127 if( aMousePixel
.Y() >= maTopLeft
.Y() &&
1128 aMousePixel
.Y() < maTopLeft
.Y() + RECT_SIZE_PIX
)
1130 if( aMousePixel
.X() >= maTopLeft
.X() &&
1131 aMousePixel
.X() < maTopLeft
.X() + RECT_SIZE_PIX
)
1133 meDragDirection
= TopLeft
;
1134 mbIsDragging
= true;
1136 else if( aMousePixel
.X() >= nMiddleX
&&
1137 aMousePixel
.X() < nMiddleX
+ RECT_SIZE_PIX
)
1139 meDragDirection
= Top
;
1140 mbIsDragging
= true;
1142 else if( aMousePixel
.X() > maBottomRight
.X() - RECT_SIZE_PIX
&&
1143 aMousePixel
.X() <= maBottomRight
.X() )
1145 meDragDirection
= TopRight
;
1146 mbIsDragging
= true;
1149 else if( aMousePixel
.Y() >= nMiddleY
&&
1150 aMousePixel
.Y() < nMiddleY
+ RECT_SIZE_PIX
)
1152 if( aMousePixel
.X() >= maTopLeft
.X() &&
1153 aMousePixel
.X() < maTopLeft
.X() + RECT_SIZE_PIX
)
1155 meDragDirection
= Left
;
1156 mbIsDragging
= true;
1158 else if( aMousePixel
.X() > maBottomRight
.X() - RECT_SIZE_PIX
&&
1159 aMousePixel
.X() <= maBottomRight
.X() )
1161 meDragDirection
= Right
;
1162 mbIsDragging
= true;
1165 else if( aMousePixel
.Y() <= maBottomRight
.Y() &&
1166 aMousePixel
.Y() > maBottomRight
.Y() - RECT_SIZE_PIX
)
1168 if( aMousePixel
.X() >= maTopLeft
.X() &&
1169 aMousePixel
.X() < maTopLeft
.X() + RECT_SIZE_PIX
)
1171 meDragDirection
= BottomLeft
;
1172 mbIsDragging
= true;
1174 else if( aMousePixel
.X() >= nMiddleX
&&
1175 aMousePixel
.X() < nMiddleX
+ RECT_SIZE_PIX
)
1177 meDragDirection
= Bottom
;
1178 mbIsDragging
= true;
1180 else if( aMousePixel
.X() > maBottomRight
.X() - RECT_SIZE_PIX
&&
1181 aMousePixel
.X() <= maBottomRight
.X() )
1183 meDragDirection
= BottomRight
;
1184 mbIsDragging
= true;
1195 bool ScanPreview::MouseButtonUp(const MouseEvent
&)
1198 mpParentDialog
->UpdateScanArea(true);
1199 mbIsDragging
= false;
1204 void ScanPreview::DrawDrag(vcl::RenderContext
& rRenderContext
)
1209 rRenderContext
.SetMapMode(MapMode(MapUnit::MapPixel
));
1211 DrawRectangles(rRenderContext
, maTopLeft
, maBottomRight
);
1213 rRenderContext
.SetMapMode(MapMode(MapUnit::MapAppFont
));
1216 Point
ScanPreview::GetPixelPos( const Point
& rIn
) const
1219 ( ( rIn
.X() * PREVIEW_WIDTH
) /
1220 ( maMaxBottomRight
.X() - maMinTopLeft
.X() ) )
1222 ( ( rIn
.Y() * PREVIEW_HEIGHT
)
1223 / ( maMaxBottomRight
.Y() - maMinTopLeft
.Y() ) )
1226 return GetDrawingArea()->get_ref_device().LogicToPixel(aConvert
, MapMode(MapUnit::MapAppFont
));
1229 Point
ScanPreview::GetLogicPos(const Point
& rIn
) const
1231 Point aConvert
= GetDrawingArea()->get_ref_device().PixelToLogic(rIn
, MapMode(MapUnit::MapAppFont
));
1232 if( aConvert
.X() < 0 )
1234 if( aConvert
.X() >= PREVIEW_WIDTH
)
1235 aConvert
.setX( PREVIEW_WIDTH
-1 );
1236 if( aConvert
.Y() < 0 )
1238 if( aConvert
.Y() >= PREVIEW_HEIGHT
)
1239 aConvert
.setY( PREVIEW_HEIGHT
-1 );
1241 aConvert
.setX( aConvert
.X() * ( maMaxBottomRight
.X() - maMinTopLeft
.X() ) );
1242 aConvert
.setX( aConvert
.X() / ( PREVIEW_WIDTH
) );
1243 aConvert
.setY( aConvert
.Y() * ( maMaxBottomRight
.Y() - maMinTopLeft
.Y() ) );
1244 aConvert
.setY( aConvert
.Y() / ( PREVIEW_HEIGHT
) );
1248 void SaneDlg::UpdateScanArea(bool bSend
)
1250 if (!mxPreview
->IsDragEnabled())
1254 mxPreview
->GetPreviewLogicRect(aUL
, aBR
);
1256 mxLeftField
->set_value(aUL
.X(), FieldUnit::NONE
);
1257 mxTopField
->set_value(aUL
.Y(), FieldUnit::NONE
);
1258 mxRightField
->set_value(aBR
.X(), FieldUnit::NONE
);
1259 mxBottomField
->set_value(aBR
.Y(), FieldUnit::NONE
);
1264 if( mrSane
.IsOpen() )
1266 SetAdjustedNumericalValue( "tl-x", static_cast<double>(aUL
.X()) );
1267 SetAdjustedNumericalValue( "tl-y", static_cast<double>(aUL
.Y()) );
1268 SetAdjustedNumericalValue( "br-x", static_cast<double>(aBR
.X()) );
1269 SetAdjustedNumericalValue( "br-y", static_cast<double>(aBR
.Y()) );
1273 bool SaneDlg::LoadState()
1277 if( ! Sane::IsSane() )
1280 const char* pEnv
= getenv("HOME");
1281 OUString aFileName
= (pEnv
? OUString(pEnv
, strlen(pEnv
), osl_getThreadTextEncoding() ) : OUString()) + "/.so_sane_state";
1282 Config
aConfig( aFileName
);
1283 if( ! aConfig
.HasGroup( "SANE" ) )
1286 aConfig
.SetGroup( "SANE"_ostr
);
1287 OString aString
= aConfig
.ReadKey( "SO_LastSaneDevice"_ostr
);
1288 for( i
= 0; i
< Sane::CountDevices() && aString
!= OUStringToOString(Sane::GetName(i
), osl_getThreadTextEncoding()); i
++ ) ;
1289 if( i
== Sane::CountDevices() )
1293 mrSane
.Open( aString
.getStr() );
1298 if( mrSane
.IsOpen() )
1300 int iMax
= aConfig
.GetKeyCount();
1301 for (i
= 0; i
< iMax
; ++i
)
1303 aString
= aConfig
.GetKeyName( i
);
1304 OString aValue
= aConfig
.ReadKey( i
);
1305 int nOption
= mrSane
.GetOptionByName( aString
.getStr() );
1309 if (aValue
.startsWith("BOOL="))
1311 aValue
= aValue
.copy(RTL_CONSTASCII_LENGTH("BOOL="));
1312 bool aBOOL
= aValue
.toInt32() != 0;
1313 mrSane
.SetOptionValue( nOption
, aBOOL
);
1315 else if (aValue
.startsWith("STRING="))
1317 aValue
= aValue
.copy(RTL_CONSTASCII_LENGTH("STRING="));
1318 mrSane
.SetOptionValue(nOption
,OStringToOUString(aValue
, osl_getThreadTextEncoding()) );
1320 else if (aValue
.startsWith("NUMERIC="))
1322 aValue
= aValue
.copy(RTL_CONSTASCII_LENGTH("NUMERIC="));
1324 sal_Int32 nIndex
= 0;
1328 OString aSub
= aValue
.getToken(0, ':', nIndex
);
1330 sscanf(aSub
.getStr(), "%lg", &fValue
);
1331 SetAdjustedNumericalValue(aString
.getStr(), fValue
, n
++);
1333 while ( nIndex
>= 0 );
1344 void SaneDlg::SaveState()
1346 if( ! Sane::IsSane() )
1349 const char* pEnv
= getenv( "HOME" );
1353 aFileName
= OUString::createFromAscii(pEnv
) + "/.so_sane_state";
1355 aFileName
= OStringToOUString("", osl_getThreadTextEncoding()) + "/.so_sane_state";
1357 Config
aConfig( aFileName
);
1358 aConfig
.DeleteGroup( "SANE" );
1359 aConfig
.SetGroup( "SANE"_ostr
);
1360 aConfig
.WriteKey( "SO_LastSANEDevice"_ostr
,
1361 OUStringToOString(mxDeviceBox
->get_active_text(), RTL_TEXTENCODING_UTF8
) );
1363 static char const* pSaveOptions
[] = {
1370 for(const char * pSaveOption
: pSaveOptions
)
1372 OString aOption
= pSaveOption
;
1373 int nOption
= mrSane
.GetOptionByName( pSaveOption
);
1376 SANE_Value_Type nType
= mrSane
.GetOptionType( nOption
);
1379 case SANE_TYPE_BOOL
:
1382 if( mrSane
.GetOptionValue( nOption
, bValue
) )
1384 OString aString
= "BOOL=" + OString::number(static_cast<sal_Int32
>(bValue
));
1385 aConfig
.WriteKey(aOption
, aString
);
1389 case SANE_TYPE_STRING
:
1392 if( mrSane
.GetOptionValue( nOption
, aValue
) )
1394 OString aString
= "STRING=" + aValue
;
1395 aConfig
.WriteKey( aOption
, aString
);
1399 case SANE_TYPE_FIXED
:
1402 OStringBuffer
aString("NUMERIC=");
1407 for( n
= 0; n
< mrSane
.GetOptionElements( nOption
); n
++ )
1409 if( ! mrSane
.GetOptionValue( nOption
, fValue
, n
) )
1412 aString
.append(':');
1413 o3tl::sprintf( buf
, "%lg", fValue
);
1414 aString
.append(buf
);
1416 if( n
>= mrSane
.GetOptionElements( nOption
) )
1417 aConfig
.WriteKey( aOption
, aString
.makeStringAndClear() );
1427 bool SaneDlg::SetAdjustedNumericalValue(
1428 const char* pOption
,
1432 if (! Sane::IsSane() || ! mrSane
.IsOpen())
1434 int const nOption(mrSane
.GetOptionByName(pOption
));
1438 if( nElement
< 0 || nElement
>= mrSane
.GetOptionElements( nOption
) )
1441 std::unique_ptr
<double[]> pValues
;
1443 if( ( nValues
= mrSane
.GetRange( nOption
, pValues
) ) < 0 )
1448 SAL_INFO("extensions.scanner", "SaneDlg::SetAdjustedNumericalValue(\"" << pOption
<< "\", " << fValue
<< ") ");
1453 double fNearest
= 1e6
;
1454 for( int i
= 0; i
< nValues
; i
++ )
1456 if( fabs( fValue
- pValues
[ i
] ) < fNearest
)
1458 fNearest
= fabs( fValue
- pValues
[ i
] );
1462 fValue
= pValues
[ nNearest
];
1466 if( fValue
< pValues
[0] )
1467 fValue
= pValues
[0];
1468 if( fValue
> pValues
[1] )
1469 fValue
= pValues
[1];
1471 mrSane
.SetOptionValue( nOption
, fValue
, nElement
);
1472 SAL_INFO("extensions.scanner", "yields " << fValue
);
1479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */