/* * File: XScannerWidget.cpp * Author: Saleem Edah-Tally - nmset@yandex.com * License: CeCILL-C * Copyright Saleem Edah-Tally - © 2024 * * Created on ? */ #include "XScannerWidget.h" #include "XClientData.hpp" #include "Common.h" #include #include #include using namespace std; XScannerWidget::~XScannerWidget() {} XScannerWidget::XScannerWidget ( wxWindow* parent, TimeredStatusBar * sb, InsaneWorker * insaneWorker, wxWindowID id, const wxPoint& pos, const wxSize& size, long int style ) : ScannerWidget ( parent, id, pos, size, style ) { UpdateExtensionsMap(); m_sb = sb; m_insaneWorker = insaneWorker; if (m_insaneWorker) m_insaneWorkerEvh = m_insaneWorker->GetEventHandler(); cmbOutputType->Append (Extensions[PDF]); // Use the file extension and the enum index without client data. #if wxUSE_LIBPNG cmbOutputType->Append (Extensions[PNG]); #endif #if wxUSE_LIBJPEG cmbOutputType->Append (Extensions[JPEG]); #endif #if wxUSE_LIBTIFF cmbOutputType->Append (Extensions[TIFF]); #endif #if wxUSE_PNM cmbOutputType->Append (Extensions[PNM]); #endif // Paper sizes handled by podofo. cmbPaperSize->Append(wxArrayString({"A0", "A1", "A2", "A3", "A4", "A5", "A6", "Letter", "Legal", "Tabloid"})); btnRefreshDevices->Bind ( wxEVT_COMMAND_BUTTON_CLICKED, &XScannerWidget::OnButtonRefreshDevices, this ); cmbDevices->Bind ( wxEVT_COMMAND_COMBOBOX_SELECTED, &XScannerWidget::OnDeviceSelected, this ); cmbOutputType->Bind ( wxEVT_COMMAND_COMBOBOX_SELECTED, &XScannerWidget::OnImageTypeSelected, this ); cmbSource->Bind ( wxEVT_COMMAND_COMBOBOX_SELECTED, &XScannerWidget::OnSourceSelected, this ); cmbMode->Bind ( wxEVT_COMMAND_COMBOBOX_SELECTED, &XScannerWidget::OnModeSelected, this ); cmbResolution->Bind ( wxEVT_COMMAND_COMBOBOX_SELECTED, &XScannerWidget::OnResolutionSelected, this ); cmbPaperSize->Bind ( wxEVT_COMMAND_COMBOBOX_SELECTED, &XScannerWidget::OnPaperSizeSelected, this ); GetParent()->Bind ( wxEVT_SHOW, &XScannerWidget::OnActivated, this ); } bool XScannerWidget::FindDevices ( bool async ) { if ( m_sb && !async ) m_sb->SetTransientText (_("Searching for devices...") ); if ( !m_insaneWorker->Init() ) { const wxString msg = _("Could not initialise insane api."); cerr << msg << endl; if (m_insaneWorkerEvh) m_insaneWorkerEvh->OnInsaneError(msg.ToStdString()); return false; } std::vector devices = m_insaneWorker->GetDeviceDescriptors(); CallAfter ( &XScannerWidget::ClearScannerItems ); uint numberOfDevices = devices.size(); for ( uint i = 0; i < numberOfDevices; i++ ) { InsaneWorker::DeviceDescriptor device = devices.at(i); CallAfter ( &XScannerWidget::AppendScannerItem, device.GetLabel(), device.id ); } if ( m_sb ) { const wxString msg = wxVariant ( ( long ) numberOfDevices ).GetString() + _(" device(s) found."); // Should be but don't : it's as if the above code has not been run. // m_sb->CallAfter(&TimeredStatusBar::SetTransientText, msg, 3000); m_sb->SetTransientText(msg); } return true; } void XScannerWidget::AppendScannerItem ( const wxString& display, const wxString& clientData ) { cmbDevices->Append ( display, new XClientData ( clientData ) ); } void XScannerWidget::ClearScannerItems() { cmbDevices->Clear(); cmbSource->Clear(); cmbMode->Clear(); cmbResolution->Clear(); } void XScannerWidget::OnButtonRefreshDevices ( wxCommandEvent& evt ) { btnRefreshDevices->Enable ( false ); m_insaneWorker->Init(); FindDevices(); evt.Skip(); btnRefreshDevices->Enable ( true ); } void XScannerWidget::SetConfig ( wxFileConfig* config ) { m_config = config; if ( !m_config ) return; wxString lastImageType; m_config->Read (_T("/Scanner/Last/OutputType"), &lastImageType ); if ( cmbOutputType->FindString ( lastImageType, true ) != wxNOT_FOUND ) cmbOutputType->SetStringSelection ( lastImageType ); else cmbOutputType->Select(0); wxString lastPaperSize; m_config->Read (_T("/Scanner/Last/PaperSize"), &lastPaperSize ); if ( cmbPaperSize->FindString ( lastPaperSize, true ) != wxNOT_FOUND ) cmbPaperSize->SetStringSelection ( lastPaperSize ); else cmbPaperSize->Select(4); } void XScannerWidget::OnDeviceSelected ( wxCommandEvent& evt ) { if ( !m_config || ( cmbDevices->GetSelection() == wxNOT_FOUND ) ) return; int currentSelection = cmbDevices->GetCurrentSelection(); if ( currentSelection == wxNOT_FOUND ) return; XClientData * lastDevice = static_cast ( cmbDevices->GetClientObject ( currentSelection ) ); if ( !lastDevice ) return; m_config->Write ( "/Scanner/Last/Device", lastDevice->GetData().GetString() ); m_config->Flush(); UpdateScannerOptions ( lastDevice->GetData().GetString() ); } void XScannerWidget::OnImageTypeSelected ( wxCommandEvent& evt ) { if ( !m_config ) return; m_config->Write ( "/Scanner/Last/OutputType", cmbOutputType->GetStringSelection() ); m_config->Flush(); } void XScannerWidget::OnSourceSelected ( wxCommandEvent& evt ) { if ( !m_config ) return; const wxString deviceId = GetCurrentDeviceId(); if ( wxIsEmpty ( deviceId ) ) return; const wxString key =_T("/Scanner/") + deviceId +_T("/") + _T ( OPT_NAME_SOURCE ); m_config->Write ( key, cmbSource->GetStringSelection() ); m_config->Flush(); } void XScannerWidget::OnModeSelected ( wxCommandEvent& evt ) { if ( !m_config ) return; const wxString deviceId = GetCurrentDeviceId(); if ( wxIsEmpty ( deviceId ) ) return; const wxString key =_T("/Scanner/") + deviceId +_T("/") + _T ( OPT_NAME_MODE ); m_config->Write ( key, cmbMode->GetStringSelection() ); m_config->Flush(); } void XScannerWidget::OnResolutionSelected ( wxCommandEvent& evt ) { if ( !m_config ) return; const wxString deviceId = GetCurrentDeviceId(); if ( wxIsEmpty ( deviceId ) ) return; const wxString key =_T("/Scanner/") + deviceId +_T("/") + _T ( OPT_NAME_RESOLUTION ); m_config->Write ( key, cmbResolution->GetStringSelection() ); m_config->Flush(); } void XScannerWidget::OnPaperSizeSelected(wxCommandEvent& evt) { if ( !m_config ) return; m_config->Write ( "/Scanner/Last/PaperSize", cmbPaperSize->GetStringSelection() ); m_config->Flush(); } void XScannerWidget::UpdateScannerOptions ( const wxString& deviceId ) { if ( wxIsEmpty ( deviceId ) ) return; auto addListConstrainedOptions = [&] ( wxComboBox * cmb, const wxString& lastKey ) { if (!cmb) return; cmb->Clear(); vector possible; const string defaultValue = m_insaneWorker->GetOptionPossibleValues(deviceId.ToStdString(), lastKey.ToStdString(), possible); for (string itemValue : possible) { cmb->Append(itemValue); } cmb->Enable(cmb->GetCount()); if ( m_config ) { wxString savedValue; const wxString key =_T("Scanner/") + deviceId +_T("/") + lastKey; m_config->Read ( key, &savedValue ); if ( !savedValue.IsEmpty() ) { cmb->SetStringSelection ( savedValue ); return; } } cmb->SetStringSelection ( defaultValue ); }; /* * For a device with flatbed and ADF, there are multiple sources, each with a name. * The display name obtained here is different from the child devices of lis_item. * Each child item is a source. The root item must not be used for scanning * following the documentation. Fortunately, they are listed in the same order * with both enumerations. * Ex: Brother DCP-L8410CDW * 0 - FlatBed - flatbed * 1 - Automatic Document Feeder(left aligned) - feeder(left aligned) * 2 - Automatic Document Feeder(centrally aligned) - feeder(centrally aligned) * We must therefore select a source by its index. */ addListConstrainedOptions(cmbSource, OPT_NAME_SOURCE); addListConstrainedOptions(cmbMode, OPT_NAME_MODE); addListConstrainedOptions(cmbResolution, OPT_NAME_RESOLUTION); } wxString XScannerWidget::GetCurrentDeviceId() const { int currentSelection = cmbDevices->GetCurrentSelection(); if ( currentSelection == wxNOT_FOUND ) return wxEmptyString; XClientData * clientData = static_cast ( cmbDevices->GetClientObject ( currentSelection ) ); if ( !clientData ) return wxEmptyString; return clientData->GetData().GetString(); } void XScannerWidget::OnActivated ( wxShowEvent& evt ) { if ( evt.IsShown() && cmbDevices->GetCount() && cmbDevices->GetCurrentSelection() == wxNOT_FOUND ) { if ( m_config ) { wxString lastDevice; m_config->Read (_T("/Scanner/Last/Device"), &lastDevice ); if ( lastDevice.IsEmpty() || !cmbDevices->GetCount() ) { evt.Skip(); return; } for ( uint i = 0; i < cmbDevices->GetCount(); i++ ) { XClientData * clientData = static_cast ( cmbDevices->GetClientObject ( i ) ); if ( !clientData ) continue; if ( clientData->GetData().GetString() == lastDevice ) { cmbDevices->Select ( i ); UpdateScannerOptions ( lastDevice ); break; } } } } evt.Skip(); } // ---------------------------------------------------------------------------- wxThread::ExitCode BackgroundScannerDiscovery::Entry() { if (m_owner) { m_owner->FindDevices ( true ); wxShowEvent evt; evt.SetShow ( true ); m_owner->OnActivated ( evt ); if (m_evh) m_evh->OnDone(); } return ( wxThread::ExitCode ) 0; } // ---------------------------------------------------------------------------- void BackgroundScannerDiscoveryEvent::OnDone() {}