diff --git a/kcontrol/kamera.cpp b/kcontrol/kamera.cpp index 4b490ed..523cf8e 100644 --- a/kcontrol/kamera.cpp +++ b/kcontrol/kamera.cpp @@ -1,460 +1,460 @@ /* 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 "kamera.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kameraconfigdialog.h" #include "kameradevice.h" K_PLUGIN_FACTORY(KKameraConfigFactory, registerPlugin();) K_EXPORT_PLUGIN(KKameraConfigFactory("kcmkamera")) Q_LOGGING_CATEGORY(KAMERA_KCONTROL, "kamera.kcontrol") // --------------- Camera control center module widget --- KKameraConfig::KKameraConfig(QWidget *parent, const QVariantList &) : KCModule(parent) { #ifdef DEBUG_KAMERA_KCONTROL QLoggingCategory::setFilterRules(QStringLiteral("kamera.kcontrol.debug = true")); #endif m_devicePopup = new QMenu(this); m_actions = new KActionCollection(this); m_config = new KConfig(KProtocolInfo::config("camera"), KConfig::SimpleConfig); m_deviceModel = new QStandardItemModel(this); m_context = gp_context_new(); if (m_context) { // Register the callback functions gp_context_set_cancel_func(m_context, cbGPCancel, this); gp_context_set_idle_func(m_context, cbGPIdle, this); displayGPSuccessDialogue(); } else { displayGPFailureDialogue(); } } KKameraConfig::~KKameraConfig() { delete m_config; } void KKameraConfig::defaults() { } void KKameraConfig::displayGPFailureDialogue(void) { QVBoxLayout *topLayout = new QVBoxLayout(this); topLayout->setSpacing(0); topLayout->setMargin(0); QLabel *label = new QLabel(i18n("Unable to initialize the gPhoto2 libraries."), this); topLayout->addWidget(label); } void KKameraConfig::displayGPSuccessDialogue(void) { // set the kcontrol module buttons setButtons(Help | Apply ); // create a layout with two vertical boxes QVBoxLayout *topLayout = new QVBoxLayout(this); topLayout->setSpacing(0); topLayout->setMargin(0); m_toolbar = new KToolBar(this, "ToolBar"); topLayout->addWidget(m_toolbar); m_toolbar->setMovable(false); // create list of devices - this is the large white box m_deviceSel = new QListView(this); topLayout->addWidget(m_deviceSel); m_deviceSel->setModel(m_deviceModel); - connect(m_deviceSel, SIGNAL(customContextMenuRequested(const QPoint &)), - SLOT(slot_deviceMenu(const QPoint &))); - connect(m_deviceSel, SIGNAL(doubleClicked(const QModelIndex &)), + connect(m_deviceSel, SIGNAL(customContextMenuRequested(QPoint)), + SLOT(slot_deviceMenu(QPoint))); + connect(m_deviceSel, SIGNAL(doubleClicked(QModelIndex)), SLOT(slot_configureCamera())); - connect(m_deviceSel, SIGNAL(activated(const QModelIndex &)), - SLOT(slot_deviceSelected(const QModelIndex &))); + connect(m_deviceSel, SIGNAL(activated(QModelIndex)), + SLOT(slot_deviceSelected(QModelIndex))); connect(m_deviceSel, SIGNAL(clicked(QModelIndex)), SLOT(slot_deviceSelected(QModelIndex))); m_deviceSel->setViewMode(QListView::IconMode); m_deviceSel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_deviceSel->setContextMenuPolicy(Qt::CustomContextMenu); // create actions, add to the toolbar QAction *act; act = m_actions->addAction("camera_add"); act->setIcon(QIcon::fromTheme("camera-photo")); act->setText(i18n("Add")); connect(act, SIGNAL(triggered(bool)), this, SLOT(slot_addCamera())); act->setWhatsThis(i18n("Click this button to add a new camera.")); m_toolbar->addAction(act); m_toolbar->addSeparator(); act = m_actions->addAction("camera_test"); act->setIcon(QIcon::fromTheme("dialog-ok")); act->setText(i18n("Test")); connect(act, SIGNAL(triggered(bool)), this, SLOT(slot_testCamera())); act->setWhatsThis(i18n("Click this button to test the connection to the selected camera.")); m_toolbar->addAction(act); act = m_actions->addAction("camera_remove"); act->setIcon(QIcon::fromTheme("user-trash")); act->setText(i18n("Remove")); connect(act, SIGNAL(triggered(bool)), this, SLOT(slot_removeCamera())); act->setWhatsThis(i18n("Click this button to remove the selected camera from the list.")); m_toolbar->addAction(act); act = m_actions->addAction("camera_configure"); act->setIcon(QIcon::fromTheme("configure")); act->setText(i18n("Configure...")); connect(act, SIGNAL(triggered(bool)), this, SLOT(slot_configureCamera())); act->setWhatsThis(i18n("Click this button to change the configuration of the selected camera.

The availability of this feature and the contents of the Configuration dialog depend on the camera model.")); m_toolbar->addAction(act); act = m_actions->addAction("camera_summary"); act->setIcon(QIcon::fromTheme("hwinfo")); act->setText(i18n("Information")); connect(act, SIGNAL(triggered(bool)), this, SLOT(slot_cameraSummary())); act->setWhatsThis(i18n("Click this button to view a summary of the current status of the selected camera.

The availability of this feature and the contents of the Information dialog depend on the camera model.")); m_toolbar->addAction(act); m_toolbar->addSeparator(); act = m_actions->addAction("camera_cancel"); act->setIcon(QIcon::fromTheme("process-stop")); act->setText(i18n("Cancel")); connect(act, SIGNAL(triggered(bool)), this, SLOT(slot_cancelOperation())); act->setWhatsThis(i18n("Click this button to cancel the current camera operation.")); act->setEnabled(false); m_toolbar->addAction(act); } void KKameraConfig::populateDeviceListView(void) { m_deviceModel->clear(); CameraDevicesMap::ConstIterator it; for (it = m_devices.constBegin(); it != m_devices.constEnd(); ++it) { if (it.value()) { QStandardItem *deviceItem = new QStandardItem; deviceItem->setEditable(false); deviceItem->setText(it.key()); deviceItem->setIcon(QIcon::fromTheme("camera-photo")); m_deviceModel->appendRow(deviceItem); } } slot_deviceSelected(m_deviceSel->currentIndex()); } void KKameraConfig::save(void) { CameraDevicesMap::Iterator it; for (it = m_devices.begin(); it != m_devices.end(); it++) { it.value()->save(m_config); } m_config->sync(); } void KKameraConfig::load(void) { QStringList groupList = m_config->groupList(); QStringList::Iterator it; int i, count; CameraList *list; CameraAbilitiesList *al; GPPortInfoList *il; const char *model, *value; KCamera *kcamera; for (it = groupList.begin(); it != groupList.end(); it++) { if (*it != "") { KConfigGroup cg(m_config, *it); if (cg.readEntry("Path").contains("usb:")) { continue; } // Load configuration for Serial port cameras qCDebug(KAMERA_KCONTROL) << "Loading configuration for serial port camera: " << *it; kcamera = new KCamera(*it, cg.readEntry("Path")); - connect(kcamera, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &))); - connect(kcamera, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &))); + connect(kcamera, SIGNAL(error(QString)), SLOT(slot_error(QString))); + connect(kcamera, SIGNAL(error(QString,QString)), SLOT(slot_error(QString,QString))); kcamera->load(m_config); m_devices[*it] = kcamera; } } m_cancelPending = false; gp_list_new (&list); gp_abilities_list_new (&al); gp_abilities_list_load (al, m_context); gp_port_info_list_new (&il); gp_port_info_list_load (il); gp_abilities_list_detect (al, il, list, m_context); gp_abilities_list_free (al); gp_port_info_list_free (il); count = gp_list_count (list); QMap ports, names; for (i = 0 ; i::iterator portit; for (portit = ports.begin() ; portit != ports.end(); portit++) { qCDebug(KAMERA_KCONTROL) << "Adding USB camera: " << portit.value() << " at " << portit.key(); kcamera = new KCamera(portit.value(), portit.key()); - connect(kcamera, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &))); - connect(kcamera, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &))); + connect(kcamera, SIGNAL(error(QString)), SLOT(slot_error(QString))); + connect(kcamera, SIGNAL(error(QString,QString)), SLOT(slot_error(QString,QString))); m_devices[portit.value()] = kcamera; } populateDeviceListView(); gp_list_free (list); } void KKameraConfig::beforeCameraOperation(void) { m_cancelPending = false; m_actions->action("camera_test")->setEnabled(false); m_actions->action("camera_remove")->setEnabled(false); m_actions->action("camera_configure")->setEnabled(false); m_actions->action("camera_summary")->setEnabled(false); m_actions->action("camera_cancel")->setEnabled(true); } void KKameraConfig::afterCameraOperation(void) { m_actions->action("camera_cancel")->setEnabled(false); // if we're regaining control after a Cancel... if (m_cancelPending) { qApp->restoreOverrideCursor(); m_cancelPending = false; } // if any item was selected before the operation was run // it makes sense for the relevant toolbar buttons to be enabled slot_deviceSelected(m_deviceSel->currentIndex()); } QString KKameraConfig::suggestName(const QString &name) { QString new_name = name; new_name.remove('/'); // we cannot have a slash in a URI's host if (!m_devices.contains(new_name)) return new_name; // try new names with a number appended until we find a free one int i = 1; while (i++ < 0xffff) { new_name = name + " (" + QString::number(i) + ')'; if (!m_devices.contains(new_name)) return new_name; } return QString(); } void KKameraConfig::slot_addCamera() { KCamera *m_device = new KCamera(QString::null, QString()); //krazy:exclusion=nullstrassign for old broken gcc - connect(m_device, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &))); - connect(m_device, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &))); + connect(m_device, SIGNAL(error(QString)), SLOT(slot_error(QString))); + connect(m_device, SIGNAL(error(QString,QString)), SLOT(slot_error(QString,QString))); KameraDeviceSelectDialog dialog(this, m_device); if (dialog.exec() == QDialog::Accepted) { dialog.save(); m_device->setName(suggestName(m_device->model())); m_devices.insert(m_device->name(), m_device); populateDeviceListView(); emit changed(true); } else { delete m_device; } } void KKameraConfig::slot_removeCamera() { const QString name = m_deviceSel->currentIndex().data(Qt::DisplayRole).toString(); if (m_devices.contains(name)) { KCamera *m_device = m_devices.value(name); m_devices.remove(name); delete m_device; m_config->deleteGroup(name); populateDeviceListView(); emit changed(true); } } void KKameraConfig::slot_testCamera() { beforeCameraOperation(); const QString name = m_deviceSel->currentIndex().data(Qt::DisplayRole).toString(); if (m_devices.contains(name)) { KCamera *m_device = m_devices.value(name); if (m_device->test()) { KMessageBox::information(this, i18n("Camera test was successful.")); } } afterCameraOperation(); } void KKameraConfig::slot_configureCamera() { const QString name = m_deviceSel->currentIndex().data(Qt::DisplayRole).toString(); if (m_devices.contains(name)) { KCamera *m_device = m_devices[name]; m_device->configure(); } } void KKameraConfig::slot_cameraSummary() { const QString name = m_deviceSel->currentIndex().data(Qt::DisplayRole).toString(); if (m_devices.contains(name)) { KCamera *m_device = m_devices[name]; QString summary = m_device->summary(); if (!summary.isNull()) { KMessageBox::information(this, summary); } } } void KKameraConfig::slot_cancelOperation() { m_cancelPending = true; // Prevent the user from keeping clicking Cancel m_actions->action("camera_cancel")->setEnabled(false); // and indicate that the click on Cancel did have some effect qApp->setOverrideCursor(Qt::WaitCursor); } void KKameraConfig::slot_deviceMenu(const QPoint &point) { QModelIndex index = m_deviceSel->indexAt(point); if (index.isValid()) { m_devicePopup->clear(); m_devicePopup->addAction(m_actions->action("camera_test")); m_devicePopup->addAction(m_actions->action("camera_remove")); m_devicePopup->addAction(m_actions->action("camera_configure")); m_devicePopup->addAction(m_actions->action("camera_summary")); m_devicePopup->exec(m_deviceSel->viewport()->mapToGlobal(point)); } } void KKameraConfig::slot_deviceSelected(const QModelIndex &index) { bool isValid = index.isValid(); m_actions->action("camera_test")->setEnabled(isValid); m_actions->action("camera_remove")->setEnabled(isValid); m_actions->action("camera_configure")->setEnabled(isValid); m_actions->action("camera_summary")->setEnabled(isValid); } void KKameraConfig::cbGPIdle(GPContext * /*context*/, void * /*data*/) { /*KKameraConfig *self( reinterpret_cast(data) );*/ qApp->processEvents(); } GPContextFeedback KKameraConfig::cbGPCancel(GPContext * /*context*/, void *data) { KKameraConfig *self( reinterpret_cast(data) ); // Since in practice no camera driver supports idle callbacks yet, // we'll use the cancel callback as opportunity to process events qApp->processEvents(); // If a cancel request is pending, ask gphoto to cancel if (self->m_cancelPending) { return GP_CONTEXT_FEEDBACK_CANCEL; } else { return GP_CONTEXT_FEEDBACK_OK; } } QString KKameraConfig::quickHelp() const { return i18n("

Digital Camera

\n" "This module allows you to configure support for your digital camera.\n" "You need to select the camera's model and the port it is connected\n" "to on your computer (e.g. USB, Serial, Firewire). If your camera does not\n" "appear on the list of Supported Cameras, go to the\n" "GPhoto web site for a possible update.

\n" "To view and download images from the digital camera, go to the address\n" "camera:/ in Konqueror and other KDE applications."); } void KKameraConfig::slot_error(const QString &message) { KMessageBox::error(this, message); } void KKameraConfig::slot_error(const QString &message, const QString &details) { KMessageBox::detailedError(this, message, details); } #include "kamera.moc" diff --git a/kcontrol/kameraconfigdialog.cpp b/kcontrol/kameraconfigdialog.cpp index ea7bc83..cb3db5b 100644 --- a/kcontrol/kameraconfigdialog.cpp +++ b/kcontrol/kameraconfigdialog.cpp @@ -1,377 +1,377 @@ /* 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 "kameraconfigdialog.h" + #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include "kameraconfigdialog.h" - #include Q_DECLARE_LOGGING_CATEGORY(KAMERA_KCONTROL) KameraConfigDialog::KameraConfigDialog(Camera */*camera*/, CameraWidget *widget, QWidget *parent) : QDialog(parent), m_widgetRoot(widget) { QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(mainWidget); mainLayout->setMargin(0); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); okButton->setDefault(true); setModal( true ); QFrame *main = new QFrame(this); mainLayout->addWidget(main); // Sets a layout for the frame, which is the parent of the GP_WIDGET_WINDOW QVBoxLayout *topLayout = new QVBoxLayout(main); topLayout->setMargin(0); m_tabWidget = 0; appendWidget(main, widget); connect(okButton,SIGNAL(clicked()),this,SLOT(slotOk())); mainLayout->addWidget(buttonBox); } void KameraConfigDialog::appendWidget(QWidget *parent, CameraWidget *widget) { QWidget *newParent = parent; CameraWidgetType widget_type; const char *widget_name; const char *widget_info; const char *widget_label; float widget_value_float; int widget_value_int; const char *widget_value_string = NULL; gp_widget_get_type(widget, &widget_type); gp_widget_get_label(widget, &widget_label); gp_widget_get_info(widget, &widget_info); gp_widget_get_name(widget, &widget_name); QString whats_this = QString::fromLocal8Bit(widget_info); // gphoto2 doesn't seem to have any standard for i18n // Add this widget to parent switch(widget_type) { case GP_WIDGET_WINDOW: { setWindowTitle(QString::fromLocal8Bit(widget_label)); break; } case GP_WIDGET_SECTION: { if (!m_tabWidget) { m_tabWidget = new QTabWidget(parent); parent->layout()->addWidget(m_tabWidget); } QWidget *tab = new QWidget; // widgets are to be aligned vertically in the tab QVBoxLayout *tabLayout = new QVBoxLayout(tab); tabLayout->setMargin(0); m_tabWidget->addTab(tab, QString::fromLocal8Bit(widget_label)); // Add scroll area QScrollArea *scrollArea = new QScrollArea(tab); scrollArea->setWidgetResizable(true); scrollArea->setFrameShape(QFrame::NoFrame); tabLayout->addWidget(scrollArea); // Add a container widget to hold the page QWidget *tabContainer = new QWidget(tab); // Add a layout for later parent->layout()->... calls new QVBoxLayout(tabContainer); // Set the container as the widget to be managed by the ScrollArea scrollArea->setWidget(tabContainer); scrollArea->show(); newParent = tabContainer; break; } case GP_WIDGET_TEXT: case GP_WIDGET_RANGE: case GP_WIDGET_TOGGLE: { // Share the QGridLayout code QWidget *grid = new QWidget(parent); QGridLayout *gridLayout = new QGridLayout(grid); grid->setLayout(gridLayout); parent->layout()->addWidget(grid); QLabel *label; if (widget_type == GP_WIDGET_TEXT) { gp_widget_get_value(widget, &widget_value_string); label = new QLabel(QString::fromLocal8Bit(widget_label)+':', grid); QLineEdit *lineEdit = new QLineEdit(widget_value_string, grid); gridLayout->addWidget(lineEdit, 0, 1, Qt::AlignRight); m_wmap.insert(widget, lineEdit); } else if (widget_type == GP_WIDGET_RANGE) { float widget_low; float widget_high; float widget_increment; gp_widget_get_range(widget, &widget_low, &widget_high, &widget_increment); gp_widget_get_value(widget, &widget_value_float); label = new QLabel(QString::fromLocal8Bit(widget_label)+':', grid); QSlider *slider = new QSlider(Qt::Horizontal, grid); gridLayout->addWidget(slider, 0, 1, Qt::AlignRight); m_wmap.insert(widget, slider); } else if (widget_type == GP_WIDGET_TOGGLE) { gp_widget_get_value(widget, &widget_value_int); label = new QLabel(QString::fromLocal8Bit(widget_label), grid); QCheckBox *checkBox = new QCheckBox(grid); checkBox->setChecked(widget_value_int); gridLayout->addWidget(checkBox, 0, 1, Qt::AlignRight); m_wmap.insert(widget, checkBox); break; } gridLayout->addWidget(label, 0, 0, Qt::AlignLeft); break; } case GP_WIDGET_RADIO: { gp_widget_get_value(widget, &widget_value_string); int count = gp_widget_count_choices(widget); // KDE4 code used Q3V/HBoxGroup to specify alignment based on count // For fewer than 5 options, align them horizontally QBoxLayout *layout; if (count < 5) { layout = new QHBoxLayout; } else { layout = new QVBoxLayout; } QGroupBox *buttonGroup = new QGroupBox( QString::fromLocal8Bit(widget_label), parent); parent->layout()->addWidget(buttonGroup); for(int i = 0; i < count; ++i) { const char *widget_choice; gp_widget_get_choice(widget, i, &widget_choice); QRadioButton *newestButton = new QRadioButton(widget_choice); if(widget_value_string && !strcmp(widget_value_string, widget_choice)) { newestButton->setChecked(true); } layout->addWidget(newestButton); } m_wmap.insert(widget, buttonGroup); buttonGroup->setLayout(layout); if (!whats_this.isEmpty()) { buttonGroup->setWhatsThis( whats_this); } break; } case GP_WIDGET_MENU: { gp_widget_get_value(widget, &widget_value_string); QComboBox *comboBox = new QComboBox(parent); parent->layout()->addWidget(comboBox); comboBox->clear(); for(int i = 0; i < gp_widget_count_choices(widget); ++i) { const char *widget_choice; gp_widget_get_choice(widget, i, &widget_choice); comboBox->addItem(widget_choice); if(widget_value_string && !strcmp(widget_value_string, widget_choice)) comboBox->setCurrentIndex(i); } m_wmap.insert(widget, comboBox); if (!whats_this.isEmpty()) { comboBox->setWhatsThis( whats_this); } break; } case GP_WIDGET_BUTTON: { // TODO // I can't see a way of implementing this. Since there is // no way of telling which button sent you a signal, we // can't map to the appropriate widget->callback QLabel *label = new QLabel(i18n("Button (not supported by KControl)"), parent); parent->layout()->addWidget(label); break; } case GP_WIDGET_DATE: { // TODO QLabel * label = new QLabel(i18n("Date (not supported by KControl)"), parent); parent->layout()->addWidget(label); break; } default: return; } // Append all this widgets children for(int i = 0; i < gp_widget_count_children(widget); ++i) { CameraWidget *widget_child; gp_widget_get_child(widget, i, &widget_child); appendWidget(newParent, widget_child); } if (widget_type == GP_WIDGET_SECTION) { // Get latest tab QWidget *tab = m_tabWidget->widget(m_tabWidget->count()-1); QScrollArea *scrollArea = dynamic_cast(tab->children().at(1)); if (scrollArea) { QVBoxLayout *vbox_layout = dynamic_cast(scrollArea->widget()->layout()); if (vbox_layout) { vbox_layout->addStretch(); } } } } void KameraConfigDialog::updateWidgetValue(CameraWidget *widget) { CameraWidgetType widget_type; gp_widget_get_type(widget, &widget_type); switch(widget_type) { case GP_WIDGET_WINDOW: // nothing to do break; case GP_WIDGET_SECTION: // nothing to do break; case GP_WIDGET_TEXT: { QLineEdit *lineEdit = static_cast(m_wmap[widget]); gp_widget_set_value(widget, (void *)lineEdit->text().toLocal8Bit().data()); break; } case GP_WIDGET_RANGE: { QSlider *slider = static_cast(m_wmap[widget]); float value_float = slider->value(); gp_widget_set_value(widget, (void *)&value_float); break; } case GP_WIDGET_TOGGLE: { QCheckBox *checkBox = static_cast(m_wmap[widget]); int value_int = checkBox->isChecked() ? 1 : 0; gp_widget_set_value(widget, (void *)&value_int); break; } case GP_WIDGET_RADIO: { QGroupBox *buttonGroup = static_cast(m_wmap[widget]); for (auto button : buttonGroup->children()) { QRadioButton *radButton = static_cast(button); if (radButton->isChecked()) { gp_widget_set_value(widget, (void *)radButton->text().toLocal8Bit().data()); break; } } break; } case GP_WIDGET_MENU: { QComboBox *comboBox = static_cast(m_wmap[widget]); gp_widget_set_value(widget, (void *)comboBox->currentText().toLocal8Bit().data()); break; } case GP_WIDGET_BUTTON: // nothing to do break; case GP_WIDGET_DATE: { // not implemented break; } } // Copy child widget values for(int i = 0; i < gp_widget_count_children(widget); ++i) { CameraWidget *widget_child; gp_widget_get_child(widget, i, &widget_child); updateWidgetValue(widget_child); } } void KameraConfigDialog::slotOk() { // Copy Qt widget values into CameraWidget hierarchy updateWidgetValue(m_widgetRoot); // 'ok' dialog accept(); } diff --git a/kcontrol/kameradevice.cpp b/kcontrol/kameradevice.cpp index 7f59ba9..eb3d63d 100644 --- a/kcontrol/kameradevice.cpp +++ b/kcontrol/kameradevice.cpp @@ -1,564 +1,564 @@ /* 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 "kameradevice.h" + #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include "config-kamera.h" +#include extern "C" { #include } -#include "kamera.h" #include "kameraconfigdialog.h" -#include "kameradevice.h" // 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= 2; static GPContext *glob_context = 0; #ifdef DEBUG static void gp_errordumper(GPLogLevel level, const char *domain, const char *str, void *data) { qCDebug(KAMERA_KCONTROL) << "GP_LOG: " << str; } // Use with // gp_log_add_func(GP_LOG_LEVEL, gp_errordumper, NULL); // where LEVEL = { DATA, DEBUG, ERROR, VERBOSE, ALL } #endif KCamera::KCamera(const QString &name, const QString &path) { m_name = name; m_model = name; m_path = path; m_camera = NULL; m_abilitylist = 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.isNull()) { return false; } if(gp_abilities_list_new(&m_abilitylist) != GP_OK) { emit error(i18n("Could not allocate memory for the 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.toLocal8Bit().data()); if(index < 0) { emit error(i18n("Description of abilities for camera %1 is not available." " Configuration options may be incorrect.", 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.isNull() || m_path.isNull()) { 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.toLocal8Bit().data()), &info); gp_camera_set_abilities(m_camera, m_abilities); gp_camera_set_port_info(m_camera, info); gp_port_info_list_free(il); // this might take some time (esp. for non-existent 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."), QString::fromLocal8Bit(gp_result_as_string(result))); return false; } return m_camera; } } Camera* KCamera::camera() { initCamera(); return m_camera; } QString 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 QString::fromLocal8Bit(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."), QString::fromLocal8Bit(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."), QString::fromLocal8Bit(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) { KConfigGroup group = config->group(m_name); if (m_model.isNull()) { m_model = group.readEntry("Model"); } if (m_path.isNull()) { m_path = group.readEntry("Path"); } invalidateCamera(); } void KCamera::save(KConfig *config) { KConfigGroup group = config->group(m_name); group.writeEntry("Model", m_model); group.writeEntry("Path", m_path); } QString KCamera::portName() { QString port = m_path.left(m_path.indexOf(":")).toLower(); if (port == "serial") return i18n("Serial"); if (port == "usb") return i18n("USB"); return i18n("Unknown port"); } void KCamera::setName(const QString &name) { m_name = name; } void KCamera::setModel(const QString &model) { m_model = model; invalidateCamera(); initInformation(); } void KCamera::setPath(const QString &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; } QStringList KCamera::supportedPorts() { initInformation(); QStringList 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(QWidget *parent, KCamera *device) : QDialog(parent) { setWindowTitle( i18n("Select Camera Device") ); setModal( true ); m_device = device; - connect(m_device, SIGNAL(error(const QString &)), - SLOT(slot_error(const QString &))); - connect(m_device, SIGNAL(error(const QString &, const QString &)), - SLOT(slot_error(const QString &, const QString &))); + connect(m_device, SIGNAL(error(QString)), + SLOT(slot_error(QString))); + connect(m_device, SIGNAL(error(QString,QString)), + SLOT(slot_error(QString,QString))); QWidget *page = new QWidget( this ); // a layout with horizontal boxes - this gives the two columns QHBoxLayout *topLayout = new QHBoxLayout(page); topLayout->setMargin(0); // the models list m_modelSel = new QListView(page); m_model = new QStandardItemModel(this); m_model->setColumnCount(1); m_model->setHeaderData(0, Qt::Horizontal, i18nc("@title:column", "Supported Cameras")); m_modelSel->setModel(m_model); topLayout->addWidget( m_modelSel ); - connect(m_modelSel, SIGNAL(activated(const QModelIndex &)), - SLOT(slot_setModel(const QModelIndex &))); + connect(m_modelSel, SIGNAL(activated(QModelIndex)), + SLOT(slot_setModel(QModelIndex))); connect(m_modelSel, SIGNAL(clicked(QModelIndex)), SLOT(slot_setModel(QModelIndex))); // make sure listview only as wide as it needs to be m_modelSel->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred)); QVBoxLayout *rightLayout = new QVBoxLayout(); rightLayout->setMargin(0); topLayout->addLayout( rightLayout ); m_portSelectGroup = new QGroupBox(i18n("Port"), page); QVBoxLayout *vertLayout = new QVBoxLayout; m_portSelectGroup->setLayout( vertLayout ); m_portSelectGroup->setMinimumSize(100, 120); rightLayout->addWidget(m_portSelectGroup); // Create port type selection radiobuttons. m_serialRB = new QRadioButton(i18n("Serial")); vertLayout->addWidget(m_serialRB ); m_serialRB->setWhatsThis( i18n("If this option is checked, the camera has " "to be connected to one of the computer's serial ports (known as COM " "ports in Microsoft Windows.)")); m_USBRB = new QRadioButton(i18n("USB")); vertLayout->addWidget(m_USBRB ); m_USBRB->setWhatsThis( i18n("If this option is checked, the camera has to " "be connected to one of the computer's USB ports, or to a USB hub.")); m_portSettingsGroup = new QGroupBox(i18n("Port Settings"), page); QVBoxLayout *lay = new QVBoxLayout; m_portSettingsGroup->setLayout( lay ); rightLayout->addWidget(m_portSettingsGroup); // Create port settings widget stack m_settingsStack = new QStackedWidget; QWidget *grid2 = new QWidget(m_settingsStack); QGridLayout *gridLayout2 = new QGridLayout(grid2); grid2->setLayout(gridLayout2); QLabel *label2 = new QLabel(i18n("Port"), grid2); gridLayout2->addWidget(label2, 0, 0, Qt::AlignLeft); lay->addWidget(grid2); lay->addWidget( m_settingsStack ); - connect(m_serialRB, SIGNAL( toggled(bool) ), - this, SLOT( changeCurrentIndex() ) ); - connect(m_USBRB, SIGNAL( toggled(bool) ), - this, SLOT( changeCurrentIndex() ) ); + connect(m_serialRB, SIGNAL(toggled(bool)), + this, SLOT(changeCurrentIndex()) ); + connect(m_USBRB, SIGNAL(toggled(bool)), + this, SLOT(changeCurrentIndex()) ); // none tab m_settingsStack->insertWidget(INDEX_NONE, new QLabel(i18n("No port type selected."), m_settingsStack)); // serial tab QWidget *grid = new QWidget(m_settingsStack); QGridLayout *gridLayout = new QGridLayout(grid); grid->setLayout(gridLayout); QLabel *label = new QLabel(i18n("Port:"), grid); m_serialPortCombo = new QComboBox(grid); m_serialPortCombo->setEditable(true); m_serialPortCombo->setWhatsThis( i18n("Specify here the serial port to " "which you connect the camera.")); gridLayout->addWidget(label, 1, 0, Qt::AlignLeft); gridLayout->addWidget(m_serialPortCombo, 1, 1, Qt::AlignRight); m_settingsStack->insertWidget(INDEX_SERIAL, grid); m_settingsStack->insertWidget(INDEX_USB, new QLabel(i18n("No further configuration is required for USB cameras."), m_settingsStack)); // Add the ok/cancel buttons to the bottom of the right side m_OkCancelButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = m_OkCancelButtonBox->button(QDialogButtonBox::Ok); QPushButton *cancelButton = m_OkCancelButtonBox->button(QDialogButtonBox::Cancel); okButton->setDefault(true); // Set false enabled to allow the use of an equivalent // to enableButtonOk(true) in slot_setModel. okButton->setEnabled(false); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(okButton, SIGNAL(clicked(bool)), SLOT(accept())); connect(cancelButton, SIGNAL(clicked(bool)), SLOT(close())); rightLayout->addWidget(m_OkCancelButtonBox); // 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) { #ifdef HAVE_GPHOTO2_5 char *xpath; gp_port_info_get_path (info, &xpath); if (strncmp(xpath, "serial:", 7) == 0) { m_serialPortCombo->addItem(QString::fromLocal8Bit(xpath).mid(7)); } #else if (strncmp(info.path, "serial:", 7) == 0) { m_serialPortCombo->addItem(QString::fromLocal8Bit(info.path).mid(7)); } #endif } } gp_port_info_list_free(list); // add a spacer rightLayout->addStretch(); // This makes it bigger page->resize(page->sizeHint()); page->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); populateCameraListView(); load(); m_portSelectGroup->setEnabled( false ); m_portSettingsGroup->setEnabled( false ); } void KameraDeviceSelectDialog::changeCurrentIndex() { QRadioButton *send = dynamic_cast( sender() ); if ( send ) { if ( send == m_serialRB ) { m_settingsStack->setCurrentIndex( INDEX_SERIAL ); } else if ( send == m_USBRB ) { m_settingsStack->setCurrentIndex( INDEX_USB ); } } } 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) { QStandardItem *cameraItem = new QStandardItem; cameraItem->setEditable(false); cameraItem->setText(a.model); m_model->appendRow(cameraItem); } } return true; } } void KameraDeviceSelectDialog::save() { m_device->setModel(m_modelSel->currentIndex().data(Qt::DisplayRole).toString()); if (m_serialRB->isChecked()) { m_device->setPath("serial:" + m_serialPortCombo->currentText()); } else if ( m_USBRB->isChecked() ) { m_device->setPath("usb:"); } } void KameraDeviceSelectDialog::load() { QString path = m_device->path(); QString port = path.left(path.indexOf(':')).toLower(); if (port == "serial") setPortType(INDEX_SERIAL); if (port == "usb") setPortType(INDEX_USB); QList items = m_model->findItems(m_device->model()); foreach (QStandardItem *item, items) { const QModelIndex index = m_model->indexFromItem(item); m_modelSel->selectionModel()->select(index, QItemSelectionModel::Select); } } void KameraDeviceSelectDialog::slot_setModel(const QModelIndex &modelIndex) { m_portSelectGroup->setEnabled(true); m_portSettingsGroup->setEnabled(true); QString model = modelIndex.data(Qt::DisplayRole).toString(); CameraAbilities abilities; int index = gp_abilities_list_lookup_model(m_device->m_abilitylist, model.toLocal8Bit().data()); if(index < 0) { slot_error(i18n("Description of abilities for camera %1 is not available." " Configuration options may be incorrect.", 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); // 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.", model)); } QPushButton *okButton = m_OkCancelButtonBox->button(QDialogButtonBox::Ok); okButton->setEnabled(true); } void KameraDeviceSelectDialog::setPortType(int type) { // Enable the correct button if ( type == INDEX_USB ) { m_USBRB->setChecked( true ); } else if ( type == INDEX_SERIAL ) { m_serialRB->setChecked( true ); } // Bring the right tab to the front m_settingsStack->setCurrentIndex(type); } void KameraDeviceSelectDialog::slot_error(const QString &message) { KMessageBox::error(this, message); } void KameraDeviceSelectDialog::slot_error(const QString &message, const QString &details) { KMessageBox::detailedError(this, message, details); } #include "moc_kameradevice.cpp" diff --git a/kcontrol/kameradevice.h b/kcontrol/kameradevice.h index 27e292e..5f3932a 100644 --- a/kcontrol/kameradevice.h +++ b/kcontrol/kameradevice.h @@ -1,117 +1,120 @@ /* 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. */ #ifndef __kameradevice_h__ #define __kameradevice_h__ +#include "kamera.h" + #include #include +#include class KConfig; class QString; class QListView; class QStackedWidget; class QComboBox; class QLineEdit; class QRadioButton; class QGroupBox; class QStandardItemModel; class QModelIndex; class KCamera : public QObject { friend class KameraDeviceSelectDialog; Q_OBJECT public: KCamera(const QString &name, const QString &path); ~KCamera(); void invalidateCamera(); bool configure(); void load(KConfig *m_config); void save(KConfig *m_config); bool test(); QStringList supportedPorts(); Camera* camera(); QString name() const { return m_name ; } QString model() const { return m_model; } QString path() const { return m_path; } QString portName(); QString summary(); CameraAbilities abilities(); void setName(const QString &name); void setModel(const QString &model); void setPath(const QString &path); bool isTestable() const; bool isConfigurable(); Q_SIGNALS: void error(const QString &message); void error(const QString &message, const QString &details); protected: bool initInformation(); bool initCamera(); Camera *m_camera; QString m_name; // the camera's real name QString m_model; QString m_path; CameraAbilities m_abilities; CameraAbilitiesList *m_abilitylist; }; class KameraDeviceSelectDialog : public QDialog { Q_OBJECT public: KameraDeviceSelectDialog(QWidget *parent, KCamera *device); void save(); void load(); protected Q_SLOTS: void slot_setModel(const QModelIndex &index); void slot_error(const QString &message); void slot_error(const QString &message, const QString &details); void changeCurrentIndex(); protected: KCamera *m_device; bool populateCameraListView(void); void setPortType(int type); // port settings widgets QListView *m_modelSel; QStandardItemModel *m_model; QLineEdit *m_nameEdit; QStackedWidget *m_settingsStack; QGroupBox *m_portSelectGroup; QGroupBox *m_portSettingsGroup; QComboBox *m_serialPortCombo; QDialogButtonBox *m_OkCancelButtonBox; // port selection radio buttons QRadioButton *m_serialRB; QRadioButton *m_USBRB; }; #endif diff --git a/kioslave/kamera.cpp b/kioslave/kamera.cpp index 42190c3..7e7fe3b 100644 --- a/kioslave/kamera.cpp +++ b/kioslave/kamera.cpp @@ -1,1196 +1,1196 @@ /* Copyright (C) 2001 The Kompany 2001-2003 Ilya Konstantinov 2001-2008 Marcus Meissner 2012 Marcus Meissner 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. */ // remove comment to enable debugging // #undef QT_NO_DEBUG +#include "kamera.h" + #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include "config-kamera.h" - -#include "kamera.h" +#include #define tocstr(x) ((x).toLocal8Bit()) #define MAXIDLETIME 30 /* seconds */ Q_LOGGING_CATEGORY(KAMERA_KIOSLAVE, "kamera.kio") using namespace KIO; extern "C" { Q_DECL_EXPORT int kdemain(int argc, char **argv); #ifdef HAVE_GPHOTO2_5 static void frontendCameraStatus(GPContext *context, const char *status, void *data); static unsigned int frontendProgressStart( GPContext *context, float totalsize, const char *status, void *data ); #else static void frontendCameraStatus(GPContext *context, const char *format, va_list args, void *data); static unsigned int frontendProgressStart( GPContext *context, float totalsize, const char *format, va_list args, void *data ); #endif static void frontendProgressUpdate( GPContext *context, unsigned int id, float current, void *data ); } int kdemain(int argc, char **argv) { QCoreApplication::setApplicationName("kio_kamera"); KLocalizedString::setApplicationDomain("kio_kamera"); #ifdef DEBUG_KAMERA_KIO QLoggingCategory::setFilterRules(QStringLiteral("kamera.kio.debug = true")); #endif if(argc != 4) { qCDebug(KAMERA_KIOSLAVE) << "Usage: kio_kamera protocol " "domain-socket1 domain-socket2" << endl; exit(-1); } KameraProtocol slave(argv[2], argv[3]); slave.dispatchLoop(); return 0; } static QString path_quote(QString path) { return path.replace("/","%2F").replace(" ","%20"); } static QString path_unquote(QString path) { return path.replace("%2F","/").replace("%20"," "); } KameraProtocol::KameraProtocol(const QByteArray &pool, const QByteArray &app) : SlaveBase("camera", pool, app), m_camera(NULL) { // attempt to initialize libgphoto2 and chosen camera (requires locking) // (will init m_camera, since the m_camera's configuration is empty) m_camera = 0; m_file = NULL; m_config = new KConfig(KProtocolInfo::config("camera"), KConfig::SimpleConfig); m_context = gp_context_new(); actiondone = true; cameraopen = false; m_lockfile = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/kamera"; idletime = 0; } // This handler is getting called every second. We use it to do the // delayed close of the camera. // Logic is: // - No more requests in the queue (signaled by actiondone) AND // - We are MAXIDLETIME seconds idle OR // - Another slave wants to have access to the camera. // // The existence of a lockfile is used to signify "please give up camera". // void KameraProtocol::special(const QByteArray&) { qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::special() at " << getpid() << ". idletime: " << idletime; if (!actiondone && cameraopen) { struct stat stbuf; if ((-1!=::stat(m_lockfile.toUtf8(),&stbuf)) || (idletime++ >= MAXIDLETIME)) { qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::special() closing camera."; closeCamera(); setTimeoutSpecialCommand(-1); } else { // continue to wait setTimeoutSpecialCommand(1); } } else { // We let it run until the slave gets no actions anymore. setTimeoutSpecialCommand(1); } actiondone = false; } KameraProtocol::~KameraProtocol() { qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::~KameraProtocol()"; delete m_config; if(m_camera) { closeCamera(); gp_camera_free(m_camera); m_camera = NULL; } } // initializes the camera for usage - // should be done before operations over the wire bool KameraProtocol::openCamera(QString &str) { idletime = 0; actiondone = true; if (!m_camera) { reparseConfiguration(); } else { if (!cameraopen) { int ret, tries = 15; qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::openCamera at " << getpid(); // Gets this far. while (tries--) { ret = gp_camera_init(m_camera, m_context); if ( (ret == GP_ERROR_IO_USB_CLAIM) || (ret == GP_ERROR_IO_LOCK)) { // just create / touch if not there int fd = ::open(m_lockfile.toUtf8(),O_CREAT|O_WRONLY,0600); if (fd != -1) ::close(fd); ::sleep(1); qCDebug(KAMERA_KIOSLAVE) << "openCamera at " << getpid() << "- busy, ret " << ret << ", trying again."; continue; } if (ret == GP_OK) break; str = gp_result_as_string(ret); return false; } ::remove(m_lockfile.toUtf8()); setTimeoutSpecialCommand(1); qCDebug(KAMERA_KIOSLAVE) << "openCamera succeeded at " << getpid(); cameraopen = true; } } return true; } // should be done after operations over the wire void KameraProtocol::closeCamera(void) { int gpr; if (!m_camera) { return; } if ((gpr=gp_camera_exit(m_camera,m_context))!=GP_OK) { qCDebug(KAMERA_KIOSLAVE) << "closeCamera failed with " << gp_result_as_string(gpr); } // HACK: gp_camera_exit() in gp 2.0 does not close the port if there // is no camera_exit function. gp_port_close(m_camera->port); cameraopen = false; current_camera = ""; current_port = ""; return; } static QString fix_foldername(QString ofolder) { QString folder = ofolder; if (folder.length() > 1) { while ((folder.length()>1) && (folder.right(1) == "/")) folder = folder.left(folder.length()-1); } if (folder.length() == 0) { folder = "/"; } return folder; } // The KIO slave "get" function (starts a download from the camera) // The actual returning of the data is done in the frontend callback functions. void KameraProtocol::get(const QUrl &url) { qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::get(" << url.path() << ")"; QString directory, file; CameraFileType fileType; int gpr; split_url2camerapath(url.path(), directory, file); if(!openCamera()) { error(KIO::ERR_DOES_NOT_EXIST, url.path()); return; } #define GPHOTO_TEXT_FILE(xx) \ if (!directory.compare("/") && !file.compare(#xx ".txt")) { \ CameraText xx; \ gpr = gp_camera_get_##xx(m_camera, &xx, m_context); \ if (gpr != GP_OK) { \ error(KIO::ERR_DOES_NOT_EXIST, url.path()); \ return; \ } \ QByteArray chunkDataBuffer = QByteArray::fromRawData(xx.text, strlen(xx.text)); \ data(chunkDataBuffer); \ processedSize(strlen(xx.text)); \ chunkDataBuffer.clear(); \ finished(); \ return; \ } GPHOTO_TEXT_FILE(about); GPHOTO_TEXT_FILE(manual); GPHOTO_TEXT_FILE(summary); #undef GPHOTO_TEXT_FILE // emit info message // WARNING Fix this //infoMessage( i18n("Retrieving data from camera %1", current_camera) ); // Note: There's no need to re-read directory for each get() anymore gp_file_new(&m_file); // emit the total size (we must do it before sending data to allow preview) CameraFileInfo info; gpr = gp_camera_file_get_info(m_camera, tocstr(fix_foldername(directory)), tocstr(file), &info, m_context); if (gpr != GP_OK) { gp_file_unref(m_file); if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND)) { error(KIO::ERR_DOES_NOT_EXIST, url.path()); } else { error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(gpr))); } return; } // at last, a proper API to determine whether a thumbnail was requested. if(cameraSupportsPreview() && metaData("thumbnail") == "1") { qCDebug(KAMERA_KIOSLAVE) << "get() retrieving the thumbnail"; fileType = GP_FILE_TYPE_PREVIEW; if (info.preview.fields & GP_FILE_INFO_SIZE) { totalSize(info.preview.size); } if (info.preview.fields & GP_FILE_INFO_TYPE) { mimeType(info.preview.type); } } else { qCDebug(KAMERA_KIOSLAVE) << "get() retrieving the full-scale photo"; fileType = GP_FILE_TYPE_NORMAL; if (info.file.fields & GP_FILE_INFO_SIZE) { totalSize(info.file.size); } if (info.preview.fields & GP_FILE_INFO_TYPE) { mimeType(info.file.type); } } // fetch the data m_fileSize = 0; gpr = gp_camera_file_get(m_camera, tocstr(fix_foldername(directory)), tocstr(file), fileType, m_file, m_context ); if ((gpr == GP_ERROR_NOT_SUPPORTED) && (fileType == GP_FILE_TYPE_PREVIEW)) { // If we get here, the file info command information // will either not be used, or still valid. fileType = GP_FILE_TYPE_NORMAL; gpr = gp_camera_file_get(m_camera, tocstr(fix_foldername(directory)), tocstr(file), fileType, m_file, m_context ); } switch(gpr) { case GP_OK: break; case GP_ERROR_FILE_NOT_FOUND: case GP_ERROR_DIRECTORY_NOT_FOUND: gp_file_unref(m_file); m_file = NULL; error(KIO::ERR_DOES_NOT_EXIST, url.fileName()); return ; default: gp_file_unref(m_file); m_file = NULL; error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(gpr))); return; } // emit the mimetype // NOTE: we must first get the file, so that CameraFile->name would be set const char *fileMimeType; gp_file_get_mime_type(m_file, &fileMimeType); mimeType(fileMimeType); // We need to pass left over data here. Some camera drivers do not // implement progress callbacks! const char *fileData; long unsigned int fileSize; // This merely returns us a pointer to gphoto's internal data // buffer -- there's no expensive memcpy gpr = gp_file_get_data_and_size(m_file, &fileData, &fileSize); if (gpr != GP_OK) { qCDebug(KAMERA_KIOSLAVE) << "get():: get_data_and_size failed."; gp_file_free(m_file); m_file = NULL; error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(gpr))); return; } // make sure we're not sending zero-sized chunks (=EOF) // also make sure we send only if the progress did not send the data // already. if ((fileSize > 0) && (fileSize - m_fileSize)>0) { unsigned long written = 0; QByteArray chunkDataBuffer; // We need to split it up here. Someone considered it funny // to discard any data() larger than 16MB. // // So nearly any Movie will just fail.... while (written < fileSize-m_fileSize) { unsigned long towrite = 1024*1024; // 1MB if (towrite > fileSize-m_fileSize-written) { towrite = fileSize-m_fileSize-written; } chunkDataBuffer = QByteArray::fromRawData( fileData + m_fileSize + written, towrite); processedSize(m_fileSize + written + towrite); data(chunkDataBuffer); chunkDataBuffer.clear(); written += towrite; } m_fileSize = fileSize; setFileSize(fileSize); } finished(); gp_file_unref(m_file); /* just unref, might be stored in fs */ m_file = NULL; } // The KIO slave "stat" function. void KameraProtocol::stat(const QUrl &url) { qCDebug(KAMERA_KIOSLAVE) << "stat(\"" << url.path() << "\")"; if (url.path().isEmpty()) { QUrl rooturl(url); qCDebug(KAMERA_KIOSLAVE) << "redirecting to /"; rooturl.setPath("/"); redirection(rooturl); finished(); return; } if(url.path() == "/") statRoot(); else statRegular(url); } // Implements stat("/") -- which always returns the same value. void KameraProtocol::statRoot(void) { KIO::UDSEntry entry; entry.insert( KIO::UDSEntry::UDS_NAME, QString::fromLocal8Bit("/")); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE,S_IFDIR); entry.insert(KIO::UDSEntry::UDS_ACCESS,(S_IRUSR | S_IRGRP | S_IROTH)); statEntry(entry); finished(); // If we just do this call, timeout right away if no other requests are // pending. This is for the kdemm autodetection using media://camera idletime = MAXIDLETIME; } void KameraProtocol::split_url2camerapath(QString url, QString &directory, QString &file ) { QStringList components, camarr; QString cam, camera, port; components = url.split('/', QString::SkipEmptyParts); if (components.size() == 0) { return; } cam = path_unquote(components.takeFirst()); if (!cam.isEmpty()) { camarr = cam.split('@'); camera = path_unquote(camarr.takeFirst()); port = path_unquote(camarr.takeLast()); setCamera (camera, port); } if (components.size() == 0) { directory = "/"; return; } file = path_unquote(components.takeLast()); directory = path_unquote("/"+components.join("/")); } // Implements a regular stat() of a file / directory, returning all we know about it void KameraProtocol::statRegular(const QUrl &xurl) { KIO::UDSEntry entry; QString directory, file; int gpr; qCDebug(KAMERA_KIOSLAVE) << "statRegular(\"" << xurl.path() << "\")"; split_url2camerapath(xurl.path(), directory, file); if (openCamera() == false) { error(KIO::ERR_DOES_NOT_EXIST, xurl.path()); return; } if (directory == "/") { KIO::UDSEntry entry; - QString xname = current_camera + "@" + current_port; + QString xname = current_camera + '@' + current_port; entry.insert( KIO::UDSEntry::UDS_NAME, path_quote(xname)); entry.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, current_camera); entry.insert( KIO::UDSEntry::UDS_FILE_TYPE,S_IFDIR); entry.insert( KIO::UDSEntry::UDS_ACCESS,(S_IRUSR | S_IRGRP | S_IROTH)); statEntry(entry); finished(); return; } // Is "url" a directory? CameraList *dirList; gp_list_new(&dirList); qCDebug(KAMERA_KIOSLAVE) << "statRegular() Requesting directories list for " << directory; gpr = gp_camera_folder_list_folders(m_camera, tocstr(fix_foldername(directory)), dirList, m_context); if (gpr != GP_OK) { if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND)) { error(KIO::ERR_DOES_NOT_EXIST, xurl.path()); } else { error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(gpr))); } gp_list_free(dirList); return; } #define GPHOTO_TEXT_FILE(xx) \ if (!directory.compare("/") && !file.compare(#xx".txt")) { \ CameraText xx; \ gpr = gp_camera_get_about(m_camera, &xx, m_context); \ if (gpr != GP_OK) { \ error(KIO::ERR_DOES_NOT_EXIST, xurl.fileName()); \ return; \ } \ translateTextToUDS(entry,#xx".txt",xx.text); \ statEntry(entry); \ finished(); \ return; \ } GPHOTO_TEXT_FILE(about); GPHOTO_TEXT_FILE(manual); GPHOTO_TEXT_FILE(summary); #undef GPHOTO_TEXT_FILE const char *name; for(int i = 0; i < gp_list_count(dirList); i++) { gp_list_get_name(dirList, i, &name); if (file.compare(name) == 0) { gp_list_free(dirList); KIO::UDSEntry entry; translateDirectoryToUDS(entry, file); statEntry(entry); finished(); return; } } gp_list_free(dirList); // Is "url" a file? CameraFileInfo info; gpr = gp_camera_file_get_info(m_camera, tocstr(fix_foldername(directory)), tocstr(file), &info, m_context ); if (gpr != GP_OK) { if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND)) { error(KIO::ERR_DOES_NOT_EXIST, xurl.path()); } else { error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(gpr))); } return; } translateFileToUDS(entry, info, file); statEntry(entry); finished(); } // The KIO slave "del" function. void KameraProtocol::del(const QUrl &url, bool isFile) { QString directory, file; qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::del(" << url.path() << ")"; split_url2camerapath (url.path(), directory, file); if(!openCamera()) { error(KIO::ERR_CANNOT_DELETE, file); return; } if (!cameraSupportsDel()) { error(KIO::ERR_CANNOT_DELETE, file); return; } if(isFile){ CameraList *list; gp_list_new(&list); int ret; ret = gp_camera_file_delete(m_camera, tocstr(fix_foldername(directory)), tocstr(file), m_context); if(ret != GP_OK) { error(KIO::ERR_CANNOT_DELETE, file); } else { finished(); } } } // The KIO slave "listDir" function. void KameraProtocol::listDir(const QUrl &yurl) { QString directory, file; qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::listDir(" << yurl.path() << ")"; split_url2camerapath(yurl.path(), directory, file); if (!file.isEmpty()) { if (directory == "/") { - directory = "/" + file; + directory = '/' + file; } else { - directory = directory + "/" + file; + directory = directory + '/' + file; } } if (yurl.path() == "/") { QUrl xurl; // List the available cameras QStringList groupList = m_config->groupList(); qCDebug(KAMERA_KIOSLAVE) << "Found cameras: " << groupList.join(", "); QStringList::Iterator it; KIO::UDSEntry entry; /* * What we do: * - Autodetect cameras and remember them with their ports. * - List all saved and possible offline cameras. * - List all autodetected and not yet printed cameras. */ QMap ports, names; QMap modelcnt; /* Autodetect USB cameras ... */ GPContext *glob_context = NULL; int i, count; CameraList *list; CameraAbilitiesList *al; GPPortInfoList *il; gp_list_new (&list); gp_abilities_list_new (&al); gp_abilities_list_load (al, glob_context); gp_port_info_list_new (&il); gp_port_info_list_load (il); gp_abilities_list_detect (al, il, list, glob_context); gp_abilities_list_free (al); gp_port_info_list_free (il); count = gp_list_count (list); for (i = 0 ; i") { continue; } KConfigGroup cg(m_config, *it); m_cfgPath = cg.readEntry("Path"); // we autodetected those ... if (m_cfgPath.contains(QString("usb:"))) { cg.deleteGroup(); continue; } QString xname; entry.clear(); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE,S_IFDIR); entry.insert(KIO::UDSEntry::UDS_ACCESS, (S_IRUSR | S_IRGRP | S_IROTH |S_IWUSR | S_IWGRP | S_IWOTH)); - xname = (*it)+"@"+m_cfgPath; + xname = (*it)+'@'+m_cfgPath; entry.insert(KIO::UDSEntry::UDS_NAME,path_quote(xname)); // do not confuse regular users with the @usb... entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME,*it); listEntry(entry); } QMap::iterator portsit; for (portsit = ports.begin(); portsit != ports.end(); portsit++) { entry.clear(); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE,S_IFDIR); // do not confuse regular users with the @usb... entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME,portsit.value()); entry.insert(KIO::UDSEntry::UDS_NAME, - path_quote(portsit.value()+"@"+portsit.key())); + path_quote(portsit.value()+'@'+portsit.key())); entry.insert(KIO::UDSEntry::UDS_ACCESS, (S_IRUSR | S_IRGRP | S_IROTH |S_IWUSR | S_IWGRP | S_IWOTH)); listEntry(entry); } finished(); return; } if (directory.isEmpty()) { QUrl rooturl(yurl); qCDebug(KAMERA_KIOSLAVE) << "redirecting to /"; if (!current_camera.isEmpty() && !current_port.isEmpty()) { - rooturl.setPath("/"+current_camera+"@"+current_port+"/"); + rooturl.setPath('/'+current_camera+'@'+current_port+'/'); } else { rooturl.setPath("/"); } redirection(rooturl); finished(); return; } if (!openCamera()) { error(KIO::ERR_COULD_NOT_READ, yurl.path()); return; } CameraList *dirList; CameraList *fileList; CameraList *specialList; gp_list_new(&dirList); gp_list_new(&fileList); gp_list_new(&specialList); int gpr; if (!directory.compare("/")) { CameraText text; if (GP_OK == gp_camera_get_manual(m_camera, &text, m_context)) { gp_list_append(specialList,"manual.txt",NULL); } if (GP_OK == gp_camera_get_about(m_camera, &text, m_context)) { gp_list_append(specialList,"about.txt",NULL); } if (GP_OK == gp_camera_get_summary(m_camera, &text, m_context)) { gp_list_append(specialList,"summary.txt",NULL); } } gpr = readCameraFolder(directory, dirList, fileList); if(gpr != GP_OK) { qCDebug(KAMERA_KIOSLAVE) << "read Camera Folder failed:" << gp_result_as_string(gpr); gp_list_free(dirList); gp_list_free(fileList); gp_list_free(specialList); error(KIO::ERR_SLAVE_DEFINED, i18n("Could not read. Reason: %1", QString::fromLocal8Bit(gp_result_as_string(gpr)))); return; } totalSize(gp_list_count(specialList) + gp_list_count(dirList) + gp_list_count(fileList)); KIO::UDSEntry entry; const char *name; for(int i = 0; i < gp_list_count(dirList); ++i) { gp_list_get_name(dirList, i, &name); translateDirectoryToUDS(entry, QString::fromLocal8Bit(name)); listEntry(entry); } CameraFileInfo info; for(int i = 0; i < gp_list_count(fileList); ++i) { gp_list_get_name(fileList, i, &name); // we want to know more info about files (size, type...) gp_camera_file_get_info(m_camera, tocstr(directory), name, &info, m_context); translateFileToUDS(entry, info, QString::fromLocal8Bit(name)); listEntry(entry); } if (!directory.compare("/")) { CameraText text; if (GP_OK == gp_camera_get_manual(m_camera, &text, m_context)) { translateTextToUDS(entry, "manual.txt", text.text); listEntry(entry); } if (GP_OK == gp_camera_get_about(m_camera, &text, m_context)) { translateTextToUDS(entry, "about.txt", text.text); listEntry(entry); } if (GP_OK == gp_camera_get_summary(m_camera, &text, m_context)) { translateTextToUDS(entry, "summary.txt", text.text); listEntry(entry); } } gp_list_free(fileList); gp_list_free(dirList); gp_list_free(specialList); finished(); } void KameraProtocol::setCamera(const QString& camera, const QString& port) { qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::setCamera(" << camera << ", " << port << ")"; int gpr, idx; if (!camera.isEmpty() && !port.isEmpty()) { if ( m_camera && (current_camera == camera) && (current_port == port) ) { qCDebug(KAMERA_KIOSLAVE) << "Configuration is same, nothing to do."; return; } if (m_camera) { qCDebug(KAMERA_KIOSLAVE) << "Configuration change detected"; closeCamera(); gp_camera_unref(m_camera); m_camera = NULL; // WARNING Fix this //infoMessage( i18n("Reinitializing camera") ); } else { qCDebug(KAMERA_KIOSLAVE) << "Initializing camera"; // WARNING Fix this //infoMessage( i18n("Initializing camera") ); } // fetch abilities CameraAbilitiesList *abilities_list; gp_abilities_list_new(&abilities_list); gp_abilities_list_load(abilities_list, m_context); idx = gp_abilities_list_lookup_model(abilities_list, tocstr(camera)); if (idx < 0) { gp_abilities_list_free(abilities_list); qCDebug(KAMERA_KIOSLAVE) << "Unable to get abilities for model: " << camera; error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(idx))); return; } gp_abilities_list_get_abilities(abilities_list, idx, &m_abilities); gp_abilities_list_free(abilities_list); // fetch port GPPortInfoList *port_info_list; GPPortInfo port_info; gp_port_info_list_new(&port_info_list); gp_port_info_list_load(port_info_list); idx = gp_port_info_list_lookup_path(port_info_list, tocstr(port)); /* Handle erronously passed usb:XXX,YYY */ if ((idx < 0) && port.startsWith("usb:")) { idx = gp_port_info_list_lookup_path(port_info_list, "usb:"); } if (idx < 0) { gp_port_info_list_free(port_info_list); qCDebug(KAMERA_KIOSLAVE) << "Unable to get port info for path: " << port; error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(idx))); return; } gp_port_info_list_get_info(port_info_list, idx, &port_info); current_camera = camera; current_port = port; // create a new camera object gpr = gp_camera_new(&m_camera); if(gpr != GP_OK) { gp_port_info_list_free(port_info_list); error(KIO::ERR_UNKNOWN, QString::fromLocal8Bit(gp_result_as_string(gpr))); return; } // register gphoto2 callback functions gp_context_set_status_func(m_context, frontendCameraStatus, this); gp_context_set_progress_funcs(m_context, frontendProgressStart, frontendProgressUpdate, NULL, this ); // gp_camera_set_message_func(m_camera, ..., this) // set model and port gp_camera_set_abilities(m_camera, m_abilities); gp_camera_set_port_info(m_camera, port_info); gp_camera_set_port_speed(m_camera, 0); // TODO: the value needs to be configurable qCDebug(KAMERA_KIOSLAVE) << "Opening camera model " << camera << " at " << port; gp_port_info_list_free(port_info_list); QString errstr; if (!openCamera(errstr)) { if (m_camera) { gp_camera_unref(m_camera); } m_camera = NULL; qCDebug(KAMERA_KIOSLAVE) << "Unable to init camera: " << errstr; error(KIO::ERR_SERVICE_NOT_AVAILABLE, errstr); return; } } } void KameraProtocol::reparseConfiguration(void) { // we have no global config, do we? } // translate a simple text to a UDS entry void KameraProtocol::translateTextToUDS(KIO::UDSEntry &udsEntry, const QString &fn, const char *text) { udsEntry.clear(); udsEntry.insert(KIO::UDSEntry::UDS_FILE_TYPE,S_IFREG); udsEntry.insert(KIO::UDSEntry::UDS_NAME,path_quote(fn)); udsEntry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME,fn); udsEntry.insert(KIO::UDSEntry::UDS_SIZE,strlen(text)); udsEntry.insert(KIO::UDSEntry::UDS_ACCESS,(S_IRUSR | S_IRGRP | S_IROTH)); } // translate a CameraFileInfo to a UDSFieldType // which we can return as a directory listing entry void KameraProtocol::translateFileToUDS(KIO::UDSEntry &udsEntry, const CameraFileInfo &info, QString name) { udsEntry.clear(); udsEntry.insert(KIO::UDSEntry::UDS_FILE_TYPE,S_IFREG); udsEntry.insert(KIO::UDSEntry::UDS_NAME,path_quote(name)); udsEntry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME,name); if (info.file.fields & GP_FILE_INFO_SIZE) { udsEntry.insert(KIO::UDSEntry::UDS_SIZE,info.file.size); } if (info.file.fields & GP_FILE_INFO_MTIME) { udsEntry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME,info.file.mtime); } else { udsEntry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME,time(NULL)); } if (info.file.fields & GP_FILE_INFO_TYPE) { udsEntry.insert(KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1(info.file.type)); } if (info.file.fields & GP_FILE_INFO_PERMISSIONS) { udsEntry.insert(KIO::UDSEntry::UDS_ACCESS, ((info.file.permissions & GP_FILE_PERM_READ) ? (S_IRUSR | S_IRGRP | S_IROTH) : 0) ); } else { udsEntry.insert(KIO::UDSEntry::UDS_ACCESS,S_IRUSR | S_IRGRP | S_IROTH); } // TODO: We do not handle info.preview in any way } // translate a directory name to a UDSFieldType // which we can return as a directory listing entry void KameraProtocol::translateDirectoryToUDS(KIO::UDSEntry &udsEntry, const QString &dirname) { udsEntry.clear(); udsEntry.insert(KIO::UDSEntry::UDS_FILE_TYPE,S_IFDIR); udsEntry.insert(KIO::UDSEntry::UDS_NAME,path_quote(dirname)); udsEntry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, dirname); udsEntry.insert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH |S_IWUSR | S_IWGRP | S_IWOTH | S_IXUSR | S_IXOTH | S_IXGRP); udsEntry.insert(KIO::UDSEntry::UDS_MIME_TYPE, QString("inode/directory")); } bool KameraProtocol::cameraSupportsDel(void) { return (m_abilities.file_operations & GP_FILE_OPERATION_DELETE); } bool KameraProtocol::cameraSupportsPut(void) { return (m_abilities.folder_operations & GP_FOLDER_OPERATION_PUT_FILE); } bool KameraProtocol::cameraSupportsPreview(void) { return (m_abilities.file_operations & GP_FILE_OPERATION_PREVIEW); } int KameraProtocol::readCameraFolder(const QString &folder, CameraList *dirList, CameraList *fileList) { qCDebug(KAMERA_KIOSLAVE) << "KameraProtocol::readCameraFolder(" << folder << ")"; int gpr; if((gpr = gp_camera_folder_list_folders(m_camera, tocstr(folder), dirList, m_context)) != GP_OK) { return gpr; } if((gpr = gp_camera_folder_list_files(m_camera, tocstr(folder), fileList, m_context)) != GP_OK) { return gpr; } return GP_OK; } void frontendProgressUpdate( GPContext * /*context*/, unsigned int /*id*/, float /*current*/, void *data ) { KameraProtocol *object = (KameraProtocol*)data; // This code will get the last chunk of data retrieved from the // camera and pass it to KIO, to allow progressive display // of the downloaded photo. const char *fileData = NULL; long unsigned int fileSize = 0; // This merely returns us a pointer to gphoto's internal data // buffer -- there's no expensive memcpy if (!object->getFile()) { return; } gp_file_get_data_and_size(object->getFile(), &fileData, &fileSize); // make sure we're not sending zero-sized chunks (=EOF) if (fileSize > 0) { // XXX using assign() here causes segfault, prolly because // gp_file_free is called before chunkData goes out of scope QByteArray chunkDataBuffer = QByteArray::fromRawData( fileData + object->getFileSize(), fileSize - object->getFileSize()); // Note: this will fail with sizes > 16MB ... object->data(chunkDataBuffer); object->processedSize(fileSize); chunkDataBuffer.clear(); object->setFileSize(fileSize); } } unsigned int frontendProgressStart( GPContext * /*context*/, float totalsize, #ifdef HAVE_GPHOTO2_5 const char *status, #else const char *format, va_list args, #endif void *data ) { KameraProtocol *object = (KameraProtocol*)data; #ifndef HAVE_GPHOTO2_5 char *status; /* We must copy the va_list to walk it twice, or all hell * breaks loose on non-i386 platforms. */ #if defined(HAVE_VA_COPY) || defined(HAVE___VA_COPY) va_list xvalist; # ifdef HAVE_VA_COPY va_copy(xvalist, args); # elif HAVE___VA_COPY __va_copy(xvalist, args); # endif int size=vsnprintf(NULL, 0, format, xvalist); if(size<=0) return GP_OK; // vsnprintf is broken, better don't do anything. status=new char[size+1]; # ifdef HAVE_VA_COPY va_copy(xvalist, args); # elif HAVE___VA_COPY __va_copy(xvalist, args); # endif vsnprintf(status, size+1, format, xvalist); #else /* We cannot copy the va_list, so make sure we * walk it just _once_. */ status=new char[300]; vsnprintf(status, 300, format, args); #endif object->infoMessage(QString::fromLocal8Bit(status)); delete [] status; #else /* libgphoto2 2.5 has resolved this already, no need for print */ object->infoMessage(QString::fromLocal8Bit(status)); #endif object->totalSize((KIO::filesize_t)totalsize); // hack: call slot directly return GP_OK; } // this callback function is activated on every status message from gphoto2 static void frontendCameraStatus( GPContext * /*context*/, #ifdef HAVE_GPHOTO2_5 const char *status, #else const char *format, va_list args, #endif void *data ) { KameraProtocol *object = (KameraProtocol*)data; #ifndef HAVE_GPHOTO2_5 char *status; /* We must copy the va_list to walk it twice, or all hell * breaks loose on non-i386 platforms. */ #if defined(HAVE_VA_COPY) || defined(HAVE___VA_COPY) va_list xvalist; # ifdef HAVE_VA_COPY va_copy(xvalist, args); # elif HAVE___VA_COPY __va_copy(xvalist, args); # endif int size=vsnprintf(NULL, 0, format, xvalist); if(size<=0) return; // vsnprintf is broken, better don't do anything. status=new char[size+1]; # ifdef HAVE_VA_COPY va_copy(xvalist, args); # elif HAVE___VA_COPY __va_copy(xvalist, args); # endif vsnprintf(status, size+1, format, xvalist); #else /* We cannot copy the va_list, so make sure we * walk it just _once_. */ status=new char[300]; vsnprintf(status, 300, format, args); #endif object->infoMessage(QString::fromLocal8Bit(status)); delete [] status; #else object->infoMessage(QString::fromLocal8Bit(status)); #endif }