summaryrefslogtreecommitdiffstats
path: root/kamera
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit47d455dd55be855e4cc691c32f687f723d9247ee (patch)
tree52e236aaa2576bdb3840ebede26619692fed6d7d /kamera
downloadtdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz
tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kamera')
-rw-r--r--kamera/AUTHORS4
-rw-r--r--kamera/Makefile.am1
-rw-r--r--kamera/README5
-rw-r--r--kamera/configure.in.in182
-rw-r--r--kamera/kcontrol/Makefile.am16
-rw-r--r--kamera/kcontrol/kamera.cpp423
-rw-r--r--kamera/kcontrol/kamera.desktop193
-rw-r--r--kamera/kcontrol/kamera.h115
-rw-r--r--kamera/kcontrol/kameraconfigdialog.cpp317
-rw-r--r--kamera/kcontrol/kameraconfigdialog.h53
-rw-r--r--kamera/kcontrol/kameradevice.cpp476
-rw-r--r--kamera/kcontrol/kameradevice.h117
-rw-r--r--kamera/kioslave/Makefile.am17
-rw-r--r--kamera/kioslave/camera.protocol16
-rw-r--r--kamera/kioslave/kamera.cpp1066
-rw-r--r--kamera/kioslave/kamera.h81
-rw-r--r--kamera/pics/Makefile.am1
-rw-r--r--kamera/pics/cr16-action-camera_test.pngbin0 -> 661 bytes
-rw-r--r--kamera/pics/cr16-app-camera.pngbin0 -> 747 bytes
-rw-r--r--kamera/pics/cr16-device-camera.pngbin0 -> 747 bytes
-rw-r--r--kamera/pics/cr22-device-camera.pngbin0 -> 953 bytes
-rw-r--r--kamera/pics/cr22-filesys-camera.pngbin0 -> 953 bytes
-rw-r--r--kamera/pics/cr32-device-camera.pngbin0 -> 1627 bytes
-rw-r--r--kamera/pics/cr32-filesys-camera.pngbin0 -> 1627 bytes
24 files changed, 3083 insertions, 0 deletions
diff --git a/kamera/AUTHORS b/kamera/AUTHORS
new file mode 100644
index 00000000..b278e9ce
--- /dev/null
+++ b/kamera/AUTHORS
@@ -0,0 +1,4 @@
+ Copyright (C) 2001 The Kompany
+ 2001-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2001-2007 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
diff --git a/kamera/Makefile.am b/kamera/Makefile.am
new file mode 100644
index 00000000..f012f4a1
--- /dev/null
+++ b/kamera/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = kcontrol kioslave pics
diff --git a/kamera/README b/kamera/README
new file mode 100644
index 00000000..592a84f4
--- /dev/null
+++ b/kamera/README
@@ -0,0 +1,5 @@
+Dependencies:
+
+You need libgphoto 2.0 final (or later).
+
+libgphoto2 2.3.1 or newer is recommended.
diff --git a/kamera/configure.in.in b/kamera/configure.in.in
new file mode 100644
index 00000000..3e2fd1c6
--- /dev/null
+++ b/kamera/configure.in.in
@@ -0,0 +1,182 @@
+dnl KDE_FIND_GPHOTO2 - Find gphoto2 libraries and include files
+dnl
+dnl Adapted from kdebase/nsplugins/configure.in.in
+
+AC_DEFUN([KDE_FIND_GPHOTO2],
+[
+
+
+
+# Clear working variables
+gphoto2_includes=
+gphoto2_libraries=
+
+
+
+# Process user input to configure
+AC_ARG_WITH(kamera,
+AC_HELP_STRING([--without-kamera],[do not build kamera (gphoto2 required)]),
+[if test "$withval" = "no" ; then
+ gphoto2_includes=none
+ gphoto2_libraries=none
+fi])dnl
+
+AC_ARG_WITH(gphoto2-includes,
+AC_HELP_STRING([--with-gphoto2-includes=DIR],[gphoto2 include files are in DIR]),
+gphoto2_includes="$withval")
+
+AC_ARG_WITH(gphoto2-libraries,
+AC_HELP_STRING([--with-gphoto2-libraries=DIR],[gphoto2 libraries are in DIR]),
+gphoto2_libraries="$withval")
+
+AC_MSG_CHECKING(for gPhoto2)
+# the pkg-config way first, if user did not use --with-
+AC_CHECK_PROG(gphoto2_config,gphoto2-config,gphoto2-config,no)
+AC_CHECK_PROG(gphoto2_port_config,gphoto2-port-config,gphoto2-port-config,no)
+if test "$gphoto2_includes" = "" -a "$gphoto2_libraries" = "" -a "$gphoto2_config" != "no" -a "$gphoto2_port_config" != "no"
+then
+ with_kamera="yes"
+ GPHOTO2_INCS="`$gphoto2_config --cflags` `$gphoto2_port_config --cflags`"
+ GPHOTO2_LIBS="`$gphoto2_config --libs` `$gphoto2_port_config --libs`"
+else
+#
+# Search for gphoto2 include files.
+#
+ if test "$gphoto2_includes" = ""; then
+ AC_CACHE_VAL(ac_cv_gphoto2_includes, [
+ ac_gphoto2_save_LIBS="$LIBS"
+ LIBS="-lgphoto2 $LIBS"
+ ac_cv_gphoto2_includes="none"
+ AC_TRY_COMPILE([#include <gphoto2.h>],[int a;],
+ [
+ # gphoto2.h is in the standard search path.
+ ac_cv_gphoto2_includes=
+ ],[
+ # gphoto2.h is not in the standard search path.
+ # Locate it and put its directory in `gphoto2_includes'
+ for dir in /usr/include /usr/local/include \
+ /usr/include/gphoto2 /usr/local/include/gphoto2; do
+ if test -f "$dir/gphoto2.h"; then
+ ac_cv_gphoto2_includes="$dir"
+ break
+ fi
+ done
+ ])
+ #
+ LIBS="$ac_gphoto2_save_LIBS"
+ ])
+ gphoto2_includes="$ac_cv_gphoto2_includes"
+ fi
+
+ #
+ # Search for libgphoto2
+ #
+ if test "$gphoto2_libraries" = ""; then
+ AC_CACHE_VAL(ac_cv_gphoto2_libraries,[
+ ac_gphoto2_save_LIBS="$LIBS"
+ LIBS="-lgphoto2_port -lgphoto2 $LIBS"
+ ac_cv_gphoto2_libraries="none"
+ AC_TRY_LINK([#include <gphoto2.h>],[gp_context_progress_start(0,0,0,0);], [
+ # libgphoto2 is in the standard search path.
+ ac_cv_gphoto2_libraries=
+ ],[
+ # libgphoto2 is not in the standard search path.
+ # Locate it and put its directory in `gphoto2_libraries'
+ for dir in /usr/lib /usr/local/lib; do
+ if test -d "$dir" && test "`ls $dir/libgphoto2.* 2> /dev/null`" != ""; then
+ ac_cv_gphoto2_libraries="$dir"
+ break
+ fi
+ done
+ ])
+ #
+ LIBS="$ac_gphoto2_save_LIBS"
+ ])
+ #
+ gphoto2_libraries="$ac_cv_gphoto2_libraries"
+ fi
+# Initialise compiler and linker flag variables for export
+ if test "$gphoto2_includes" = "none" -o "$gphoto2_libraries" = "none" ; then
+ with_kamera="no"
+ else
+ with_kamera="yes"
+
+ if test "$gphoto2_libraries" = "" -o "$gphoto2_libraries" = "none"; then
+ GPHOTO2_LIBS="-lgphoto2"
+ else
+ GPHOTO2_LIBS="-L$gphoto2_libraries -lgphoto2"
+ fi
+ if test "$gphoto2_includes" != "" -a "$gphoto2_includes" != "none"; then
+ GPHOTO2_INCS="-I$gphoto2_includes"
+ fi
+ fi
+fi
+
+if test "$with_kamera" = "yes" ; then
+ # Check if it works.
+ ac_gphoto2_save_LIBS="$LIBS"
+ ac_gphoto2_save_CFLAGS="$CFLAGS"
+ LIBS="$LIBS $GPHOTO2_LIBS"
+ CFLAGS="$CFLAGS $GPHOTO2_INCS"
+ AC_TRY_LINK([#include <gphoto2.h>],[gp_context_progress_start(0,0,0,0);], [
+ # It works.
+ AC_DEFINE(HAVE_GPHOTO2,1,[Define if you have gPhoto2 installed])
+ ],[
+ with_kamera="no"
+ ])
+ LIBS="$ac_gphoto2_save_LIBS"
+ CFLAGS="$ac_gphoto2_save_CFLAGS"
+fi
+dnl **** Check for va_copy ****
+AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy,
+ AC_TRY_LINK(
+ [#include <stdarg.h>],
+ [va_list ap1, ap2;
+ va_copy(ap1,ap2);
+ ],
+ [ac_cv_c_va_copy="yes"],
+ [ac_cv_c_va_copy="no"])
+ )
+if test "$ac_cv_c_va_copy" = "yes"
+then
+ AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy])
+fi
+AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy,
+ AC_TRY_LINK(
+ [#include <stdarg.h>],
+ [va_list ap1, ap2;
+ __va_copy(ap1,ap2);
+ ],
+ [ac_cv_c___va_copy="yes"],
+ [ac_cv_c___va_copy="no"])
+ )
+if test "$ac_cv_c___va_copy" = "yes"
+then
+ AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy])
+fi
+
+# Export compiler and linker flags for replacement in Makefile
+AC_SUBST(GPHOTO2_INCS)
+AC_SUBST(GPHOTO2_LIBS)
+
+
+# Display results of configuration
+gphoto2_libraries_result="$gphoto2_libraries"
+gphoto2_includes_result="$gphoto2_includes"
+
+test "$gphoto2_libraries" = "" && gphoto2_libraries_result="in default path"
+test "$gphoto2_includes" = "" && gphoto2_includes_result="in default path"
+
+test "$gphoto2_libraries" = "none" && gphoto2_libraries_result="(none)"
+test "$gphoto2_includes" = "none" && gphoto2_includes_result="(none)"
+
+AC_MSG_RESULT(
+ [gphoto2 libraries $gphoto2_libraries_result, gphoto2 headers $gphoto2_includes_result])
+
+]) dnl end of KDE_FIND_GPHOTO2 definition
+
+KDE_FIND_GPHOTO2
+if test "$with_kamera" = "no"; then
+dnl AC_MSG_WARN([You need to install gphoto 2.0 (or later), e.g. http://gphoto.net/dist/gphoto2-2.0.tar.gz if your distributor doesn't have a package])
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kamera"
+fi
diff --git a/kamera/kcontrol/Makefile.am b/kamera/kcontrol/Makefile.am
new file mode 100644
index 00000000..9fd30f46
--- /dev/null
+++ b/kamera/kcontrol/Makefile.am
@@ -0,0 +1,16 @@
+kde_module_LTLIBRARIES = kcm_kamera.la
+
+kcm_kamera_la_SOURCES = kamera.cpp kameradevice.cpp kameraconfigdialog.cpp
+
+kcm_kamera_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kcm_kamera_la_LIBADD = $(LIB_KIO) $(GPHOTO2_LIBS)
+INCLUDES= $(all_includes) $(GPHOTO2_INCS)
+
+kcm_kamera_la_METASOURCES = AUTO
+
+noinst_HEADERS = kamera.h kameradevice.h kameraconfigdialog.h
+
+messages:
+ $(XGETTEXT) $(kcm_kamera_la_SOURCES) -o $(podir)/kcmkamera.pot
+
+xdg_apps_DATA = kamera.desktop
diff --git a/kamera/kcontrol/kamera.cpp b/kamera/kcontrol/kamera.cpp
new file mode 100644
index 00000000..0fdc416a
--- /dev/null
+++ b/kamera/kcontrol/kamera.cpp
@@ -0,0 +1,423 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 <qlabel.h>
+#include <qlayout.h>
+
+#include <kgenericfactory.h>
+#include <ksimpleconfig.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kiconview.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <ktoolbar.h>
+#include <kpopupmenu.h>
+#include <kprotocolinfo.h>
+#include <kdebug.h>
+
+#include "kameraconfigdialog.h"
+#include "kameradevice.h"
+#include "kamera.h"
+#include "kamera.moc"
+
+typedef KGenericFactory<KKameraConfig, QWidget> KKameraConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kamera, KKameraConfigFactory( "kcmkamera" ) )
+
+// --------------- Camera control center module widget ---
+
+KKameraConfig *KKameraConfig::m_instance = NULL;
+
+KKameraConfig::KKameraConfig(QWidget *parent, const char *name, const QStringList &)
+ : KCModule(KKameraConfigFactory::instance(), parent, name)
+{
+ m_devicePopup = new KPopupMenu(this);
+ m_actions = new KActionCollection(this);
+ m_config = new KSimpleConfig(KProtocolInfo::config("camera"));
+
+ 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();
+
+ // load existing configuration
+ load();
+
+ } else {
+
+ displayGPFailureDialogue();
+ }
+
+ // store instance for frontend_prompt
+ m_instance = this;
+}
+
+KKameraConfig::~KKameraConfig()
+{
+ delete m_config;
+}
+
+void KKameraConfig::defaults()
+{
+ load( true );
+}
+
+void KKameraConfig::displayGPFailureDialogue(void)
+{
+ new QLabel(i18n("Unable to initialize the gPhoto2 libraries."), this);
+}
+
+void KKameraConfig::displayGPSuccessDialogue(void)
+{
+ // set the kcontrol module buttons
+ setButtons(Help | Apply | Cancel | Ok);
+
+ // create a layout with two vertical boxes
+ QVBoxLayout *topLayout = new QVBoxLayout(this, 0, 0);
+ topLayout->setAutoAdd(true);
+
+ m_toolbar = new KToolBar(this, "ToolBar");
+ m_toolbar->setMovingEnabled(false);
+
+ // create list of devices
+ m_deviceSel = new KIconView(this);
+
+ connect(m_deviceSel, SIGNAL(rightButtonClicked(QIconViewItem *, const QPoint &)),
+ SLOT(slot_deviceMenu(QIconViewItem *, const QPoint &)));
+ connect(m_deviceSel, SIGNAL(doubleClicked(QIconViewItem *)),
+ SLOT(slot_configureCamera()));
+ connect(m_deviceSel, SIGNAL(selectionChanged(QIconViewItem *)),
+ SLOT(slot_deviceSelected(QIconViewItem *)));
+
+ m_deviceSel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ // create actions
+ KAction *act;
+
+ act = new KAction(i18n("Add"), "camera", 0, this, SLOT(slot_addCamera()), m_actions, "camera_add");
+ act->setWhatsThis(i18n("Click this button to add a new camera."));
+ act->plug(m_toolbar);
+ m_toolbar->insertLineSeparator();
+ act = new KAction(i18n("Test"), "camera_test", 0, this, SLOT(slot_testCamera()), m_actions, "camera_test");
+ act->setWhatsThis(i18n("Click this button to remove the selected camera from the list."));
+ act->plug(m_toolbar);
+ act = new KAction(i18n("Remove"), "edittrash", 0, this, SLOT(slot_removeCamera()), m_actions, "camera_remove");
+ act->setWhatsThis(i18n("Click this button to remove the selected camera from the list."));
+ act->plug(m_toolbar);
+ act = new KAction(i18n("Configure..."), "configure", 0, this, SLOT(slot_configureCamera()), m_actions, "camera_configure");
+ act->setWhatsThis(i18n("Click this button to change the configuration of the selected camera.<br><br>The availability of this feature and the contents of the Configuration dialog depend on the camera model."));
+ act->plug(m_toolbar);
+ act = new KAction(i18n("Information"), "hwinfo", 0, this, SLOT(slot_cameraSummary()), m_actions, "camera_summary");
+ act->setWhatsThis(i18n("Click this button to view a summary of the current status of the selected camera.<br><br>The availability of this feature and the contents of the Configuration dialog depend on the camera model."));
+ act->plug(m_toolbar);
+ m_toolbar->insertLineSeparator();
+ act = new KAction(i18n("Cancel"), "stop", 0, this, SLOT(slot_cancelOperation()), m_actions, "camera_cancel");
+ act->setWhatsThis(i18n("Click this button to cancel the current camera operation."));
+ act->setEnabled(false);
+ act->plug(m_toolbar);
+}
+
+void KKameraConfig::populateDeviceListView(void)
+{
+ m_deviceSel->clear();
+ CameraDevicesMap::Iterator it;
+ for (it = m_devices.begin(); it != m_devices.end(); it++) {
+ if (it.data()) {
+ new QIconViewItem(m_deviceSel, it.key(), DesktopIcon("camera"));
+ }
+ }
+ slot_deviceSelected(m_deviceSel->currentItem());
+}
+
+void KKameraConfig::save(void)
+{
+ CameraDevicesMap::Iterator it;
+
+ for (it = m_devices.begin(); it != m_devices.end(); it++)
+ {
+ it.data()->save(m_config);
+ }
+ m_config->sync();
+}
+
+void KKameraConfig::load(void)
+{
+ load( false );
+}
+
+void KKameraConfig::load(bool useDefaults )
+{
+ m_config->setReadDefaults( useDefaults );
+ 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 != "<default>") {
+ m_config->setGroup(*it);
+ if (m_config->readEntry("Path").contains("usb:"))
+ continue;
+
+ kcamera = new KCamera(*it,m_config->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 &)));
+ 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<QString,QString> ports, names;
+
+ for (i = 0 ; i<count ; i++) {
+ gp_list_get_name (list, i, &model);
+ gp_list_get_value (list, i, &value);
+
+ ports[value] = model;
+ if (!strcmp(value,"usb:"))
+ names[model] = value;
+ }
+ if (ports.contains("usb:") && names[ports["usb:"]]!="usb:")
+ ports.remove("usb:");
+
+ QMap<QString,QString>::iterator portit;
+
+ for (portit = ports.begin() ; portit != ports.end(); portit++) {
+ /* kdDebug() << "Adding USB camera: " << portit.data() << " at " << portit.key() << endl; */
+
+ kcamera = new KCamera(portit.data(),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 &)));
+ m_devices[portit.data()] = kcamera;
+ }
+ populateDeviceListView();
+
+ gp_list_free (list);
+
+ emit changed( useDefaults );
+}
+
+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->currentItem());
+}
+
+QString KKameraConfig::suggestName(const QString &name)
+{
+ QString new_name = name;
+ new_name.replace("/", ""); // 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::null;
+}
+
+void KKameraConfig::slot_addCamera()
+{
+ KCamera *m_device = new KCamera(QString::null,QString::null);
+ 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 &)));
+ 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()
+{
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ m_devices.remove(name);
+ delete m_device;
+ m_config->deleteGroup(name, true);
+ populateDeviceListView();
+ emit changed(true);
+ }
+}
+
+void KKameraConfig::slot_testCamera()
+{
+ beforeCameraOperation();
+
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ if (m_device->test())
+ KMessageBox::information(this, i18n("Camera test was successful."));
+ }
+
+ afterCameraOperation();
+}
+
+void KKameraConfig::slot_configureCamera()
+{
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ m_device->configure();
+ }
+}
+
+void KKameraConfig::slot_cameraSummary()
+{
+ QString summary;
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ 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(QIconViewItem *item, const QPoint &point)
+{
+ if (item) {
+ m_devicePopup->clear();
+ m_actions->action("camera_test")->plug(m_devicePopup);
+ m_actions->action("camera_remove")->plug(m_devicePopup);
+ m_actions->action("camera_configure")->plug(m_devicePopup);
+ m_actions->action("camera_summary")->plug(m_devicePopup);
+ m_devicePopup->popup(point);
+ }
+}
+
+void KKameraConfig::slot_deviceSelected(QIconViewItem *item)
+{
+ m_actions->action("camera_test")->setEnabled(item);
+ m_actions->action("camera_remove")->setEnabled(item);
+ m_actions->action("camera_configure")->setEnabled(item);
+ m_actions->action("camera_summary")->setEnabled(item);
+}
+
+void KKameraConfig::cbGPIdle(GPContext * /*context*/, void * /*data*/)
+{
+ /*KKameraConfig *self( reinterpret_cast<KKameraConfig*>(data) );*/
+
+ qApp->processEvents();
+}
+
+GPContextFeedback KKameraConfig::cbGPCancel(GPContext * /*context*/, void *data)
+{
+ KKameraConfig *self( reinterpret_cast<KKameraConfig*>(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("<h1>Digital Camera</h1>\n"
+ "This module allows you to configure support for your digital camera.\n"
+ "You would 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 doesn't\n"
+ "appear in the list of <i>Supported Cameras</i>, go to the\n"
+ "<a href=\"http://www.gphoto.org\">GPhoto web site</a> for a possible update.<br><br>\n"
+ "To view and download images from the digital camera, go to address\n"
+ "<a href=\"camera:/\">camera:/</a> 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);
+}
+
diff --git a/kamera/kcontrol/kamera.desktop b/kamera/kcontrol/kamera.desktop
new file mode 100644
index 00000000..0fda1401
--- /dev/null
+++ b/kamera/kcontrol/kamera.desktop
@@ -0,0 +1,193 @@
+[Desktop Entry]
+Comment=Configure Kamera
+Comment[af]=Konfigureer Kamera
+Comment[ar]=إعداد Kamera
+Comment[az]=Kameranı Quraşdır
+Comment[bg]=Настройване на цифров фотоапарат
+Comment[br]=Kefluniañ Kamera
+Comment[bs]=Podesi kameru
+Comment[ca]=Configura Kamera
+Comment[cs]=Nastavení Kamery
+Comment[cy]=Ffurfweddu Kamera
+Comment[da]=Indstil kamera
+Comment[de]=Kamera einrichten
+Comment[el]=Ρύθμιση Kamera
+Comment[eo]=Agordu fotilon
+Comment[es]=Configura Kamera
+Comment[et]=Kaamera seadistamine
+Comment[eu]=Konfiguratu Kamera
+Comment[fa]=پیکربندی Kamera
+Comment[fi]=Kameran asetukset
+Comment[fr]=Configuration de Kamera
+Comment[ga]=Cumraigh Kamera
+Comment[gl]=Configurar Kamera
+Comment[he]=שינוי הגדרות Kamera
+Comment[hi]=कॉन्फ़िगर केमरा
+Comment[hr]=Podesi Kameru
+Comment[hu]=A digitális fényképezőgépek beállításai
+Comment[id]=Konfigurasi kamera
+Comment[is]=Stilla samskiptaforrit stafrænna myndavéla (Kamera)
+Comment[it]=Configura Kamera
+Comment[ja]=カメラの設定
+Comment[kk]=Kamera баптаулары
+Comment[km]=កំណត់​រចនាសម្ព័ន្ធ Kamera
+Comment[ko]=카메라 설정
+Comment[lt]=Konfigūruoti Kamera
+Comment[mk]=Конфигурирајте ја Kamera
+Comment[ms]=Konfigurasi Kamera
+Comment[mt]=Ikkonfigura Kamera
+Comment[nb]=Tilpass Kamera
+Comment[nds]=Kamera instellen
+Comment[ne]=क्यामेरा कन्फिगर गर्नुहोस्
+Comment[nl]=Camera instellen
+Comment[nn]=Set opp Kamera
+Comment[nso]=Beakanya Kamera
+Comment[pa]=ਕੈਮਰਾ ਸੰਰਚਨਾ
+Comment[pl]=Konfiguracja Kamery
+Comment[pt]=Configuração do Kamera
+Comment[pt_BR]=Configurar Kamera
+Comment[ro]=Configurează aparatul foto digital
+Comment[ru]=Настройка камеры
+Comment[se]=Heivet govvenapperáhta
+Comment[sk]=Nastaviť program Kamera
+Comment[sl]=Nastavitve fotoaparata
+Comment[sr]=Подеси Kamera-у
+Comment[sr@Latn]=Podesi Kamera-u
+Comment[sv]=Anpassa kamera
+Comment[ta]=காமிராவை அமை
+Comment[tg]=Танзимоти камера
+Comment[th]=ปรับแต่ง Kamera
+Comment[tr]=Kamera'yı Yapılandır
+Comment[uk]=Налаштувати Kamera
+Comment[uz]=Fotoaparatni moslash
+Comment[uz@cyrillic]=Фотоапаратни мослаш
+Comment[ven]=Dzudzanya kamera
+Comment[xh]=Qwalasela Umfoti
+Comment[zh_CN]=配置 Kamera
+Comment[zh_HK]=設定 Kamera
+Comment[zh_TW]=設定照相機
+Comment[zu]=Hlanganisa ikhamera
+Keywords=gphoto,camera,digicam,webcam,kamera
+Keywords[ar]=gphoto,كاميرا,كاميرا رقمية,كاميرا ويب,kamera
+Keywords[az]=gphoto,kamera,digicam,veb kamera,Kamera,webcam
+Keywords[bg]=фото, апарат, фотоапарат, камера, цифров, цифрова, gphoto, camera, digicam, webcam, kamera
+Keywords[br]=gphoto,kamera,digicam,webcam,kamera
+Keywords[ca]=gphoto,càmera,digicam,webcam,kamera
+Keywords[cs]=gphoto,Kamera,Digitální kamera,Webová kamera,Foto
+Keywords[da]=gphoto,kamera,digicam,webcam
+Keywords[de]=gphoto,Kamera,Digicam,Webcam,Digitalkamera
+Keywords[el]=gphoto,κάμερα,digicam,webcam,kamera
+Keywords[eo]=gphoto,kamerao,fotilo,cifereca fotilo,TTT-fotilo
+Keywords[es]=gphoto,cámara,digicam,webcam,kamera
+Keywords[et]=gphoto,kaamera,digitaalkaamera,veebikaamera,kamera
+Keywords[eu]=gphoto,kamera,digicam,webcam,kamera
+Keywords[fa]=gphoto، دوربین، دوربین رقمی، دوربین وب، kamera
+Keywords[fi]=gphoto,kamera,digicam,webcam
+Keywords[fr]=gphoto,camera,digicam,webcam,kamera,caméscope,caméra,appareil photo
+Keywords[he]=gphoto,kamera,מצלמה,מצלמת רשת,מצלמה דיגיטלית, amera,digicam,webcam
+Keywords[hi]=जीफोटो,केमरा,डिजिकेम,वेबकेम,केमरा
+Keywords[hu]=gphoto,fényképezőgép,digitális fényképezőgép,webkamera,videókamera
+Keywords[is]=gphoto,myndavél,stafræn myndavél,webcam,kamera
+Keywords[it]=gphoto,fotocamera,macchina fotografica digitale,webcam,kamera
+Keywords[ja]=gphoto,カメラ,デジカム,ウェブカム,kamera
+Keywords[km]=gphoto,ម៉ាស៊ីន​ថត​រូប,digicam,ម៉ាស៊ីនថត​តាម​បណ្ដាញ,kamera
+Keywords[ko]=gphoto,camera,digicam,webcam,kamera,사진,카메라,사진기,웹캠
+Keywords[lv]=gfoto,camera,digicam,webcam,kamera
+Keywords[nb]=gphoto,kamera,digicam,webcam,webkamera
+Keywords[nds]=gphoto,Kamera,Webcam,Kamera,Nettkamera
+Keywords[ne]=जी फोटो, क्यामेरा, डिजिक्याम, वेबक्याम, कामेरा
+Keywords[nl]=gphoto,camera,digicam,webcam,kamera,foto
+Keywords[nn]=gphoto,fotoapparat,digitalt kamera,webkamera,vevkamera,kamera
+Keywords[pl]=gphoto,kamera,kamera cyfrowa,kamera sieciowa
+Keywords[pt]=gphoto,câmara,digicam,webcam,kamera
+Keywords[pt_BR]=gphoto,câmera,câmera digital,webcam,kamera
+Keywords[ro]=gphoto,aparat,foto,digicam,webcam,camera,kamera
+Keywords[ru]=gphoto,camera,digicam,webcam,kamera,камера,фото
+Keywords[sl]=gphoto,kamera,digicam,webcam,foto,fotoaparat,spletna kamera
+Keywords[sr]=gphoto,camera,digicam,webcam,kamera,камера
+Keywords[sr@Latn]=gphoto,camera,digicam,webcam,kamera,kamera
+Keywords[sv]=gphoto,kamera,digital kamera,webbkamera,kamera
+Keywords[ta]=ஜிபோட்டோ, காமிரா, டிஜிகேம்,வலைதள காமிரா, காமிரா
+Keywords[tg]=gphoto,camera,digicam,webcam,kamera,камера,фото
+Keywords[tr]=gphoto,kamera,digicam,web kamera,Kamera,webcam
+Keywords[uk]=gphoto,камера,цифрова камера,камера Тенет,kamera
+Keywords[ven]=Tshinepe tsha g,Tshaudzhia zwifanyiso,digicam,webcam,Tshaudzhiazwifanyiso
+Keywords[xh]=gphoto,umfoti,digicam,webcam,umfoti
+Keywords[zh_CN]=gphoto,camera,digicam,webcam,kamera,照相机,数码相机,摄像头
+Keywords[zh_TW]=gphoto,camera,digicam,webcam,kamera,照相機
+Keywords[zu]=gphoto,ikhamera,digicam,webcam,ikhamera
+Name=Digital Camera
+Name[af]=Digitaal Kamera
+Name[ar]=كاميرا رقمية
+Name[az]=Digital Kamera
+Name[bg]=Фотоапарат
+Name[br]=Kamera niverel
+Name[bs]=Digitalna kamera
+Name[ca]=Càmera digital
+Name[cs]=Digitální fotoaparát
+Name[cy]=Camera Digidol
+Name[da]=Digitalt kamera
+Name[de]=Digitalkamera
+Name[el]=Ψηφιακή κάμερα
+Name[eo]=Cifereca fotilo
+Name[es]=Cámara digital
+Name[et]=Digitaalkaamera
+Name[eu]=Kamera digitala
+Name[fa]=دوربین رقمی
+Name[fi]=Digitaalikamera
+Name[fr]=Appareil photo numérique
+Name[ga]=Ceamara Digiteach
+Name[gl]=Cámara dixital
+Name[he]=מצלמה דיגיטלית
+Name[hi]=डिजिटल कैमरा
+Name[hr]=Digitalna kamera
+Name[hu]=Digitális fényképezőgép
+Name[is]=Stafræn myndavél
+Name[it]=Macchina fotografica digitale
+Name[ja]=デジタルカメラ
+Name[kk]=Цифрлық камера
+Name[km]=ម៉ាស៊ីន​ថតរូប​ឌីជីថល
+Name[lt]=Skaitmeninė kamera
+Name[lv]=Digitālā Kamera
+Name[mk]=Дигитална камера
+Name[ms]=Kamera Digital
+Name[mt]=Kamera diġitali
+Name[nb]=Digitalkamera
+Name[nds]=Digitaalkamera
+Name[ne]= डिजिटल क्यामेरा
+Name[nl]=Digitale camera
+Name[nn]=Digitalkamera
+Name[nso]=Camera ya Digital
+Name[pa]=ਡਿਜ਼ੀਟਲ ਕੈਮਰਾ
+Name[pl]=Aparat cyfrowy
+Name[pt]=Máquina Fotográfica Digital
+Name[pt_BR]=Câmera Digital
+Name[ro]=Aparat foto digital
+Name[ru]=Цифровая камера
+Name[se]=Digitalalaš govvenapperáhtta
+Name[sk]=Digitálny fotoaparát
+Name[sl]=Digitalni fotoaparat
+Name[sr]=Дигитална камера
+Name[sr@Latn]=Digitalna kamera
+Name[sv]=Digitalkamera
+Name[ta]= Digital Camera
+Name[tg]=Камераи digital
+Name[th]=กล้องดิจิตอล
+Name[tr]=Sayısal Kamera
+Name[uk]=Цифровий фотоапарат
+Name[uz]=Fotoaparat
+Name[uz@cyrillic]=Фотоапарат
+Name[ven]=Tshau dzhia zwifanyiso tsha didzhithala
+Name[xh]=Ikhamera Yesuntswana
+Name[zh_CN]=数码相机
+Name[zh_HK]=數碼相機
+Name[zh_TW]=數位相機
+Name[zu]=Ikhamera ebonisa inani ngalinye
+Terminal=false
+Type=Application
+X-KDE-Library=kamera
+X-KDE-ModuleType=Library
+Icon=camera
+Exec=kcmshell kamera
+DocPath=kamera/index.html
+Categories=Qt;KDE;Settings;X-KDE-settings-hardware;
diff --git a/kamera/kcontrol/kamera.h b/kamera/kcontrol/kamera.h
new file mode 100644
index 00000000..35f93bc0
--- /dev/null
+++ b/kamera/kcontrol/kamera.h
@@ -0,0 +1,115 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 __kamera_h__
+#define __kamera_h__
+
+#include <kcmodule.h>
+#include <gphoto2.h>
+
+class QWidget;
+class QRadioButton;
+class QPushButton;
+class QComboBox;
+class QVButtonGroup;
+class QLineEdit;
+class QWidgetStack;
+class QCheckBox;
+class QIconViewItem;
+
+class KCamera;
+class KameraDeviceSelectDialog;
+class KSimpleConfig;
+class KIconView;
+class KActionCollection;
+class KToolBar;
+class KPopupMenu;
+
+class KKameraConfig : public KCModule
+{
+ Q_OBJECT
+ friend class KameraDeviceSelectDialog;
+
+public:
+ KKameraConfig(QWidget *parent, const char *name, const QStringList &);
+ virtual ~KKameraConfig();
+
+ // KCModule interface methods
+ void load();
+ void load(bool useDefaults);
+ void save();
+ void defaults();
+ int buttons();
+ QString quickHelp() const;
+
+protected:
+ QString suggestName(const QString &name);
+
+protected slots:
+ void slot_deviceMenu(QIconViewItem *item, const QPoint &point);
+ void slot_deviceSelected(QIconViewItem *item);
+ void slot_addCamera();
+ void slot_removeCamera();
+ void slot_configureCamera();
+ void slot_cameraSummary();
+ void slot_testCamera();
+ void slot_cancelOperation();
+ void slot_error(const QString &message);
+ void slot_error(const QString &message, const QString &details);
+
+private:
+ void displayGPFailureDialogue(void);
+ void displayGPSuccessDialogue(void);
+ void displayCameraAbilities(const CameraAbilities &abilities);
+ void populateDeviceListView(void);
+ void beforeCameraOperation(void);
+ void afterCameraOperation(void);
+
+ // gphoto callbacks
+ static void cbGPIdle(GPContext *context, void *data);
+ static GPContextFeedback cbGPCancel(GPContext *context, void *data);
+
+private:
+ typedef QMap<QString, KCamera *> CameraDevicesMap;
+
+ KSimpleConfig *m_config;
+ CameraDevicesMap m_devices;
+ bool m_cancelPending;
+
+ // gphoto members
+ GPContext *m_context;
+
+ // widgets for the cameras listview
+ KIconView *m_deviceSel;
+ KActionCollection *m_actions;
+ QPushButton *m_addCamera, *m_removeCamera, *m_testCamera, *m_configureCamera;
+ KToolBar *m_toolbar;
+ KPopupMenu *m_devicePopup;
+
+ // true if libgphoto2 was initialised successfully in
+ // the constructor
+ bool m_gpInitialised;
+
+ static KKameraConfig *m_instance;
+};
+
+#endif
diff --git a/kamera/kcontrol/kameraconfigdialog.cpp b/kamera/kcontrol/kameraconfigdialog.cpp
new file mode 100644
index 00000000..5af0b33d
--- /dev/null
+++ b/kamera/kcontrol/kameraconfigdialog.cpp
@@ -0,0 +1,317 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 <qlayout.h>
+#include <qgrid.h>
+#include <qlabel.h>
+#include <qvgroupbox.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qslider.h>
+#include <qvbuttongroup.h>
+#include <qhbuttongroup.h>
+#include <qvbox.h>
+#include <qtabwidget.h>
+#include <qwhatsthis.h>
+
+#include <klocale.h>
+
+#include "kameraconfigdialog.h"
+#include "kameraconfigdialog.moc"
+
+KameraConfigDialog::KameraConfigDialog(Camera */*camera*/,
+ CameraWidget *widget,
+ QWidget *parent,
+ const char *name) :
+KDialogBase(parent, name, true, QString::null, Ok|Cancel, Ok ),
+m_widgetRoot(widget)
+{
+ QFrame *main = makeMainWidget();
+ QVBoxLayout *topLayout = new QVBoxLayout(main, 0, spacingHint());
+ topLayout->setAutoAdd(true);
+
+ m_tabWidget = 0;
+
+ appendWidget(main, widget);
+}
+
+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;
+ 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:
+ {
+ setCaption(widget_label);
+
+ break;
+ }
+ case GP_WIDGET_SECTION:
+ {
+ if (!m_tabWidget)
+ m_tabWidget = new QTabWidget(parent);
+ QWidget *tab = new QWidget(m_tabWidget);
+ // widgets are to be aligned vertically in the tab
+ QVBoxLayout *tabLayout = new QVBoxLayout(tab, marginHint(),
+ spacingHint());
+ m_tabWidget->insertTab(tab, widget_label);
+ QVBox *tabContainer = new QVBox(tab);
+ tabContainer->setSpacing(spacingHint());
+ tabLayout->addWidget(tabContainer);
+ newParent = tabContainer;
+
+ tabLayout->addStretch();
+
+ break;
+ }
+ case GP_WIDGET_TEXT:
+ {
+ gp_widget_get_value(widget, &widget_value_string);
+
+ QGrid *grid = new QGrid(2, Horizontal, parent);
+ grid->setSpacing(spacingHint());
+ new QLabel(QString::fromLocal8Bit( widget_label )+":", grid);
+ QLineEdit *lineEdit = new QLineEdit(widget_value_string, grid);
+ m_wmap.insert(widget, lineEdit);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(grid, whats_this);
+
+ break;
+ }
+ case 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);
+
+ QGroupBox *groupBox = new QVGroupBox(widget_label, parent);
+ QSlider *slider = new QSlider(
+ ( int )widget_low,
+ ( int )widget_high,
+ ( int )widget_increment,
+ ( int )widget_value_float,
+ QSlider::Horizontal,
+ groupBox );
+ m_wmap.insert(widget, slider);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(groupBox, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_TOGGLE:
+ {
+ gp_widget_get_value(widget, &widget_value_int);
+
+ QCheckBox *checkBox = new QCheckBox(widget_label, parent);
+ checkBox->setChecked(widget_value_int);
+ m_wmap.insert(widget, checkBox);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(checkBox, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_RADIO:
+ {
+ gp_widget_get_value(widget, &widget_value_string);
+
+ int count = gp_widget_count_choices(widget);
+
+ // for less than 5 options, align them horizontally
+ QButtonGroup *buttonGroup;
+ if (count > 4)
+ buttonGroup = new QVButtonGroup(widget_label, parent);
+ else
+ buttonGroup = new QHButtonGroup(widget_label, parent);
+
+ for(int i = 0; i < count; ++i) {
+ const char *widget_choice;
+ gp_widget_get_choice(widget, i, &widget_choice);
+
+ new QRadioButton(widget_choice, buttonGroup);
+ if(!strcmp(widget_value_string, widget_choice))
+ buttonGroup->setButton(i);
+ }
+ m_wmap.insert(widget, buttonGroup);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(buttonGroup, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_MENU:
+ {
+ gp_widget_get_value(widget, &widget_value_string);
+
+ QComboBox *comboBox = new QComboBox(FALSE, parent);
+ 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->insertItem(widget_choice);
+ if(!strcmp(widget_value_string, widget_choice))
+ comboBox->setCurrentItem(i);
+ }
+ m_wmap.insert(widget, comboBox);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(comboBox, 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
+ new QLabel(i18n("Button (not supported by KControl)"), parent);
+
+ break;
+ }
+ case GP_WIDGET_DATE:
+ {
+ // TODO
+ new QLabel(i18n("Date (not supported by KControl)"), parent);
+
+ 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);
+ }
+
+ // Things that must be done after all children were added
+/*
+ switch (widget_type) {
+ case GP_WIDGET_SECTION:
+ {
+ tabLayout->addItem( new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) );
+ break;
+ }
+ }
+*/
+}
+
+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<QLineEdit *>(m_wmap[widget]);
+ gp_widget_set_value(widget, (void *)lineEdit->text().local8Bit().data());
+
+ break;
+ }
+ case GP_WIDGET_RANGE:
+ {
+ QSlider *slider = static_cast<QSlider *>(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<QCheckBox *>(m_wmap[widget]);
+ int value_int = checkBox->isChecked() ? 1 : 0;
+ gp_widget_set_value(widget, (void *)&value_int);
+
+ break;
+ }
+ case GP_WIDGET_RADIO:
+ {
+ QButtonGroup *buttonGroup = static_cast<QVButtonGroup *>(m_wmap[widget]);
+ gp_widget_set_value(widget, (void *)buttonGroup->selected()->text().local8Bit().data());
+
+ break;
+ }
+ case GP_WIDGET_MENU:
+ {
+ QComboBox *comboBox = static_cast<QComboBox *>(m_wmap[widget]);
+ gp_widget_set_value(widget, (void *)comboBox->currentText().local8Bit().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/kamera/kcontrol/kameraconfigdialog.h b/kamera/kcontrol/kameraconfigdialog.h
new file mode 100644
index 00000000..73b2a012
--- /dev/null
+++ b/kamera/kcontrol/kameraconfigdialog.h
@@ -0,0 +1,53 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 __kameraconfigdialog_h__
+#define __kameraconfigdialog_h__
+
+#include <qmap.h>
+#include <kdialogbase.h>
+#include <qtabwidget.h>
+
+extern "C" {
+ #include <gphoto2.h>
+}
+
+class KameraConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KameraConfigDialog(Camera *camera, CameraWidget *widget,
+ QWidget *parent = 0, const char *name = 0);
+
+private slots:
+ void slotOk();
+
+private:
+ void appendWidget(QWidget *parent, CameraWidget *widget);
+ void updateWidgetValue(CameraWidget *widget);
+
+ QMap<CameraWidget *, QWidget *> m_wmap;
+ CameraWidget *m_widgetRoot;
+ QTabWidget *m_tabWidget;
+};
+
+#endif
diff --git a/kamera/kcontrol/kameradevice.cpp b/kamera/kcontrol/kameradevice.cpp
new file mode 100644
index 00000000..010bf694
--- /dev/null
+++ b/kamera/kcontrol/kameradevice.cpp
@@ -0,0 +1,476 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 <qlayout.h>
+#include <qwidgetstack.h>
+#include <qvbuttongroup.h>
+#include <qvgroupbox.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qradiobutton.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+#include <qgrid.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <klistview.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+extern "C" {
+ #include <gphoto2.h>
+}
+
+#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 QString &name, const QString &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.").arg(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;
+}
+
+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(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);
+}
+
+QString KCamera::portName()
+{
+ QString 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 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)
+ : KDialogBase(parent, "kkameradeviceselect", true, i18n("Select Camera Device"), Ok | Cancel, Ok, 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 &)));
+
+ QWidget *page = new QWidget( this );
+ setMainWidget(page);
+
+ // a layout with vertical boxes
+ QHBoxLayout *topLayout = new QHBoxLayout(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, QListView::Maximum);
+ connect(m_modelSel, SIGNAL(selectionChanged(QListViewItem *)),
+ SLOT(slot_setModel(QListViewItem *)));
+ // make sure listview only as wide as it needs to be
+ m_modelSel->setSizePolicy(QSizePolicy(QSizePolicy::Maximum,
+ QSizePolicy::Preferred));
+
+ QVBoxLayout *rightLayout = new QVBoxLayout(0L, 0, KDialog::spacingHint());
+ topLayout->addLayout( rightLayout );
+
+ m_portSelectGroup = new QVButtonGroup(i18n("Port"), page);
+ rightLayout->addWidget(m_portSelectGroup);
+ m_portSettingsGroup = new QVGroupBox(i18n("Port Settings"), page);
+ rightLayout->addWidget(m_portSettingsGroup);
+
+ // Create port type selection radiobuttons.
+ m_serialRB = new QRadioButton(i18n("Serial"), m_portSelectGroup);
+ m_portSelectGroup->insert(m_serialRB, INDEX_SERIAL);
+ QWhatsThis::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 QRadioButton(i18n("USB"), m_portSelectGroup);
+ m_portSelectGroup->insert(m_USBRB, INDEX_USB);
+ QWhatsThis::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 QWidgetStack(m_portSettingsGroup);
+ connect(m_portSelectGroup, SIGNAL(clicked(int)),
+ m_settingsStack, SLOT(raiseWidget(int)));
+
+ // none tab
+ m_settingsStack->addWidget(new QLabel(i18n("No port type selected."),
+ m_settingsStack), INDEX_NONE);
+
+ // serial tab
+ QGrid *grid = new QGrid(2, m_settingsStack);
+ grid->setSpacing(KDialog::spacingHint());
+ new QLabel(i18n("Port:"), grid);
+ m_serialPortCombo = new QComboBox(TRUE, grid);
+ QWhatsThis::add(m_serialPortCombo, i18n("Here you should choose the serial port you connect the camera to."));
+ m_settingsStack->addWidget(grid, INDEX_SERIAL);
+
+ grid = new QGrid(2, m_settingsStack);
+ grid->setSpacing(KDialog::spacingHint());
+ new QLabel(i18n("Port"), grid);
+
+ m_settingsStack->addWidget(new
+ QLabel(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(QString::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 QListViewItem(m_modelSel, a.model);
+ }
+ }
+ return true;
+ }
+}
+
+void KameraDeviceSelectDialog::save()
+{
+ m_device->setModel(m_modelSel->currentItem()->text(0));
+
+ if (m_portSelectGroup->selected()) {
+ QString 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()
+{
+ QString path = m_device->path();
+ QString port = path.left(path.find(":")).lower();
+
+ if (port == "serial") setPortType(INDEX_SERIAL);
+ if (port == "usb") setPortType(INDEX_USB);
+
+ QListViewItem *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(QListViewItem *item)
+{
+ enableButtonOK(true);
+ m_portSelectGroup->setEnabled(true);
+ m_portSettingsGroup->setEnabled(true);
+
+ QString 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.").arg(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
+ QButton *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.").arg(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 QString &message)
+{
+ KMessageBox::error(this, message);
+}
+
+void KameraDeviceSelectDialog::slot_error(const QString &message, const QString &details)
+{
+ KMessageBox::detailedError(this, message, details);
+}
diff --git a/kamera/kcontrol/kameradevice.h b/kamera/kcontrol/kameradevice.h
new file mode 100644
index 00000000..aae24e02
--- /dev/null
+++ b/kamera/kcontrol/kameradevice.h
@@ -0,0 +1,117 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 <qmap.h>
+#include <kdialogbase.h>
+#include <config.h>
+
+class KConfig;
+class QString;
+class KListView;
+class QWidgetStack;
+class QVButtonGroup;
+class QVGroupBox;
+class QComboBox;
+class QLineEdit;
+class QRadioButton;
+
+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();
+
+signals:
+ void error(const QString &message);
+ void error(const QString &message, const QString &details);
+
+protected:
+ bool initInformation();
+ bool initCamera();
+// void doConfigureCamera(Camera *camera, CameraWidget *widgets);
+// int frontend_prompt(Camera *camera, CameraWidget *widgets);
+
+ Camera *m_camera;
+// KConfig *m_config;
+ QString m_name; // the camera's real name
+ QString m_model;
+ QString m_path;
+ CameraAbilities m_abilities;
+ CameraAbilitiesList *m_abilitylist;
+};
+
+class KameraDeviceSelectDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KameraDeviceSelectDialog(QWidget *parent, KCamera *device);
+ void save();
+ void load();
+protected slots:
+ void slot_setModel(QListViewItem *item);
+ void slot_error(const QString &message);
+ void slot_error(const QString &message, const QString &details);
+protected:
+ KCamera *m_device;
+
+ bool populateCameraListView(void);
+ void setPortType(int type);
+
+ // port settings widgets
+ KListView *m_modelSel;
+ QLineEdit *m_nameEdit;
+ QWidgetStack *m_settingsStack;
+ QVButtonGroup *m_portSelectGroup;
+ QVGroupBox *m_portSettingsGroup;
+ QComboBox *m_serialPortCombo;
+ // port selection radio buttons
+ QRadioButton *m_serialRB;
+ QRadioButton *m_USBRB;
+};
+
+#endif
diff --git a/kamera/kioslave/Makefile.am b/kamera/kioslave/Makefile.am
new file mode 100644
index 00000000..4c6c148e
--- /dev/null
+++ b/kamera/kioslave/Makefile.am
@@ -0,0 +1,17 @@
+# $Id$
+# Makefile for kdebase/kioslave/kamera
+
+INCLUDES= -I$(srcdir)/../.. -I$(srcdir)/.. $(all_includes) $(GPHOTO2_INCS)
+
+####### Files
+
+kde_module_LTLIBRARIES = kio_kamera.la
+
+kio_kamera_la_SOURCES = kamera.cpp
+kio_kamera_la_LIBADD = $(LIB_KIO) -lgphoto2
+kio_kamera_la_LDFLAGS = $(all_libraries) $(GPHOTO2_LIBS) -module $(KDE_PLUGIN)
+
+noinst_HEADERS = kamera.h
+
+kde_services_DATA = camera.protocol
+
diff --git a/kamera/kioslave/camera.protocol b/kamera/kioslave/camera.protocol
new file mode 100644
index 00000000..947d02b9
--- /dev/null
+++ b/kamera/kioslave/camera.protocol
@@ -0,0 +1,16 @@
+[Protocol]
+exec=kio_kamera
+protocol=camera
+input=none
+output=filesystem
+listing=Name,Type
+reading=true
+writing=false
+deleting=true
+source=true
+makedir=false
+linking=false
+moving=false
+Icon=camera
+maxInstances=1
+Class=:local
diff --git a/kamera/kioslave/kamera.cpp b/kamera/kioslave/kamera.cpp
new file mode 100644
index 00000000..ab4eb469
--- /dev/null
+++ b/kamera/kioslave/kamera.cpp
@@ -0,0 +1,1066 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2001-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2001-2007 Marcus Meissner <marcus@jet.franken.de>
+
+ 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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include <kinstance.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <kio/slaveconfig.h>
+
+#include <config.h>
+
+#include "kamera.h"
+
+#define MAXIDLETIME 30 /* seconds */
+
+#define tocstr(x) ((x).local8Bit())
+
+using namespace KIO;
+
+extern "C"
+{
+ KDE_EXPORT int kdemain(int argc, char **argv);
+
+ 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
+ );
+ static void frontendProgressUpdate(
+ GPContext *context, unsigned int id, float current, void *data
+ );
+}
+
+int kdemain(int argc, char **argv)
+{
+ KInstance instance("kio_kamera");
+
+ if(argc != 4) {
+ kdDebug(7123) << "Usage: kio_kamera protocol "
+ "domain-socket1 domain-socket2" << endl;
+ exit(-1);
+ }
+ KameraProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+ return 0;
+}
+
+KameraProtocol::KameraProtocol(const QCString &pool, const QCString &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 KSimpleConfig(KProtocolInfo::config("camera"));
+ m_context = gp_context_new();
+ actiondone = true;
+ cameraopen = false;
+ m_lockfile = locateLocal("tmp", "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 existance of a lockfile is used to signify "please give up camera".
+//
+void KameraProtocol::special(const QByteArray&) {
+ kdDebug(7123) << "KameraProtocol::special() at " << getpid() << endl;
+
+ if (!actiondone && cameraopen) {
+ struct stat stbuf;
+ if ((-1!=::stat(m_lockfile.utf8(),&stbuf)) || (idletime++ >= MAXIDLETIME)) {
+ kdDebug(7123) << "KameraProtocol::special() closing camera." << endl;
+ 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()
+{
+ kdDebug(7123) << "KameraProtocol::~KameraProtocol()" << endl;
+ 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;
+ kdDebug(7123) << "KameraProtocol::openCamera at " << getpid() << endl;
+ 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.utf8(),O_CREAT|O_WRONLY,0600);
+ if (fd != -1) ::close(fd);
+ ::sleep(1);
+ kdDebug(7123) << "openCamera at " << getpid() << "- busy, ret " << ret << ", trying again." << endl;
+ continue;
+ }
+ if (ret == GP_OK) break;
+ str = gp_result_as_string(ret);
+ return false;
+ }
+ ::unlink(m_lockfile.utf8());
+ setTimeoutSpecialCommand(1);
+ kdDebug(7123) << "openCamera succeeded at " << getpid() << endl;
+ cameraopen = true;
+ }
+ }
+ return true;
+}
+
+// should be done after operations over the wire
+void KameraProtocol::closeCamera(void)
+{
+ int gpr;
+
+ if (!m_camera)
+ return;
+
+ kdDebug(7123) << "KameraProtocol::closeCamera at " << getpid() << endl;
+ if ((gpr=gp_camera_exit(m_camera,m_context))!=GP_OK) {
+ kdDebug(7123) << "closeCamera failed with " << gp_result_as_string(gpr) << endl;
+ }
+ // 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;
+ 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 KURL &url)
+{
+ kdDebug(7123) << "KameraProtocol::get(" << url.path() << ")" << endl;
+
+ CameraFileType fileType;
+ int gpr;
+ if (url.host().isEmpty()) {
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ return;
+ }
+
+ if(!openCamera()) {
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ return;
+ }
+
+ // fprintf(stderr,"get(%s)\n",url.path().latin1());
+
+#define GPHOTO_TEXT_FILE(xx) \
+ if (!url.path().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; \
+ chunkDataBuffer.setRawData(xx.text, strlen(xx.text)); \
+ data(chunkDataBuffer); \
+ processedSize(strlen(xx.text)); \
+ chunkDataBuffer.resetRawData(xx.text, strlen(xx.text)); \
+ finished(); \
+ return; \
+ }
+
+ GPHOTO_TEXT_FILE(about);
+ GPHOTO_TEXT_FILE(manual);
+ GPHOTO_TEXT_FILE(summary);
+
+#undef GPHOTO_TEXT_FILE
+ // emit info message
+ infoMessage( i18n("Retrieving data from camera <b>%1</b>").arg(url.user()) );
+
+ // 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(url.directory(false))), tocstr(url.fileName()), &info, m_context);
+ if (gpr != GP_OK) {
+ // fprintf(stderr,"Folder %s / File %s not found, gpr is %d\n",folder.latin1(), url.fileName().latin1(), gpr);
+ 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, gp_result_as_string(gpr));
+ return;
+ }
+
+ // at last, a proper API to determine whether a thumbnail was requested.
+ if(cameraSupportsPreview() && metaData("thumbnail") == "1") {
+ kdDebug(7123) << "get() retrieving the thumbnail" << endl;
+ 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 {
+ kdDebug(7123) << "get() retrieving the full-scale photo" << endl;
+ 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(url.directory(false))), tocstr(url.fileName()), 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(url.directory(false))), tocstr(url.fileName()), 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, 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) {
+ kdDebug(7123) << "get():: get_data_and_size failed." << endl;
+ gp_file_free(m_file);
+ m_file = NULL;
+ error(KIO::ERR_UNKNOWN, 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.setRawData(fileData + m_fileSize + written, towrite);
+ processedSize(m_fileSize + written + towrite);
+ data(chunkDataBuffer);
+ chunkDataBuffer.resetRawData(fileData + m_fileSize + written, towrite);
+ 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 KURL &url)
+{
+ kdDebug(7123) << "stat(\"" << url.path() << "\")" << endl;
+
+ if (url.path() == "") {
+ KURL rooturl(url);
+
+ kdDebug(7123) << "redirecting to /" << endl;
+ rooturl.setPath("/");
+ rooturl.setHost(url.host());
+ rooturl.setUser(url.user());
+ redirection(rooturl);
+ finished();
+ return;
+ }
+
+ if(url.path() == "/")
+ statRoot();
+ else
+ statRegular(url);
+}
+
+// Implements stat("/") -- which always returns the same value.
+void KameraProtocol::statRoot(void)
+{
+ UDSEntry entry;
+ UDSAtom atom;
+
+ atom.m_uds = UDS_NAME;
+ atom.m_str = "/";
+ entry.append(atom);
+
+ atom.m_uds = UDS_FILE_TYPE;
+ atom.m_long = S_IFDIR;
+ entry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ entry.append(atom);
+
+ statEntry(entry);
+
+ finished();
+
+ // This call happens on autodetect by kdemm. So close the camera, but
+ // only if no more requests are pending.
+ idletime = MAXIDLETIME;
+}
+
+// Implements a regular stat() of a file / directory, returning all we know about it
+void KameraProtocol::statRegular(const KURL &url)
+{
+ UDSEntry entry;
+ int gpr;
+
+ kdDebug(7123) << "statRegular(\"" << url.path() << "\")" << endl;
+ if (openCamera() == false) {
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ return;
+ }
+
+ // fprintf(stderr,"statRegular(%s)\n",url.path().latin1());
+
+ // Is "url" a directory?
+ CameraList *dirList;
+ gp_list_new(&dirList);
+ kdDebug(7123) << "statRegular() Requesting directories list for " << url.directory() << endl;
+
+ gpr = gp_camera_folder_list_folders(m_camera, tocstr(fix_foldername(url.directory(false))), 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, url.path());
+ else
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ gp_list_free(dirList);
+ return;
+ }
+
+#define GPHOTO_TEXT_FILE(xx) \
+ if (!url.path().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, url.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 (url.fileName().compare(name) == 0) {
+ gp_list_free(dirList);
+ UDSEntry entry;
+ translateDirectoryToUDS(entry, url.fileName());
+ 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(url.directory(false))), tocstr(url.fileName()), &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, url.path());
+ else
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ return;
+ }
+ translateFileToUDS(entry, info, url.fileName());
+ statEntry(entry);
+ finished();
+}
+
+// The KIO slave "del" function.
+void KameraProtocol::del(const KURL &url, bool isFile)
+{
+ kdDebug(7123) << "KameraProtocol::del(" << url.path() << ")" << endl;
+
+ if(!openCamera()) {
+ error(KIO::ERR_CANNOT_DELETE, url.fileName());
+ return;
+ }
+ if (!cameraSupportsDel()) {
+ error(KIO::ERR_CANNOT_DELETE, url.fileName());
+ return;
+ }
+ if(isFile){
+ CameraList *list;
+ gp_list_new(&list);
+ int ret;
+
+ ret = gp_camera_file_delete(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), m_context);
+
+ if(ret != GP_OK) {
+ error(KIO::ERR_CANNOT_DELETE, url.fileName());
+ } else {
+ finished();
+ }
+ }
+}
+
+// The KIO slave "listDir" function.
+void KameraProtocol::listDir(const KURL &url)
+{
+ kdDebug(7123) << "KameraProtocol::listDir(" << url.path() << ")" << endl;
+
+ if (url.host().isEmpty()) {
+ KURL xurl;
+ // List the available cameras
+ QStringList groupList = m_config->groupList();
+ kdDebug(7123) << "Found cameras: " << groupList.join(", ") << endl;
+ QStringList::Iterator it;
+ UDSEntry entry;
+ UDSAtom atom;
+
+
+ /*
+ * 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<QString,QString> ports, names;
+ QMap<QString,int> 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<count ; i++) {
+ const char *model, *value;
+
+ gp_list_get_name (list, i, &model);
+ gp_list_get_value (list, i, &value);
+
+ ports[value] = model;
+ // NOTE: We might get different ports than usb: later!
+ if (strcmp(value, "usb:"))
+ names[model] = value;
+
+ /* Save them, even though we can autodetect them for
+ * offline listing.
+ */
+ m_config->setGroup(model);
+ m_config->writeEntry("Model",model);
+ m_config->writeEntry("Path",value);
+ modelcnt[model]++;
+ }
+ gp_list_free (list);
+
+ /* Avoid duplicated entry for usb: and usb:001,042 entries. */
+ if (ports.contains("usb:") && names[ports["usb:"]]!="usb:")
+ ports.remove("usb:");
+
+ for (it = groupList.begin(); it != groupList.end(); it++) {
+ QString m_cfgPath;
+ if (*it == "<default>")
+ continue;
+
+ m_config->setGroup(*it);
+ m_cfgPath = m_config->readEntry("Path");
+
+ /* If autodetect by USB autodetect ... skip it here.
+ * We leave unattached USB cameras in here, because the user
+ * might plug them in later and does not want to press reload.
+ * We add them with port "usb:".
+ */
+ if (modelcnt[*it] > 0)
+ continue;
+
+ entry.clear();
+ atom.m_uds = UDS_FILE_TYPE;atom.m_long = S_IFDIR;entry.append(atom);
+ atom.m_uds = UDS_NAME;atom.m_str = *it;entry.append(atom);
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ entry.append(atom);
+
+ atom.m_uds = UDS_URL;
+
+ xurl.setProtocol("camera");
+ xurl.setUser(*it);
+ /* Avoid setting usb:xxx,yyy. */
+ if (m_cfgPath.contains("usb:")>0) {
+ names[*it] = "usb:";
+ xurl.setHost("usb:");
+ } else {
+ xurl.setHost(m_cfgPath);
+ }
+ xurl.setPath("/");
+ atom.m_str = xurl.url();
+ entry.append(atom);
+
+ listEntry(entry, false);
+ }
+
+ QMap<QString,QString>::iterator portsit;
+
+ for (portsit = ports.begin(); portsit != ports.end(); portsit++) {
+ entry.clear();
+ atom.m_uds = UDS_FILE_TYPE;atom.m_long = S_IFDIR; entry.append(atom);
+ atom.m_uds = UDS_NAME;atom.m_str = portsit.data();entry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ entry.append(atom);
+
+ atom.m_uds = UDS_URL;
+ xurl.setProtocol("camera");
+ xurl.setHost(portsit.key());
+ xurl.setUser(portsit.data());
+ xurl.setPath("/");
+ atom.m_str = xurl.url();
+ entry.append(atom);
+
+ listEntry(entry, false);
+ }
+ listEntry(entry, true);
+
+ finished();
+ return;
+ }
+
+ if (url.path() == "") {
+ KURL rooturl(url);
+
+ kdDebug(7123) << "redirecting to /" << endl;
+ rooturl.setPath("/");
+ rooturl.setHost(url.host());
+ rooturl.setUser(url.user());
+ redirection(rooturl);
+ finished();
+ return;
+ }
+
+ if (!openCamera()) {
+ error(KIO::ERR_COULD_NOT_READ,url.path());
+ return;
+ }
+
+ CameraList *dirList;
+ CameraList *fileList;
+ CameraList *specialList;
+ gp_list_new(&dirList);
+ gp_list_new(&fileList);
+ gp_list_new(&specialList);
+ int gpr;
+
+ if (!url.path().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(url.path(), dirList, fileList);
+ if(gpr != GP_OK) {
+ kdDebug(7123) << "read Camera Folder failed:" << gp_result_as_string(gpr) <<endl;
+ gp_list_free(dirList);
+ gp_list_free(fileList);
+ gp_list_free(specialList);
+ error(KIO::ERR_COULD_NOT_READ, gp_result_as_string(gpr));
+ return;
+ }
+
+ totalSize(gp_list_count(specialList) + gp_list_count(dirList) + gp_list_count(fileList));
+
+ 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, false);
+ }
+
+ 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(url.path()), name, &info, m_context);
+ translateFileToUDS(entry, info, QString::fromLocal8Bit(name));
+ listEntry(entry, false);
+ }
+ if (!url.path().compare("/")) {
+ CameraText text;
+ if (GP_OK == gp_camera_get_manual(m_camera, &text, m_context)) {
+ translateTextToUDS(entry, "manual.txt", text.text);
+ listEntry(entry, false);
+ }
+ if (GP_OK == gp_camera_get_about(m_camera, &text, m_context)) {
+ translateTextToUDS(entry, "about.txt", text.text);
+ listEntry(entry, false);
+ }
+ if (GP_OK == gp_camera_get_summary(m_camera, &text, m_context)) {
+ translateTextToUDS(entry, "summary.txt", text.text);
+ listEntry(entry, false);
+ }
+ }
+
+
+ gp_list_free(fileList);
+ gp_list_free(dirList);
+ gp_list_free(specialList);
+
+ listEntry(entry, true); // 'entry' is not used in this case - we only signal list completion
+ finished();
+}
+
+void KameraProtocol::setHost(const QString& host, int port, const QString& user, const QString& pass )
+{
+ kdDebug(7123) << "KameraProtocol::setHost(" << host << ", " << port << ", " << user << ", " << pass << ")" << endl;
+ int gpr, idx;
+
+ if (!host.isEmpty()) {
+ kdDebug(7123) << "model is " << user << ", port is " << host << endl;
+ if (m_camera) {
+ kdDebug(7123) << "Configuration change detected" << endl;
+ closeCamera();
+ gp_camera_unref(m_camera);
+ m_camera = NULL;
+ infoMessage( i18n("Reinitializing camera") );
+ } else {
+ kdDebug(7123) << "Initializing camera" << endl;
+ 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(user));
+ if (idx < 0) {
+ gp_abilities_list_free(abilities_list);
+ kdDebug(7123) << "Unable to get abilities for model: " << user << endl;
+ error(KIO::ERR_UNKNOWN, 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(host));
+
+ /* Handle erronously passed usb:XXX,YYY */
+ if ((idx < 0) && host.startsWith("usb:"))
+ idx = gp_port_info_list_lookup_path(port_info_list, "usb:");
+ if (idx < 0) {
+ gp_port_info_list_free(port_info_list);
+ kdDebug(7123) << "Unable to get port info for path: " << host << endl;
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(idx));
+ return;
+ }
+ gp_port_info_list_get_info(port_info_list, idx, &port_info);
+ gp_port_info_list_free(port_info_list);
+
+ // create a new camera object
+ gpr = gp_camera_new(&m_camera);
+ if(gpr != GP_OK) {
+ error(KIO::ERR_UNKNOWN, 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
+ kdDebug(7123) << "Opening camera model " << user << " at " << host << endl;
+
+ QString errstr;
+ if (!openCamera(errstr)) {
+ kdDebug(7123) << "Unable to init camera: " << gp_result_as_string(gpr) << endl;
+ error(KIO::ERR_SERVICE_NOT_AVAILABLE, errstr);
+ gp_camera_exit(m_camera, m_context);
+ return;
+ }
+ }
+}
+
+void KameraProtocol::reparseConfiguration(void)
+{
+ // we have no global config, do we?
+}
+
+// translate a simple text to a UDS entry
+void KameraProtocol::translateTextToUDS(UDSEntry &udsEntry, const QString &fn,
+ const char *text
+) {
+ UDSAtom atom;
+
+ udsEntry.clear();
+
+ atom.m_uds = UDS_FILE_TYPE; // UDS type
+ atom.m_long = S_IFREG; // file
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_NAME;
+ atom.m_str = fn;
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_SIZE;
+ atom.m_long = strlen(text);
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH;
+ udsEntry.append(atom);
+}
+
+// translate a CameraFileInfo to a UDSEntry which we can return as a directory listing entry
+void KameraProtocol::translateFileToUDS(UDSEntry &udsEntry, const CameraFileInfo &info, QString name)
+{
+ UDSAtom atom;
+
+ udsEntry.clear();
+
+ atom.m_uds = UDS_FILE_TYPE; // UDS type
+ atom.m_long = S_IFREG; // file
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_NAME;
+ if (info.file.fields & GP_FILE_INFO_NAME)
+ atom.m_str = QString::fromLocal8Bit(info.file.name);
+ else
+ atom.m_str = name;
+ udsEntry.append(atom);
+
+ if (info.file.fields & GP_FILE_INFO_SIZE) {
+ atom.m_uds = UDS_SIZE;
+ atom.m_long = info.file.size;
+ udsEntry.append(atom);
+ }
+
+ if (info.file.fields & GP_FILE_INFO_MTIME) {
+ atom.m_uds = UDS_MODIFICATION_TIME;
+ atom.m_long = info.file.mtime;
+ udsEntry.append(atom);
+ } else {
+ atom.m_uds = UDS_MODIFICATION_TIME;
+ atom.m_long = time(NULL); /* NOW */
+ udsEntry.append(atom);
+ }
+
+ if (info.file.fields & GP_FILE_INFO_TYPE) {
+ atom.m_uds = UDS_MIME_TYPE;
+ atom.m_str = QString::fromLatin1(info.file.type);
+ udsEntry.append(atom);
+ }
+
+ if (info.file.fields & GP_FILE_INFO_PERMISSIONS) {
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = 0;
+ atom.m_long |= (info.file.permissions & GP_FILE_PERM_READ) ? (S_IRUSR | S_IRGRP | S_IROTH) : 0;
+ // we cannot represent individual FP_FILE_PERM_DELETE permission in the Unix access scheme
+ // since the parent directory's write permission defines that
+ udsEntry.append(atom);
+ } else {
+ // basic permissions, in case the camera doesn't provide permissions info
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH;
+ udsEntry.append(atom);
+ }
+
+ // TODO: We do not handle info.preview in any way
+}
+
+// translate a directory name to a UDSEntry which we can return as a directory listing entry
+void KameraProtocol::translateDirectoryToUDS(UDSEntry &udsEntry, const QString &dirname)
+{
+ UDSAtom atom;
+
+ udsEntry.clear();
+
+ atom.m_uds = UDS_FILE_TYPE; // UDS type
+ atom.m_long = S_IFDIR; // directory
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_NAME;
+ atom.m_str = dirname;
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_MIME_TYPE;
+ atom.m_str = "inode/directory";
+ udsEntry.append(atom);
+}
+
+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)
+{
+ kdDebug(7123) << "KameraProtocol::readCameraFolder(" << folder << ")" << endl;
+
+ 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;
+ chunkDataBuffer.setRawData(fileData + object->getFileSize(), fileSize - object->getFileSize());
+ // Note: this will fail with sizes > 16MB ...
+ object->data(chunkDataBuffer);
+ object->processedSize(fileSize);
+ chunkDataBuffer.resetRawData(fileData + object->getFileSize(), fileSize - object->getFileSize());
+ object->setFileSize(fileSize);
+ }
+}
+
+unsigned int frontendProgressStart(
+ GPContext * /*context*/, float totalsize, const char *format, va_list args,
+ void *data
+) {
+ KameraProtocol *object = (KameraProtocol*)data;
+ 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;
+ object->totalSize((int)totalsize); // hack: call slot directly
+ return GP_OK;
+}
+
+// this callback function is activated on every status message from gphoto2
+static void frontendCameraStatus(GPContext * /*context*/, const char *format, va_list args, void *data)
+{
+ KameraProtocol *object = (KameraProtocol*)data;
+ 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;
+}
diff --git a/kamera/kioslave/kamera.h b/kamera/kioslave/kamera.h
new file mode 100644
index 00000000..765f6560
--- /dev/null
+++ b/kamera/kioslave/kamera.h
@@ -0,0 +1,81 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2001-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2001-2007 Marcus Meissner <marcus@jet.franken.de>
+
+ 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 __kamera_h__
+#define __kamera_h__
+
+#include <config.h>
+#include <kio/slavebase.h>
+#include <gphoto2.h>
+
+class KSimpleConfig;
+
+class KameraProtocol : public KIO::SlaveBase
+{
+public:
+ KameraProtocol(const QCString &pool, const QCString &app);
+ virtual ~KameraProtocol();
+
+ virtual void get(const KURL &url);
+ virtual void stat(const KURL &url);
+ virtual void del(const KURL &url, bool isFile);
+ virtual void setHost(const QString& host, int port, const QString& user, const QString& pass );
+ virtual void listDir(const KURL &url);
+ virtual void special(const QByteArray &data);
+
+ CameraFile *getFile() { return m_file; }
+ int getFileSize() { return m_fileSize; }
+ void setFileSize(int newfs) { m_fileSize = newfs; }
+
+private:
+ Camera *m_camera;
+ CameraAbilities m_abilities;
+ KSimpleConfig *m_config;
+
+ GPContext *m_context;
+
+ void reparseConfiguration(void);
+ bool openCamera(QString& str);
+ bool openCamera(void ) {
+ QString errstr;
+ return openCamera(errstr);
+ }
+ void closeCamera(void);
+
+ void statRoot(void);
+ void statRegular(const KURL &url);
+ void translateTextToUDS(KIO::UDSEntry &udsEntry, const QString &info, const char *txt);
+ void translateFileToUDS(KIO::UDSEntry &udsEntry, const CameraFileInfo &info, QString name);
+ void translateDirectoryToUDS(KIO::UDSEntry &udsEntry, const QString &dirname);
+ bool cameraSupportsPreview(void);
+ bool cameraSupportsDel(void);
+ bool cameraSupportsPut(void);
+ int readCameraFolder(const QString &folder, CameraList *dirList, CameraList *fileList);
+
+ QString m_lockfile;
+ int idletime;
+
+ int m_fileSize;
+ CameraFile *m_file;
+ bool actiondone, cameraopen;
+};
+#endif
diff --git a/kamera/pics/Makefile.am b/kamera/pics/Makefile.am
new file mode 100644
index 00000000..b74ac1ca
--- /dev/null
+++ b/kamera/pics/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON = camera camera_test
diff --git a/kamera/pics/cr16-action-camera_test.png b/kamera/pics/cr16-action-camera_test.png
new file mode 100644
index 00000000..543710fb
--- /dev/null
+++ b/kamera/pics/cr16-action-camera_test.png
Binary files differ
diff --git a/kamera/pics/cr16-app-camera.png b/kamera/pics/cr16-app-camera.png
new file mode 100644
index 00000000..364167f0
--- /dev/null
+++ b/kamera/pics/cr16-app-camera.png
Binary files differ
diff --git a/kamera/pics/cr16-device-camera.png b/kamera/pics/cr16-device-camera.png
new file mode 100644
index 00000000..364167f0
--- /dev/null
+++ b/kamera/pics/cr16-device-camera.png
Binary files differ
diff --git a/kamera/pics/cr22-device-camera.png b/kamera/pics/cr22-device-camera.png
new file mode 100644
index 00000000..745affe7
--- /dev/null
+++ b/kamera/pics/cr22-device-camera.png
Binary files differ
diff --git a/kamera/pics/cr22-filesys-camera.png b/kamera/pics/cr22-filesys-camera.png
new file mode 100644
index 00000000..745affe7
--- /dev/null
+++ b/kamera/pics/cr22-filesys-camera.png
Binary files differ
diff --git a/kamera/pics/cr32-device-camera.png b/kamera/pics/cr32-device-camera.png
new file mode 100644
index 00000000..6876fa90
--- /dev/null
+++ b/kamera/pics/cr32-device-camera.png
Binary files differ
diff --git a/kamera/pics/cr32-filesys-camera.png b/kamera/pics/cr32-filesys-camera.png
new file mode 100644
index 00000000..6876fa90
--- /dev/null
+++ b/kamera/pics/cr32-filesys-camera.png
Binary files differ