LibreOffice Module extensions (master) 1
sanedlg.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <stdlib.h>
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"
32#include "grid.hxx"
33#include <math.h>
34#include <sal/macros.h>
35#include <sal/log.hxx>
36#include <rtl/strbuf.hxx>
37#include <memory>
38#include <strings.hrc>
39
40#define PREVIEW_WIDTH 113
41#define PREVIEW_HEIGHT 160
42
43#define RECT_SIZE_PIX 7
44
45namespace {
46
47void DrawRect(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
48{
49 tools::Rectangle aRect(rRect);
50 rRenderContext.SetFillColor(COL_BLACK);
51 rRenderContext.SetLineColor();
52 rRenderContext.DrawRect(aRect);
53 aRect.Move(1, 1);
54 aRect.AdjustRight(-2);
55 aRect.AdjustBottom(-2);
56 rRenderContext.SetFillColor();
57 rRenderContext.SetLineColor(COL_WHITE);
58 rRenderContext.DrawRect(aRect);
59}
60
61void DrawRectangles(vcl::RenderContext& rRenderContext, Point const & rUL, Point const & rBR)
62{
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();
67
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);
73
74 rRenderContext.SetLineColor(COL_BLACK);
75 LineInfo aInfo(LineStyle::Dash, 1);
76 aInfo.SetDistance(8);
77 aInfo.SetDotLen(4);
78 aInfo.SetDotCount(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);
83
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));
93}
94
95}
96
98{
99private:
102
111
112public:
115 , mpParentDialog(nullptr)
117 , mbDragEnable(false)
118 , mbIsDragging(false)
119 {
120 }
121
122 void Init(SaneDlg *pParent)
123 {
124 mpParentDialog = pParent;
125 }
126
128 {
129 maTopLeft = Point();
133 }
134
136 {
137 mbDragEnable = true;
138 }
139
141 {
142 mbDragEnable = false;
143 }
144
145 bool IsDragEnabled() const
146 {
147 return mbDragEnable;
148 }
149
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;
156
157 void GetPreviewLogicRect(Point& rTopLeft, Point &rBottomRight) const
158 {
159 rTopLeft = GetLogicPos(maTopLeft);
160 rBottomRight = GetLogicPos(maBottomRight);
161 }
162 void GetMaxLogicRect(Point& rTopLeft, Point &rBottomRight) const
163 {
164 rTopLeft = maMinTopLeft;
165 rBottomRight = maMaxBottomRight;
166
167 }
169 {
170 Point aPoint(0, Y);
171 aPoint = GetPixelPos(aPoint);
172 maTopLeft.setY( aPoint.Y() );
173 }
175 {
176 Point aPoint(X, 0);
177 aPoint = GetPixelPos(aPoint);
178 maTopLeft.setX( aPoint.X() );
179 }
181 {
182 Point aPoint(0, Y);
183 aPoint = GetPixelPos(aPoint);
184 maBottomRight.setY( aPoint.Y() );
185 }
187 {
188 Point aPoint(X, 0);
189 aPoint = GetPixelPos(aPoint);
190 maBottomRight.setX( aPoint.X() );
191 }
192 void SetPreviewLogicRect(const Point& rTopLeft, const Point &rBottomRight)
193 {
194 maTopLeft = GetPixelPos(rTopLeft);
195 maBottomRight = GetPixelPos(rBottomRight);
198 maBottomRight.Y() - maTopLeft.Y()));
199 }
200 void SetPreviewMaxRect(const Point& rTopLeft, const Point &rBottomRight)
201 {
202 maMinTopLeft = rTopLeft;
203 maMaxBottomRight = rBottomRight;
204 }
205 void DrawDrag(vcl::RenderContext& rRenderContext);
206 void UpdatePreviewBounds();
207 void SetBitmap(SvStream &rStream)
208 {
209 ReadDIBBitmapEx(maPreviewBitmapEx, rStream, true);
210 }
211 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
212 {
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);
219 }
220};
221
222SaneDlg::SaneDlg(weld::Window* pParent, Sane& rSane, bool bScanEnabled)
223 : GenericDialogController(pParent, "modules/scanner/ui/sanedialog.ui", "SaneDialog")
224 , mpParent(pParent)
225 , mrSane(rSane)
226 , mbScanEnabled(bScanEnabled)
227 , mnCurrentOption(0)
228 , mnCurrentElement(0)
229 , mfMin(0.0)
230 , mfMax(0.0)
231 , doScan(false)
232 , mxCancelButton(m_xBuilder->weld_button("cancel"))
233 , mxDeviceInfoButton(m_xBuilder->weld_button("deviceInfoButton"))
234 , mxPreviewButton(m_xBuilder->weld_button("previewButton"))
235 , mxScanButton(m_xBuilder->weld_button("ok"))
236 , mxButtonOption(m_xBuilder->weld_button("optionsButton"))
237 , mxOptionTitle(m_xBuilder->weld_label("optionTitleLabel"))
238 , mxOptionDescTxt(m_xBuilder->weld_label("optionsDescLabel"))
239 , mxVectorTxt(m_xBuilder->weld_label("vectorLabel"))
240 , mxLeftField(m_xBuilder->weld_metric_spin_button("leftSpinbutton", FieldUnit::PIXEL))
241 , mxTopField(m_xBuilder->weld_metric_spin_button("topSpinbutton", FieldUnit::PIXEL))
242 , mxRightField(m_xBuilder->weld_metric_spin_button("rightSpinbutton", FieldUnit::PIXEL))
243 , mxBottomField(m_xBuilder->weld_metric_spin_button("bottomSpinbutton", FieldUnit::PIXEL))
244 , mxDeviceBox(m_xBuilder->weld_combo_box("deviceCombobox"))
245 , mxReslBox(m_xBuilder->weld_combo_box("reslCombobox"))
246 , mxAdvancedBox(m_xBuilder->weld_check_button("advancedCheckbutton"))
247 , mxVectorBox(m_xBuilder->weld_spin_button("vectorSpinbutton"))
248 , mxQuantumRangeBox(m_xBuilder->weld_combo_box("quantumRangeCombobox"))
249 , mxStringRangeBox(m_xBuilder->weld_combo_box("stringRangeCombobox"))
250 , mxBoolCheckBox(m_xBuilder->weld_check_button("boolCheckbutton"))
251 , mxStringEdit(m_xBuilder->weld_entry("stringEntry"))
252 , mxNumericEdit(m_xBuilder->weld_entry("numericEntry"))
253 , mxOptionBox(m_xBuilder->weld_tree_view("optionSvTreeListBox"))
254 , mxPreview(new ScanPreview)
255 , mxPreviewWnd(new weld::CustomWeld(*m_xBuilder, "preview", *mxPreview))
256{
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);
261 if( Sane::IsSane() )
262 {
263 InitDevices(); // opens first sane device
265 InitFields();
266 }
267
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_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 ) );
287
288 maOldLink = mrSane.SetReloadOptionsHdl( LINK( this, SaneDlg, ReloadSaneOptionsHdl ) );
289}
290
292{
294}
295
296namespace {
297
298OUString SaneResId(TranslateId aID)
299{
300 return Translate::get(aID, Translate::Create("pcr"));
301}
302
303}
304
306{
307 if (!Sane::IsSane())
308 {
309 std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(mpParent,
310 VclMessageType::Warning, VclButtonsType::Ok,
311 SaneResId(STR_COULD_NOT_BE_INIT)));
312 xErrorBox->run();
313 return RET_CANCEL;
314 }
315 LoadState();
316 return GenericDialogController::run();
317}
318
320{
321 if( ! Sane::IsSane() )
322 return;
323
324 if( mrSane.IsOpen() )
325 mrSane.Close();
327 mxDeviceBox->clear();
328 for (int i = 0; i < Sane::CountDevices(); ++i)
329 mxDeviceBox->append_text(Sane::GetName(i));
330 if( Sane::CountDevices() )
331 {
332 mrSane.Open(0);
333 mxDeviceBox->set_active(0);
334 }
335}
336
338{
339 if( ! Sane::IsSane() )
340 return;
341
342 int nOption, i, nValue;
343 double fValue;
344 const char *ppSpecialOptions[] = {
345 "resolution",
346 "tl-x",
347 "tl-y",
348 "br-x",
349 "br-y",
350 "preview"
351 };
352
353 mxPreview->EnableDrag();
354 mxReslBox->clear();
355 Point aTopLeft, aBottomRight;
356 mxPreview->GetPreviewLogicRect(aTopLeft, aBottomRight);
357 Point aMinTopLeft, aMaxBottomRight;
358 mxPreview->GetMaxLogicRect(aMinTopLeft, aMaxBottomRight);
359 mxScanButton->set_visible( mbScanEnabled );
360
361 if( ! mrSane.IsOpen() )
362 return;
363
364 // set Resolution
365 nOption = mrSane.GetOptionByName( "resolution" );
366 if( nOption != -1 )
367 {
368 double fRes;
369
370 if( mrSane.GetOptionValue( nOption, fRes ) )
371 {
372 mxReslBox->set_sensitive(true);
373
374 mxReslBox->set_entry_text(OUString::number(static_cast<sal_uInt32>(fRes)));
375 std::unique_ptr<double[]> pDouble;
376 nValue = mrSane.GetRange( nOption, pDouble );
377 if( nValue > -1 )
378 {
379 assert(pDouble);
380 if( nValue )
381 {
382 for( i=0; i<nValue; i++ )
383 {
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])));
386 }
387 }
388 else
389 {
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
393 // support that
394 // workaround: offer at least some more standard dpi resolution between
395 // min and max value
396 int bGot300 = 0;
397 for (sal_uInt32 nRes = static_cast<sal_uInt32>(pDouble[0]) * 2; nRes < static_cast<sal_uInt32>(pDouble[1]); nRes = nRes * 2)
398 {
399 if ( !bGot300 && nRes > 300 ) {
400 nRes = 300; bGot300 = 1;
401 }
402 mxReslBox->append_text(OUString::number(nRes));
403 }
404 mxReslBox->append_text(OUString::number(static_cast<sal_uInt32>(pDouble[1])));
405 }
406 }
407 else
408 mxReslBox->set_sensitive( false );
409 }
410 }
411 else
412 mxReslBox->set_sensitive( false );
413
414 // set scan area
415 for( i = 0; i < 4; i++ )
416 {
417 char const *pOptionName = nullptr;
418 weld::MetricSpinButton* pField = nullptr;
419 switch( i )
420 {
421 case 0:
422 pOptionName = "tl-x";
423 pField = mxLeftField.get();
424 break;
425 case 1:
426 pOptionName = "tl-y";
427 pField = mxTopField.get();
428 break;
429 case 2:
430 pOptionName = "br-x";
431 pField = mxRightField.get();
432 break;
433 case 3:
434 pOptionName = "br-y";
435 pField = mxBottomField.get();
436 }
437 nOption = pOptionName ? mrSane.GetOptionByName( pOptionName ) : -1;
438 if( nOption != -1 )
439 {
440 if( mrSane.GetOptionValue( nOption, fValue ) )
441 {
442 if( mrSane.GetOptionUnit( nOption ) == SANE_UNIT_MM )
443 {
444 pField->set_unit( FieldUnit::MM );
445 pField->set_value( static_cast<int>(fValue), FieldUnit::MM );
446 }
447 else // SANE_UNIT_PIXEL
448 {
449 pField->set_unit( FieldUnit::PIXEL );
450 pField->set_value( static_cast<int>(fValue), FieldUnit::PIXEL );
451 }
452 switch( i ) {
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;
457 }
458 }
459 std::unique_ptr<double[]> pDouble;
460 nValue = mrSane.GetRange( nOption, pDouble );
461 if( nValue > -1 )
462 {
463 if( pDouble )
464 {
465 pField->set_min( static_cast<tools::Long>(pDouble[0]), FieldUnit::NONE );
466 if( nValue )
467 pField->set_max( static_cast<tools::Long>(pDouble[ nValue-1 ]), FieldUnit::NONE );
468 else
469 pField->set_max( static_cast<tools::Long>(pDouble[ 1 ]), FieldUnit::NONE );
470 }
471 switch( i ) {
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;
476 }
477 }
478 else
479 {
480 switch( i ) {
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;
485 }
486 }
487 pField->set_sensitive(true);
488 }
489 else
490 {
491 mxPreview->DisableDrag();
492 pField->set_min( 0, FieldUnit::NONE );
493 switch( i ) {
494 case 0:
495 aMinTopLeft.setX( 0 );
496 aTopLeft.setX( 0 );
497 pField->set_max( PREVIEW_WIDTH, FieldUnit::NONE );
498 pField->set_value( 0, FieldUnit::NONE );
499 break;
500 case 1:
501 aMinTopLeft.setY( 0 );
502 aTopLeft.setY( 0 );
503 pField->set_max( PREVIEW_HEIGHT, FieldUnit::NONE );
504 pField->set_value( 0, FieldUnit::NONE );
505 break;
506 case 2:
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 );
511 break;
512 case 3:
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 );
517 break;
518 }
519 pField->set_sensitive(false);
520 }
521 }
522
523 mxPreview->SetPreviewMaxRect(aMinTopLeft, aMaxBottomRight);
524 mxPreview->SetPreviewLogicRect(aTopLeft, aBottomRight);
525 mxPreview->Invalidate();
526
527 // fill OptionBox
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++ )
532 {
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 )
538 {
539 if( bInsertAdvanced )
540 {
541 aOption = mrSane.GetOptionTitle( i );
542 mxOptionBox->append(xParentEntry.get());
543 mxOptionBox->set_text(*xParentEntry, aOption, 0);
544 bGroupRejected = false;
545 }
546 else
547 bGroupRejected = true;
548 }
549 else if( !aOption.isEmpty() &&
550 ! ( mrSane.GetOptionCap( i ) &
551 (
552 SANE_CAP_HARD_SELECT |
553 SANE_CAP_INACTIVE
554 ) ) &&
555 bInsertAdvanced && ! bGroupRejected )
556 {
557 bool bIsSpecial = false;
558 for( size_t n = 0; !bIsSpecial &&
559 n < SAL_N_ELEMENTS(ppSpecialOptions); n++ )
560 {
561 if( aOption == OUString::createFromAscii(ppSpecialOptions[n]) )
562 bIsSpecial=true;
563 }
564 if( ! bIsSpecial )
565 {
566 if (xParentEntry)
567 mxOptionBox->append(xParentEntry.get(), aOption);
568 else
569 mxOptionBox->append_text(aOption);
570 }
571 }
572 }
573}
574
575IMPL_LINK( SaneDlg, ClickBtnHdl, weld::Button&, rButton, void )
576{
577 if( mrSane.IsOpen() )
578 {
579 if( &rButton == mxDeviceInfoButton.get() )
580 {
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,
588 aString));
589 xInfoBox->run();
590 }
591 else if( &rButton == mxPreviewButton.get() )
592 AcquirePreview();
593 else if( &rButton == mxButtonOption.get() )
594 {
595
596 SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption );
597 switch( nType )
598 {
599 case SANE_TYPE_BUTTON:
600 mrSane.ActivateButtonOption( mnCurrentOption );
601 break;
602 case SANE_TYPE_FIXED:
603 case SANE_TYPE_INT:
604 {
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() );
611
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() );
617 }
618 break;
619 case SANE_TYPE_BOOL:
620 case SANE_TYPE_STRING:
621 case SANE_TYPE_GROUP:
622 break;
623 }
624 }
625 }
626 if (&rButton == mxScanButton.get())
627 {
628 double fRes = static_cast<double>(mxReslBox->get_active_text().toUInt32());
629 SetAdjustedNumericalValue( "resolution", fRes );
630 UpdateScanArea(true);
631 SaveState();
632 m_xDialog->response(mrSane.IsOpen() ? RET_OK : RET_CANCEL);
633 doScan = mrSane.IsOpen();
634 }
635 else if( &rButton == mxCancelButton.get() )
636 {
637 mrSane.Close();
638 m_xDialog->response(RET_CANCEL);
639 }
640}
641
642IMPL_LINK( SaneDlg, ToggleBtnHdl, weld::Toggleable&, rButton, void )
643{
644 if( mrSane.IsOpen() )
645 {
646 if( &rButton == mxBoolCheckBox.get() )
647 {
648 mrSane.SetOptionValue( mnCurrentOption,
649 mxBoolCheckBox->get_active() );
650 }
651 else if( &rButton == mxAdvancedBox.get() )
652 {
653 ReloadSaneOptionsHdl( mrSane );
654 }
655 }
656}
657
658IMPL_LINK( SaneDlg, SelectHdl, weld::ComboBox&, rListBox, void )
659{
660 if( &rListBox == mxDeviceBox.get() && Sane::IsSane() && Sane::CountDevices() )
661 {
662 int nNewNumber = mxDeviceBox->get_active();
663 int nOldNumber = mrSane.GetDeviceNumber();
664 if (nNewNumber != nOldNumber)
665 {
666 mrSane.Close();
667 mrSane.Open(nNewNumber);
668 mxPreview->ResetForNewScanner();
669 InitFields();
670 }
671 }
672 if( mrSane.IsOpen() )
673 {
674 if( &rListBox == mxQuantumRangeBox.get() )
675 {
676 double fValue = mxQuantumRangeBox->get_active_text().toDouble();
677 mrSane.SetOptionValue(mnCurrentOption, fValue, mnCurrentElement);
678 }
679 else if( &rListBox == mxStringRangeBox.get() )
680 {
681 mrSane.SetOptionValue(mnCurrentOption, mxStringRangeBox->get_active_text());
682 }
683 }
684}
685
686IMPL_LINK_NOARG(SaneDlg, OptionsBoxSelectHdl, weld::TreeView&, void)
687{
688 if (!Sane::IsSane())
689 return;
690
691 OUString aOption = mxOptionBox->get_selected_text();
692 int nOption = mrSane.GetOptionByName(OUStringToOString(aOption,
693 osl_getThreadTextEncoding()).getStr());
694 if( nOption == -1 || nOption == mnCurrentOption )
695 return;
696
697 DisableOption();
698 mnCurrentOption = nOption;
699 mxOptionTitle->set_label(mrSane.GetOptionTitle(mnCurrentOption));
700 SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption );
701 SANE_Constraint_Type nConstraint;
702 switch( nType )
703 {
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();
709 else
710 EstablishStringOption();
711 break;
712 case SANE_TYPE_FIXED:
713 case SANE_TYPE_INT:
714 {
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();
721 else
722 {
723 mfMin = mfMax = 0.0;
724 EstablishNumericOption();
725 }
726 if( nElements > 1 )
727 {
728 if( nElements <= 10 )
729 {
730 mxVectorBox->set_range(1, mrSane.GetOptionElements(mnCurrentOption));
731 mxVectorBox->set_value(1);
732 mxVectorBox->show();
733 mxVectorTxt->show();
734 }
735 else
736 {
737 DisableOption();
738 // bring up dialog only on button click
739 EstablishButtonOption();
740 }
741 }
742 }
743 break;
744 case SANE_TYPE_BUTTON:
745 EstablishButtonOption();
746 break;
747 default: break;
748 }
749}
750
751IMPL_LINK(SaneDlg, ModifyHdl, weld::Entry&, rEdit, void)
752{
753 if( !mrSane.IsOpen() )
754 return;
755
756 if (&rEdit == mxStringEdit.get())
757 {
758 mrSane.SetOptionValue( mnCurrentOption, mxStringEdit->get_text() );
759 }
760 else if (&rEdit == mxNumericEdit.get())
761 {
762 double fValue = mxNumericEdit->get_text().toDouble();
763 if( mfMin != mfMax && ( fValue < mfMin || fValue > mfMax ) )
764 {
765 char pBuf[256];
766 if( fValue < mfMin )
767 fValue = mfMin;
768 else if( fValue > mfMax )
769 fValue = mfMax;
770 o3tl::sprintf( pBuf, "%g", fValue );
771 mxNumericEdit->set_text( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) );
772 }
773 mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement );
774 }
775 else if (&rEdit == mxVectorBox.get())
776 {
777 mnCurrentElement = mxVectorBox->get_value() - 1;
778 double fValue;
779 if( mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement ))
780 {
781 char pBuf[256];
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 );
786 }
787 }
788}
789
790IMPL_LINK(SaneDlg, ValueModifyHdl, weld::ComboBox&, rEdit, void)
791{
792 if( !mrSane.IsOpen() )
793 return;
794
795 if (&rEdit != mxReslBox.get())
796 return;
797
798 double fRes = static_cast<double>(mxReslBox->get_active_text().toUInt32());
799 int nOption = mrSane.GetOptionByName( "resolution" );
800 if( nOption == -1 )
801 return;
802
803 std::unique_ptr<double[]> pDouble;
804 int nValues = mrSane.GetRange( nOption, pDouble );
805 if( nValues > 0 )
806 {
807 int i;
808 for( i = 0; i < nValues; i++ )
809 {
810 if( fRes == pDouble[i] )
811 break;
812 }
813 if( i >= nValues )
814 fRes = pDouble[0];
815 }
816 else if( nValues == 0 )
817 {
818 if( fRes < pDouble[ 0 ] )
819 fRes = pDouble[ 0 ];
820 if( fRes > pDouble[ 1 ] )
821 fRes = pDouble[ 1 ];
822 }
823 mxReslBox->set_entry_text(OUString::number(static_cast<sal_uInt32>(fRes)));
824}
825
826IMPL_LINK(SaneDlg, MetricValueModifyHdl, weld::MetricSpinButton&, rEdit, void)
827{
828 if( !mrSane.IsOpen() )
829 return;
830
831 if (&rEdit == mxTopField.get())
832 {
833 mxPreview->ChangePreviewLogicTopLeftY(mxTopField->get_value(FieldUnit::NONE));
834 mxPreview->Invalidate();
835 }
836 else if (&rEdit == mxLeftField.get())
837 {
838 mxPreview->ChangePreviewLogicTopLeftX(mxLeftField->get_value(FieldUnit::NONE));
839 mxPreview->Invalidate();
840 }
841 else if (&rEdit == mxBottomField.get())
842 {
843 mxPreview->ChangePreviewLogicBottomRightY(mxBottomField->get_value(FieldUnit::NONE));
844 mxPreview->Invalidate();
845 }
846 else if (&rEdit == mxRightField.get())
847 {
848 mxPreview->ChangePreviewLogicBottomRightX(mxRightField->get_value(FieldUnit::NONE));
849 mxPreview->Invalidate();
850 }
851}
852
853IMPL_LINK_NOARG( SaneDlg, ReloadSaneOptionsHdl, Sane&, void )
854{
855 mnCurrentOption = -1;
856 mnCurrentElement = 0;
857 DisableOption();
858 InitFields();
859 mxPreview->Invalidate();
860}
861
863{
864 if( ! mrSane.IsOpen() )
865 return;
866
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 );
871
872 int nOption = mrSane.GetOptionByName( "preview" );
873 if( nOption == -1 )
874 {
875 OUString aString(SaneResId(STR_SLOW_PREVIEW));
876 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
877 VclMessageType::Warning, VclButtonsType::OkCancel,
878 aString));
879 if (xBox->run() == RET_CANCEL)
880 return;
881 }
882 else
883 mrSane.SetOptionValue( nOption, true );
884
886 if (!mrSane.Start(*xTransporter))
887 {
888 std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
889 VclMessageType::Warning, VclButtonsType::Ok,
890 SaneResId(STR_ERROR_SCAN)));
891 xErrorBox->run();
892 }
893 else
894 {
895#if OSL_DEBUG_LEVEL > 0
896 SAL_INFO("extensions.scanner", "Previewbitmapstream contains " << xTransporter->getStream().TellEnd() << "bytes");
897#endif
898 xTransporter->getStream().Seek( STREAM_SEEK_TO_BEGIN );
899 mxPreview->SetBitmap(xTransporter->getStream());
900 }
901
902 SetAdjustedNumericalValue( "resolution", fResl );
903 mxReslBox->set_entry_text(OUString::number(static_cast<sal_uInt32>(fResl)));
904
905 mxPreview->UpdatePreviewBounds();
906 mxPreview->Invalidate();
907}
908
910{
911 if( mbDragEnable )
912 {
915 maBottomRight.Y() - maTopLeft.Y() )
916 );
917 }
918 else
919 {
921 if( aBMSize.Width() > aBMSize.Height() && aBMSize.Width() )
922 {
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 ),
926 nVHeight ) );
927 }
928 else if (aBMSize.Height())
929 {
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() ),
932 Size( nVWidth,
933 maBottomRight.Y() - maTopLeft.Y() ) );
934 }
935 }
936}
937
939{
940 rRenderContext.SetMapMode(MapMode(MapUnit::MapAppFont));
941 rRenderContext.SetFillColor(COL_WHITE);
942 rRenderContext.SetLineColor(COL_WHITE);
943 rRenderContext.DrawRect(tools::Rectangle(Point(0, 0),
945 rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel));
946 // check for sane values
948
949 DrawDrag(rRenderContext);
950}
951
953{
954 mxBoolCheckBox->hide();
955 mxStringEdit->hide();
956 mxNumericEdit->hide();
957 mxQuantumRangeBox->hide();
958 mxStringRangeBox->hide();
959 mxButtonOption->hide();
960 mxVectorBox->hide();
961 mxVectorTxt->hide();
962 mxOptionDescTxt->hide();
963}
964
966{
967 bool bSuccess, bValue;
968
969 bSuccess = mrSane.GetOptionValue( mnCurrentOption, bValue );
970 if( bSuccess )
971 {
973 mxBoolCheckBox->set_active( bValue );
974 mxBoolCheckBox->show();
975 }
976}
977
979{
980 bool bSuccess;
981 OString aValue;
982
983 bSuccess = mrSane.GetOptionValue( mnCurrentOption, aValue );
984 if( bSuccess )
985 {
987 mxOptionDescTxt->show();
988 mxStringEdit->set_text(OStringToOUString(aValue, osl_getThreadTextEncoding()));
989 mxStringEdit->show();
990 }
991}
992
994{
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() ) );
999 OString aValue;
1001 mxStringRangeBox->set_active_text(OStringToOUString(aValue, osl_getThreadTextEncoding()));
1002 mxStringRangeBox->show();
1004 mxOptionDescTxt->show();
1005}
1006
1008{
1009 mpRange.reset();
1010 int nValues = mrSane.GetRange( mnCurrentOption, mpRange );
1011 if( nValues == 0 )
1012 {
1013 mfMin = mpRange[ 0 ];
1014 mfMax = mpRange[ 1 ];
1015 mpRange.reset();
1017 }
1018 else if( nValues > 0 )
1019 {
1020 char pBuf[ 256 ];
1021 mxQuantumRangeBox->clear();
1022 mfMin = mpRange[ 0 ];
1023 mfMax = mpRange[ nValues-1 ];
1024 for( int i = 0; i < nValues; i++ )
1025 {
1026 o3tl::sprintf( pBuf, "%g", mpRange[ i ] );
1027 mxQuantumRangeBox->append_text( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) );
1028 }
1029 double fValue;
1031 {
1032 o3tl::sprintf( pBuf, "%g", fValue );
1033 mxQuantumRangeBox->set_active_text( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) );
1034 }
1035 mxQuantumRangeBox->show();
1036 OUString aText = mrSane.GetOptionName( mnCurrentOption ) + " "
1038 mxOptionDescTxt->set_label(aText);
1039 mxOptionDescTxt->show();
1040 }
1041}
1042
1044{
1045 bool bSuccess;
1046 double fValue;
1047
1048 bSuccess = mrSane.GetOptionValue( mnCurrentOption, fValue );
1049 if( ! bSuccess )
1050 return;
1051
1052 char pBuf[256];
1053 OUString aText = mrSane.GetOptionName( mnCurrentOption ) + " "
1055 if( mfMin != mfMax )
1056 {
1057 o3tl::sprintf( pBuf, " < %g ; %g >", mfMin, mfMax );
1058 aText += OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() );
1059 }
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();
1065}
1066
1068{
1070 mxOptionDescTxt->show();
1071 mxButtonOption->show();
1072}
1073
1075{
1076 if( !mbIsDragging )
1077 return false;
1078
1079 Point aMousePos = rMEvt.GetPosPixel();
1080 // move into valid area
1081 Point aLogicPos = GetLogicPos( aMousePos );
1082 aMousePos = GetPixelPos( aLogicPos );
1083 switch( meDragDirection )
1084 {
1085 case TopLeft: maTopLeft = aMousePos; break;
1086 case Top: maTopLeft.setY( aMousePos.Y() ); break;
1087 case TopRight:
1088 maTopLeft.setY( aMousePos.Y() );
1089 maBottomRight.setX( aMousePos.X() );
1090 break;
1091 case Right: maBottomRight.setX( aMousePos.X() ); break;
1092 case BottomRight: maBottomRight = aMousePos; break;
1093 case Bottom: maBottomRight.setY( aMousePos.Y() ); break;
1094 case BottomLeft:
1095 maTopLeft.setX( aMousePos.X() );
1096 maBottomRight.setY( aMousePos.Y() );
1097 break;
1098 case Left: maTopLeft.setX( aMousePos.X() ); break;
1099 default: break;
1100 }
1101 int nSwap;
1102 if( maTopLeft.X() > maBottomRight.X() )
1103 {
1104 nSwap = maTopLeft.X();
1106 maBottomRight.setX( nSwap );
1107 }
1108 if( maTopLeft.Y() > maBottomRight.Y() )
1109 {
1110 nSwap = maTopLeft.Y();
1112 maBottomRight.setY( nSwap );
1113 }
1114 Invalidate();
1116 return false;
1117}
1118
1120{
1121 if (!mbIsDragging && mbDragEnable)
1122 {
1123 Point aMousePixel = rMEvt.GetPosPixel();
1124
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 )
1129 {
1130 if( aMousePixel.X() >= maTopLeft.X() &&
1131 aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1132 {
1134 mbIsDragging = true;
1135 }
1136 else if( aMousePixel.X() >= nMiddleX &&
1137 aMousePixel.X() < nMiddleX + RECT_SIZE_PIX )
1138 {
1140 mbIsDragging = true;
1141 }
1142 else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1143 aMousePixel.X() <= maBottomRight.X() )
1144 {
1146 mbIsDragging = true;
1147 }
1148 }
1149 else if( aMousePixel.Y() >= nMiddleY &&
1150 aMousePixel.Y() < nMiddleY + RECT_SIZE_PIX )
1151 {
1152 if( aMousePixel.X() >= maTopLeft.X() &&
1153 aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1154 {
1156 mbIsDragging = true;
1157 }
1158 else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1159 aMousePixel.X() <= maBottomRight.X() )
1160 {
1162 mbIsDragging = true;
1163 }
1164 }
1165 else if( aMousePixel.Y() <= maBottomRight.Y() &&
1166 aMousePixel.Y() > maBottomRight.Y() - RECT_SIZE_PIX )
1167 {
1168 if( aMousePixel.X() >= maTopLeft.X() &&
1169 aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1170 {
1172 mbIsDragging = true;
1173 }
1174 else if( aMousePixel.X() >= nMiddleX &&
1175 aMousePixel.X() < nMiddleX + RECT_SIZE_PIX )
1176 {
1178 mbIsDragging = true;
1179 }
1180 else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1181 aMousePixel.X() <= maBottomRight.X() )
1182 {
1184 mbIsDragging = true;
1185 }
1186 }
1187 }
1188
1189 if( mbIsDragging )
1190 Invalidate();
1191
1192 return false;
1193}
1194
1196{
1197 if( mbIsDragging )
1199 mbIsDragging = false;
1200
1201 return false;
1202}
1203
1205{
1206 if (!mbDragEnable)
1207 return;
1208
1209 rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel));
1210
1211 DrawRectangles(rRenderContext, maTopLeft, maBottomRight);
1212
1213 rRenderContext.SetMapMode(MapMode(MapUnit::MapAppFont));
1214}
1215
1217{
1218 Point aConvert(
1219 ( ( rIn.X() * PREVIEW_WIDTH ) /
1220 ( maMaxBottomRight.X() - maMinTopLeft.X() ) )
1221 ,
1222 ( ( rIn.Y() * PREVIEW_HEIGHT )
1223 / ( maMaxBottomRight.Y() - maMinTopLeft.Y() ) )
1224 );
1225
1226 return GetDrawingArea()->get_ref_device().LogicToPixel(aConvert, MapMode(MapUnit::MapAppFont));
1227}
1228
1230{
1231 Point aConvert = GetDrawingArea()->get_ref_device().PixelToLogic(rIn, MapMode(MapUnit::MapAppFont));
1232 if( aConvert.X() < 0 )
1233 aConvert.setX( 0 );
1234 if( aConvert.X() >= PREVIEW_WIDTH )
1235 aConvert.setX( PREVIEW_WIDTH-1 );
1236 if( aConvert.Y() < 0 )
1237 aConvert.setY( 0 );
1238 if( aConvert.Y() >= PREVIEW_HEIGHT )
1239 aConvert.setY( PREVIEW_HEIGHT-1 );
1240
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) );
1245 return aConvert;
1246}
1247
1249{
1250 if (!mxPreview->IsDragEnabled())
1251 return;
1252
1253 Point aUL, aBR;
1254 mxPreview->GetPreviewLogicRect(aUL, aBR);
1255
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);
1260
1261 if (!bSend)
1262 return;
1263
1264 if( mrSane.IsOpen() )
1265 {
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()) );
1270 }
1271}
1272
1274{
1275 int i;
1276
1277 if( ! Sane::IsSane() )
1278 return false;
1279
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" ) )
1284 return false;
1285
1286 aConfig.SetGroup( "SANE" );
1287 OString aString = aConfig.ReadKey( "SO_LastSaneDevice" );
1288 for( i = 0; i < Sane::CountDevices() && aString != OUStringToOString(Sane::GetName(i), osl_getThreadTextEncoding()); i++ ) ;
1289 if( i == Sane::CountDevices() )
1290 return false;
1291
1292 mrSane.Close();
1293 mrSane.Open( aString.getStr() );
1294
1295 DisableOption();
1296 InitFields();
1297
1298 if( mrSane.IsOpen() )
1299 {
1300 int iMax = aConfig.GetKeyCount();
1301 for (i = 0; i < iMax; ++i)
1302 {
1303 aString = aConfig.GetKeyName( i );
1304 OString aValue = aConfig.ReadKey( i );
1305 int nOption = mrSane.GetOptionByName( aString.getStr() );
1306 if( nOption == -1 )
1307 continue;
1308
1309 if (aValue.startsWith("BOOL="))
1310 {
1311 aValue = aValue.copy(RTL_CONSTASCII_LENGTH("BOOL="));
1312 bool aBOOL = aValue.toInt32() != 0;
1313 mrSane.SetOptionValue( nOption, aBOOL );
1314 }
1315 else if (aValue.startsWith("STRING="))
1316 {
1317 aValue = aValue.copy(RTL_CONSTASCII_LENGTH("STRING="));
1318 mrSane.SetOptionValue(nOption,OStringToOUString(aValue, osl_getThreadTextEncoding()) );
1319 }
1320 else if (aValue.startsWith("NUMERIC="))
1321 {
1322 aValue = aValue.copy(RTL_CONSTASCII_LENGTH("NUMERIC="));
1323
1324 sal_Int32 nIndex = 0;
1325 int n = 0;
1326 do
1327 {
1328 OString aSub = aValue.getToken(0, ':', nIndex);
1329 double fValue=0.0;
1330 sscanf(aSub.getStr(), "%lg", &fValue);
1331 SetAdjustedNumericalValue(aString.getStr(), fValue, n++);
1332 }
1333 while ( nIndex >= 0 );
1334 }
1335 }
1336 }
1337
1338 DisableOption();
1339 InitFields();
1340
1341 return true;
1342}
1343
1345{
1346 if( ! Sane::IsSane() )
1347 return;
1348
1349 const char* pEnv = getenv( "HOME" );
1350 OUString aFileName;
1351
1352 if( pEnv )
1353 aFileName = OUString::createFromAscii(pEnv) + "/.so_sane_state";
1354 else
1355 aFileName = OStringToOUString("", osl_getThreadTextEncoding()) + "/.so_sane_state";
1356
1357 Config aConfig( aFileName );
1358 aConfig.DeleteGroup( "SANE" );
1359 aConfig.SetGroup( "SANE" );
1360 aConfig.WriteKey( "SO_LastSANEDevice",
1361 OUStringToOString(mxDeviceBox->get_active_text(), RTL_TEXTENCODING_UTF8) );
1362
1363 static char const* pSaveOptions[] = {
1364 "resolution",
1365 "tl-x",
1366 "tl-y",
1367 "br-x",
1368 "br-y"
1369 };
1370 for(const char * pSaveOption : pSaveOptions)
1371 {
1372 OString aOption = pSaveOption;
1373 int nOption = mrSane.GetOptionByName( pSaveOption );
1374 if( nOption > -1 )
1375 {
1376 SANE_Value_Type nType = mrSane.GetOptionType( nOption );
1377 switch( nType )
1378 {
1379 case SANE_TYPE_BOOL:
1380 {
1381 bool bValue;
1382 if( mrSane.GetOptionValue( nOption, bValue ) )
1383 {
1384 OString aString = "BOOL=" + OString::number(static_cast<sal_Int32>(bValue));
1385 aConfig.WriteKey(aOption, aString);
1386 }
1387 }
1388 break;
1389 case SANE_TYPE_STRING:
1390 {
1391 OString aValue;
1392 if( mrSane.GetOptionValue( nOption, aValue ) )
1393 {
1394 OString aString = "STRING=" + aValue;
1395 aConfig.WriteKey( aOption, aString );
1396 }
1397 }
1398 break;
1399 case SANE_TYPE_FIXED:
1400 case SANE_TYPE_INT:
1401 {
1402 OStringBuffer aString("NUMERIC=");
1403 double fValue;
1404 char buf[256];
1405 int n;
1406
1407 for( n = 0; n < mrSane.GetOptionElements( nOption ); n++ )
1408 {
1409 if( ! mrSane.GetOptionValue( nOption, fValue, n ) )
1410 break;
1411 if( n > 0 )
1412 aString.append(':');
1413 o3tl::sprintf( buf, "%lg", fValue );
1414 aString.append(buf);
1415 }
1416 if( n >= mrSane.GetOptionElements( nOption ) )
1417 aConfig.WriteKey( aOption, aString.makeStringAndClear() );
1418 }
1419 break;
1420 default:
1421 break;
1422 }
1423 }
1424 }
1425}
1426
1428 const char* pOption,
1429 double fValue,
1430 int nElement )
1431{
1432 if (! Sane::IsSane() || ! mrSane.IsOpen())
1433 return false;
1434 int const nOption(mrSane.GetOptionByName(pOption));
1435 if (nOption == -1)
1436 return false;
1437
1438 if( nElement < 0 || nElement >= mrSane.GetOptionElements( nOption ) )
1439 return false;
1440
1441 std::unique_ptr<double[]> pValues;
1442 int nValues;
1443 if( ( nValues = mrSane.GetRange( nOption, pValues ) ) < 0 )
1444 {
1445 return false;
1446 }
1447
1448 SAL_INFO("extensions.scanner", "SaneDlg::SetAdjustedNumericalValue(\"" << pOption << "\", " << fValue << ") ");
1449
1450 if( nValues )
1451 {
1452 int nNearest = 0;
1453 double fNearest = 1e6;
1454 for( int i = 0; i < nValues; i++ )
1455 {
1456 if( fabs( fValue - pValues[ i ] ) < fNearest )
1457 {
1458 fNearest = fabs( fValue - pValues[ i ] );
1459 nNearest = i;
1460 }
1461 }
1462 fValue = pValues[ nNearest ];
1463 }
1464 else
1465 {
1466 if( fValue < pValues[0] )
1467 fValue = pValues[0];
1468 if( fValue > pValues[1] )
1469 fValue = pValues[1];
1470 }
1471 mrSane.SetOptionValue( nOption, fValue, nElement );
1472 SAL_INFO("extensions.scanner", "yields " << fValue);
1473
1474
1475 return true;
1476}
1477
1478
1479/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const PropertyValue * pValues
Reference< XExecutableDialog > m_xDialog
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
const Size & GetSizePixel() const
OString GetKeyName(sal_uInt16 nKey) const
void SetGroup(const OString &rGroup)
void DeleteGroup(std::string_view rGroup)
sal_uInt16 GetKeyCount() const
OString ReadKey(const OString &rKey) const
bool HasGroup(std::string_view rGroup) const
void WriteKey(const OString &rKey, const OString &rValue)
void setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY)
Definition: grid.cxx:422
double * getNewYValues()
Definition: grid.cxx:694
void SetDotCount(sal_uInt16 nDotCount)
void SetDistance(double nDistance)
void SetDotLen(double nDotLen)
const Point & GetPosPixel() const
void DrawBitmapEx(const Point &rDestPt, const BitmapEx &rBitmapEx)
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
void DrawRect(const tools::Rectangle &rRect)
void DrawLine(const Point &rStartPt, const Point &rEndPt)
void SetLineColor()
void SetMapMode()
void SetFillColor()
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
constexpr tools::Long Y() const
void setX(tools::Long nX)
void setY(tools::Long nY)
constexpr tools::Long X() const
std::unique_ptr< weld::CheckButton > mxBoolCheckBox
Definition: sanedlg.hxx:67
Link< Sane &, void > maOldLink
Definition: sanedlg.hxx:35
std::unique_ptr< weld::ComboBox > mxQuantumRangeBox
Definition: sanedlg.hxx:64
void EstablishBoolOption()
Definition: sanedlg.cxx:965
std::unique_ptr< weld::MetricSpinButton > mxBottomField
Definition: sanedlg.hxx:57
void UpdateScanArea(bool)
Definition: sanedlg.cxx:1248
std::unique_ptr< weld::MetricSpinButton > mxTopField
Definition: sanedlg.hxx:55
std::unique_ptr< weld::Button > mxPreviewButton
Definition: sanedlg.hxx:46
std::unique_ptr< weld::SpinButton > mxVectorBox
Definition: sanedlg.hxx:63
std::unique_ptr< weld::CheckButton > mxAdvancedBox
Definition: sanedlg.hxx:61
void AcquirePreview()
Definition: sanedlg.cxx:862
int mnCurrentElement
Definition: sanedlg.hxx:38
std::unique_ptr< weld::MetricSpinButton > mxRightField
Definition: sanedlg.hxx:56
virtual ~SaneDlg() override
Definition: sanedlg.cxx:291
std::unique_ptr< weld::ComboBox > mxDeviceBox
Definition: sanedlg.hxx:59
std::unique_ptr< weld::TreeView > mxOptionBox
Definition: sanedlg.hxx:72
bool SetAdjustedNumericalValue(const char *pOption, double fValue, int nElement=0)
Definition: sanedlg.cxx:1427
void SaveState()
Definition: sanedlg.cxx:1344
std::unique_ptr< weld::Label > mxOptionTitle
Definition: sanedlg.hxx:50
std::unique_ptr< ScanPreview > mxPreview
Definition: sanedlg.hxx:74
SaneDlg(weld::Window *, Sane &, bool)
Definition: sanedlg.cxx:222
void EstablishButtonOption()
Definition: sanedlg.cxx:1067
std::unique_ptr< double[]> mpRange
Definition: sanedlg.hxx:39
void InitFields()
Definition: sanedlg.cxx:337
std::unique_ptr< weld::ComboBox > mxStringRangeBox
Definition: sanedlg.hxx:65
void EstablishStringRange()
Definition: sanedlg.cxx:993
void EstablishQuantumRange()
Definition: sanedlg.cxx:1007
std::unique_ptr< weld::Button > mxButtonOption
Definition: sanedlg.hxx:48
int mnCurrentOption
Definition: sanedlg.hxx:37
void DisableOption()
Definition: sanedlg.cxx:952
virtual short run() override
Definition: sanedlg.cxx:305
void EstablishStringOption()
Definition: sanedlg.cxx:978
Sane & mrSane
Definition: sanedlg.hxx:32
std::unique_ptr< weld::ComboBox > mxReslBox
Definition: sanedlg.hxx:60
std::unique_ptr< weld::Label > mxOptionDescTxt
Definition: sanedlg.hxx:51
std::unique_ptr< weld::Label > mxVectorTxt
Definition: sanedlg.hxx:52
std::unique_ptr< weld::MetricSpinButton > mxLeftField
Definition: sanedlg.hxx:54
std::unique_ptr< weld::Entry > mxStringEdit
Definition: sanedlg.hxx:69
bool LoadState()
Definition: sanedlg.cxx:1273
std::unique_ptr< weld::Entry > mxNumericEdit
Definition: sanedlg.hxx:70
void InitDevices()
Definition: sanedlg.cxx:319
std::unique_ptr< weld::Button > mxScanButton
Definition: sanedlg.hxx:47
weld::Window * mpParent
Definition: sanedlg.hxx:31
std::unique_ptr< weld::Button > mxCancelButton
Definition: sanedlg.hxx:44
std::unique_ptr< weld::Button > mxDeviceInfoButton
Definition: sanedlg.hxx:45
bool mbScanEnabled
Definition: sanedlg.hxx:33
double mfMin
Definition: sanedlg.hxx:40
void EstablishNumericOption()
Definition: sanedlg.cxx:1043
double mfMax
Definition: sanedlg.hxx:40
Definition: sane.hxx:60
static OUString GetVendor(int n)
Definition: sane.hxx:119
SANE_Unit GetOptionUnit(int n)
Definition: sane.hxx:132
bool GetOptionValue(int, bool &)
Definition: sane.cxx:343
bool IsOpen() const
Definition: sane.hxx:113
OUString GetOptionUnitName(int n)
Definition: sane.cxx:978
void Close()
Definition: sane.cxx:320
int GetOptionByName(const char *)
Definition: sane.cxx:331
bool Start(BitmapTransporter &)
Definition: sane.cxx:537
SANE_Int GetOptionCap(int n)
Definition: sane.hxx:135
OUString GetOptionName(int n)
Definition: sane.hxx:126
int GetOptionElements(int n)
Definition: sane.hxx:172
int GetRange(int, std::unique_ptr< double[]> &)
Definition: sane.cxx:902
SANE_Value_Type GetOptionType(int n)
Definition: sane.hxx:130
bool Open(const char *)
Definition: sane.cxx:287
Link< Sane &, void > SetReloadOptionsHdl(const Link< Sane &, void > &rLink)
Definition: sane.hxx:183
static OUString GetModel(int n)
Definition: sane.hxx:121
int CountOptions()
Definition: sane.hxx:157
static OUString GetName(int n)
Definition: sane.hxx:117
void ReloadDevices()
Definition: sane.cxx:254
void SetOptionValue(int, bool)
Definition: sane.cxx:412
static bool IsSane()
Definition: sane.hxx:111
static OUString GetType(int n)
Definition: sane.hxx:123
static int CountDevices()
Definition: sane.hxx:115
const char ** GetStringConstraint(int n)
Definition: sane.hxx:139
OUString GetOptionTitle(int n)
Definition: sane.hxx:128
BitmapEx maPreviewBitmapEx
Definition: sanedlg.cxx:103
Point maBottomRight
Definition: sanedlg.cxx:105
void SetPreviewLogicRect(const Point &rTopLeft, const Point &rBottomRight)
Definition: sanedlg.cxx:192
bool mbDragEnable
Definition: sanedlg.cxx:109
SaneDlg * mpParentDialog
Definition: sanedlg.cxx:107
void SetPreviewMaxRect(const Point &rTopLeft, const Point &rBottomRight)
Definition: sanedlg.cxx:200
void GetMaxLogicRect(Point &rTopLeft, Point &rBottomRight) const
Definition: sanedlg.cxx:162
Point GetLogicPos(const Point &rIn) const
Definition: sanedlg.cxx:1229
void UpdatePreviewBounds()
Definition: sanedlg.cxx:909
virtual bool MouseButtonDown(const MouseEvent &rMEvt) override
Definition: sanedlg.cxx:1119
bool IsDragEnabled() const
Definition: sanedlg.cxx:145
void SetBitmap(SvStream &rStream)
Definition: sanedlg.cxx:207
void ChangePreviewLogicBottomRightX(tools::Long X)
Definition: sanedlg.cxx:186
void EnableDrag()
Definition: sanedlg.cxx:135
void ChangePreviewLogicTopLeftY(tools::Long Y)
Definition: sanedlg.cxx:168
void ChangePreviewLogicTopLeftX(tools::Long X)
Definition: sanedlg.cxx:174
bool mbIsDragging
Definition: sanedlg.cxx:110
void Init(SaneDlg *pParent)
Definition: sanedlg.cxx:122
Point maMinTopLeft
Definition: sanedlg.cxx:106
Point maMaxBottomRight
Definition: sanedlg.cxx:106
Point GetPixelPos(const Point &rIn) const
Definition: sanedlg.cxx:1216
void DisableDrag()
Definition: sanedlg.cxx:140
void GetPreviewLogicRect(Point &rTopLeft, Point &rBottomRight) const
Definition: sanedlg.cxx:157
tools::Rectangle maPreviewRect
Definition: sanedlg.cxx:104
DragDirection meDragDirection
Definition: sanedlg.cxx:108
void ChangePreviewLogicBottomRightY(tools::Long Y)
Definition: sanedlg.cxx:180
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: sanedlg.cxx:938
virtual void SetDrawingArea(weld::DrawingArea *pDrawingArea) override
Definition: sanedlg.cxx:211
void DrawDrag(vcl::RenderContext &rRenderContext)
Definition: sanedlg.cxx:1204
virtual bool MouseMove(const MouseEvent &rMEvt) override
Definition: sanedlg.cxx:1074
Point maTopLeft
Definition: sanedlg.cxx:105
void ResetForNewScanner()
Definition: sanedlg.cxx:127
virtual bool MouseButtonUp(const MouseEvent &rMEvt) override
Definition: sanedlg.cxx:1195
constexpr tools::Long getHeight() const
constexpr tools::Long Height() const
constexpr tools::Long getWidth() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
constexpr Point TopLeft() const
constexpr Size GetSize() const
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
weld::DrawingArea * GetDrawingArea() const
void SetOutputSizePixel(const Size &rSize)
virtual short run()
void set_title(const OUString &rTitle)
virtual OutputDevice & get_ref_device()=0
std::shared_ptr< weld::Dialog > m_xDialog
sal_Int64 get_max(FieldUnit eValueUnit) const
void set_sensitive(bool sensitive)
void set_unit(FieldUnit eUnit)
sal_Int64 get_min(FieldUnit eValueUnit) const
void set_value(sal_Int64 nValue, FieldUnit eValueUnit)
void set_max(sal_Int64 max, FieldUnit eValueUnit)
void set_min(sal_Int64 min, FieldUnit eValueUnit)
virtual void set_size_request(int nWidth, int nHeight)=0
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
sal_Int32 nElements
bool VCL_DLLPUBLIC ReadDIBBitmapEx(BitmapEx &rTarget, SvStream &rIStm, bool bFileHeader=true, bool bMSOFormat=false)
RegionData_Impl * mpParent
float y
float x
FieldUnit
sal_Int16 nValue
sal_Int32 nIndex
sal_Int64 n
#define SAL_INFO(area, stream)
#define SAL_N_ELEMENTS(arr)
std::locale Create(std::string_view aPrefixName, const LanguageTag &rLocale)
OUString get(TranslateId sContextAndId, const std::locale &loc)
int i
int sprintf(char(&s)[N], char const *format, T &&... arguments)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
long Long
#define Y
QPRO_FUNC_TYPE nType
#define RECT_SIZE_PIX
Definition: sanedlg.cxx:43
IMPL_LINK(SaneDlg, ClickBtnHdl, weld::Button &, rButton, void)
Definition: sanedlg.cxx:575
#define PREVIEW_HEIGHT
Definition: sanedlg.cxx:41
IMPL_LINK_NOARG(SaneDlg, OptionsBoxSelectHdl, weld::TreeView &, void)
Definition: sanedlg.cxx:686
#define PREVIEW_WIDTH
Definition: sanedlg.cxx:40
#define STREAM_SEEK_TO_BEGIN
RET_OK
RET_CANCEL