/* Copyright (C) 2001 The Kompany 2002-2003 Ilya Konstantinov 2002-2003 Marcus Meissner 2003 Nadeem Hasan This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include } #include "kamera.h" #include "kameraconfigdialog.h" #include "kameradevice.moc" // Define some parts of the old API #define GP_PROMPT_OK 0 #define GP_PROMPT_CANCEL -1 static const int INDEX_NONE= 0; static const int INDEX_SERIAL = 1; static const int INDEX_USB= 3; static GPContext *glob_context = 0; KCamera::KCamera(const TQString &name, const TQString &path) { m_name = name; m_model = name; m_path = path; m_camera = NULL; } KCamera::~KCamera() { if(m_camera) gp_camera_free(m_camera); if(m_abilitylist) gp_abilities_list_free(m_abilitylist); } bool KCamera::initInformation() { if (!m_model) return false; if(gp_abilities_list_new(&m_abilitylist) != GP_OK) { emit error(i18n("Could not allocate memory for abilities list.")); return false; } if(gp_abilities_list_load(m_abilitylist, glob_context) != GP_OK) { emit error(i18n("Could not load ability list.")); return false; } int index = gp_abilities_list_lookup_model(m_abilitylist, m_model.local8Bit().data()); if(index < 0) { emit error(i18n("Description of abilities for camera %1 is not available." " Configuration options may be incorrect.").tqarg(m_model)); return false; } gp_abilities_list_get_abilities(m_abilitylist, index, &m_abilities); return true; } bool KCamera::initCamera() { if (m_camera) return m_camera; else { int result; initInformation(); if (!m_model || !m_path) return false; result = gp_camera_new(&m_camera); if (result != GP_OK) { // m_camera is not initialized, so we cannot get result as string emit error(i18n("Could not access driver. Check your gPhoto2 installation.")); return false; } // set the camera's model GPPortInfo info; GPPortInfoList *il; gp_port_info_list_new(&il); gp_port_info_list_load(il); gp_port_info_list_get_info(il, gp_port_info_list_lookup_path(il, m_path.local8Bit().data()), &info); gp_port_info_list_free(il); gp_camera_set_abilities(m_camera, m_abilities); gp_camera_set_port_info(m_camera, info); // this might take some time (esp. for non-existant camera) - better be done asynchronously result = gp_camera_init(m_camera, glob_context); if (result != GP_OK) { gp_camera_free(m_camera); m_camera = NULL; emit error( i18n("Unable to initialize camera. Check your port settings and camera connectivity and try again."), gp_result_as_string(result)); return false; } return m_camera; } } Camera* KCamera::camera() { initCamera(); return m_camera; } TQString KCamera::summary() { int result; CameraText summary; initCamera(); result = gp_camera_get_summary(m_camera, &summary, glob_context); if (result != GP_OK) return i18n("No camera summary information is available.\n"); return TQString(summary.text); } bool KCamera::configure() { CameraWidget *window; int result; initCamera(); result = gp_camera_get_config(m_camera, &window, glob_context); if (result != GP_OK) { emit error(i18n("Camera configuration failed."), gp_result_as_string(result)); return false; } KameraConfigDialog kcd(m_camera, window); result = kcd.exec() ? GP_PROMPT_OK : GP_PROMPT_CANCEL; if (result == GP_PROMPT_OK) { result = gp_camera_set_config(m_camera, window, glob_context); if (result != GP_OK) { emit error(i18n("Camera configuration failed."), gp_result_as_string(result)); return false; } } return true; } bool KCamera::test() { // TODO: Make testing non-blocking (maybe via KIO?) // Currently, a failed serial test times out at about 30 sec. return camera() != 0; } void KCamera::load(KConfig *config) { config->setGroup(m_name); if (m_model.isNull()) m_model = config->readEntry("Model"); if (m_path.isNull()) m_path = config->readEntry("Path"); invalidateCamera(); } void KCamera::save(KConfig *config) { config->setGroup(m_name); config->writeEntry("Model", m_model); config->writeEntry("Path", m_path); } TQString KCamera::portName() { TQString port = m_path.left(m_path.find(":")).lower(); if (port == "serial") return i18n("Serial"); if (port == "usb") return i18n("USB"); return i18n("Unknown port"); } void KCamera::setName(const TQString &name) { m_name = name; } void KCamera::setModel(const TQString &model) { m_model = model; invalidateCamera(); initInformation(); } void KCamera::setPath(const TQString &path) { m_path = path; invalidateCamera(); } void KCamera::invalidateCamera() { if (m_camera) { gp_camera_free(m_camera); m_camera = NULL; } } bool KCamera::isTestable() const { return true; } bool KCamera::isConfigurable() { initInformation(); return m_abilities.operations & GP_OPERATION_CONFIG; } TQStringList KCamera::supportedPorts() { initInformation(); TQStringList ports; if (m_abilities.port & GP_PORT_SERIAL) ports.append("serial"); if (m_abilities.port & GP_PORT_USB) ports.append("usb"); return ports; } CameraAbilities KCamera::abilities() { return m_abilities; } // ---------- KameraSelectCamera ------------ KameraDeviceSelectDialog::KameraDeviceSelectDialog(TQWidget *parent, KCamera *device) : KDialogBase(parent, "kkameradeviceselect", true, i18n("Select Camera Device"), Ok | Cancel, Ok, true) { m_device = device; connect(m_device, TQT_SIGNAL(error(const TQString &)), TQT_SLOT(slot_error(const TQString &))); connect(m_device, TQT_SIGNAL(error(const TQString &, const TQString &)), TQT_SLOT(slot_error(const TQString &, const TQString &))); TQWidget *page = new TQWidget( this ); setMainWidget(page); // a tqlayout with vertical boxes TQHBoxLayout *topLayout = new TQHBoxLayout(page, 0, KDialog::spacingHint()); // the models list m_modelSel = new KListView(page); topLayout->addWidget( m_modelSel ); m_modelSel->addColumn(i18n("Supported Cameras")); m_modelSel->setColumnWidthMode(0, TQListView::Maximum); connect(m_modelSel, TQT_SIGNAL(selectionChanged(TQListViewItem *)), TQT_SLOT(slot_setModel(TQListViewItem *))); // make sure listview only as wide as it needs to be m_modelSel->setSizePolicy(TQSizePolicy(TQSizePolicy::Maximum, TQSizePolicy::Preferred)); TQVBoxLayout *rightLayout = new TQVBoxLayout(0L, 0, KDialog::spacingHint()); topLayout->addLayout( rightLayout ); m_portSelectGroup = new TQVButtonGroup(i18n("Port"), page); rightLayout->addWidget(m_portSelectGroup); m_portSettingsGroup = new TQVGroupBox(i18n("Port Settings"), page); rightLayout->addWidget(m_portSettingsGroup); // Create port type selection radiobuttons. m_serialRB = new TQRadioButton(i18n("Serial"), m_portSelectGroup); m_portSelectGroup->insert(m_serialRB, INDEX_SERIAL); TQWhatsThis::add(m_serialRB, i18n("If this option is checked, the camera would have to be connected one of the serial ports (known as COM in Microsoft Windows) in your computer.")); m_USBRB = new TQRadioButton(i18n("USB"), m_portSelectGroup); m_portSelectGroup->insert(m_USBRB, INDEX_USB); TQWhatsThis::add(m_USBRB, i18n("If this option is checked, the camera would have to be connected to one of the USB slots in your computer or USB hub.")); // Create port settings widget stack m_settingsStack = new TQWidgetStack(m_portSettingsGroup); connect(m_portSelectGroup, TQT_SIGNAL(clicked(int)), m_settingsStack, TQT_SLOT(raiseWidget(int))); // none tab m_settingsStack->addWidget(new TQLabel(i18n("No port type selected."), m_settingsStack), INDEX_NONE); // serial tab TQGrid *grid = new TQGrid(2, m_settingsStack); grid->setSpacing(KDialog::spacingHint()); new TQLabel(i18n("Port:"), grid); m_serialPortCombo = new TQComboBox(TRUE, grid); TQWhatsThis::add(m_serialPortCombo, i18n("Here you should choose the serial port you connect the camera to.")); m_settingsStack->addWidget(grid, INDEX_SERIAL); grid = new TQGrid(2, m_settingsStack); grid->setSpacing(KDialog::spacingHint()); new TQLabel(i18n("Port"), grid); m_settingsStack->addWidget(new TQLabel(i18n("No further configuration is required for USB."), m_settingsStack), INDEX_USB); // query gphoto2 for existing serial ports GPPortInfoList *list; GPPortInfo info; int gphoto_ports=0; gp_port_info_list_new(&list); if(gp_port_info_list_load(list) >= 0) { gphoto_ports = gp_port_info_list_count(list); } for (int i = 0; i < gphoto_ports; i++) { if (gp_port_info_list_get_info(list, i, &info) >= 0) { if (strncmp(info.path, "serial:", 7) == 0) m_serialPortCombo->insertItem(TQString::fromLatin1(info.path).mid(7)); } } gp_port_info_list_free(list); // add a spacer rightLayout->addStretch(); populateCameraListView(); load(); enableButtonOK(false ); m_portSelectGroup->setEnabled( false ); m_portSettingsGroup->setEnabled( false ); } bool KameraDeviceSelectDialog::populateCameraListView() { gp_abilities_list_new (&m_device->m_abilitylist); gp_abilities_list_load(m_device->m_abilitylist, glob_context); int numCams = gp_abilities_list_count(m_device->m_abilitylist); CameraAbilities a; if(numCams < 0) { // XXX libgphoto2 failed to get te camera list return false; } else { for(int x = 0; x < numCams; ++x) { if(gp_abilities_list_get_abilities(m_device->m_abilitylist, x, &a) == GP_OK) { new TQListViewItem(m_modelSel, a.model); } } return true; } } void KameraDeviceSelectDialog::save() { m_device->setModel(m_modelSel->currentItem()->text(0)); if (m_portSelectGroup->selected()) { TQString type = m_portSelectGroup->selected()->text(); if(type == i18n("Serial")) m_device->setPath("serial:" + m_serialPortCombo->currentText()); else if(type == i18n("USB")) m_device->setPath("usb:"); } else { // This camera has no port type (e.g. "Directory Browse" camera). // Do nothing. } } void KameraDeviceSelectDialog::load() { TQString path = m_device->path(); TQString port = path.left(path.find(":")).lower(); if (port == "serial") setPortType(INDEX_SERIAL); if (port == "usb") setPortType(INDEX_USB); TQListViewItem *modelItem = m_modelSel->firstChild(); if( modelItem) { do { if (modelItem->text(0) == m_device->model()) { m_modelSel->setSelected(modelItem, true); m_modelSel->ensureItemVisible(modelItem); } } while ( ( modelItem = modelItem->nextSibling() ) ); } } void KameraDeviceSelectDialog::slot_setModel(TQListViewItem *item) { enableButtonOK(true); m_portSelectGroup->setEnabled(true); m_portSettingsGroup->setEnabled(true); TQString model = item->text(0); CameraAbilities abilities; int index = gp_abilities_list_lookup_model(m_device->m_abilitylist, model.local8Bit().data()); if(index < 0) { slot_error(i18n("Description of abilities for camera %1 is not available." " Configuration options may be incorrect.").tqarg(model)); } int result = gp_abilities_list_get_abilities(m_device->m_abilitylist, index, &abilities); if (result == GP_OK) { // enable radiobuttons for supported port types m_serialRB->setEnabled(abilities.port & GP_PORT_SERIAL); m_USBRB->setEnabled(abilities.port & GP_PORT_USB); // turn off any selected port TQButton *selected = m_portSelectGroup->selected(); if(selected != NULL) selected->toggle(); // if there's only one available port type, make sure it's selected if (abilities.port == GP_PORT_SERIAL) setPortType(INDEX_SERIAL); if (abilities.port == GP_PORT_USB) setPortType(INDEX_USB); } else { slot_error(i18n("Description of abilities for camera %1 is not available." " Configuration options may be incorrect.").tqarg(model)); } } void KameraDeviceSelectDialog::setPortType(int type) { // Enable the correct button m_portSelectGroup->setButton(type); // Bring the right tab to the front m_settingsStack->raiseWidget(type); } void KameraDeviceSelectDialog::slot_error(const TQString &message) { KMessageBox::error(this, message); } void KameraDeviceSelectDialog::slot_error(const TQString &message, const TQString &details) { KMessageBox::detailedError(this, message, details); }