diff options
Diffstat (limited to 'src/utilities/cameragui')
35 files changed, 9575 insertions, 0 deletions
diff --git a/src/utilities/cameragui/Makefile.am b/src/utilities/cameragui/Makefile.am new file mode 100644 index 00000000..83f810f4 --- /dev/null +++ b/src/utilities/cameragui/Makefile.am @@ -0,0 +1,30 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libcameragui.la + +# NOTE from Gilles (06-12-06): gpcamera.cpp must be placed on the top of source file list +# to unbreak compilation with './configure -enable-final' option. I suspect a problem with +# Gphoto2 C Ansi header. +libcameragui_la_SOURCES = gpcamera.cpp cameraui.cpp cameraiconview.cpp \ + cameraiconitem.cpp cameracontroller.cpp \ + camerafolderview.cpp camerafolderitem.cpp \ + animwidget.cpp renamecustomizer.cpp \ + dkcamera.cpp umscamera.cpp gpiteminfo.cpp \ + camerainfodialog.cpp albumselectdialog.cpp \ + camerafolderdialog.cpp freespacewidget.cpp + +libcameragui_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +libcameragui_la_LIBADD = $(top_builddir)/src/libs/imageproperties/libimagepropertiescamgui.la \ + $(LIB_GPHOTO) $(LIBJPEG) + +INCLUDES = -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/libs/jpegutils \ + -I$(top_srcdir)/src/libs/themeengine \ + -I$(top_srcdir)/src/libs/imageproperties \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + $(LIBKEXIV2_CFLAGS) \ + $(GPHOTO_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes) diff --git a/src/utilities/cameragui/albumselectdialog.cpp b/src/utilities/cameragui/albumselectdialog.cpp new file mode 100644 index 00000000..486c4711 --- /dev/null +++ b/src/utilities/cameragui/albumselectdialog.cpp @@ -0,0 +1,417 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-06-16 + * Description : a dialog to select a target album to download + * pictures from camera + * + * Copyright (C) 2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqframe.h> +#include <tqlayout.h> +#include <tqpopupmenu.h> +#include <tqcursor.h> +#include <tqdatetime.h> +#include <tqmap.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdeaction.h> +#include <kinputdialog.h> +#include <tdemessagebox.h> + +// Local includes. + +#include "ddebug.h" +#include "folderview.h" +#include "folderitem.h" +#include "album.h" +#include "albummanager.h" +#include "albumsettings.h" +#include "searchtextbar.h" +#include "albumselectdialog.h" +#include "albumselectdialog.moc" + +namespace Digikam +{ + +class AlbumSelectDialogPrivate +{ + +public: + + AlbumSelectDialogPrivate() + { + allowRootSelection = false; + folderView = 0; + searchBar = 0; + } + + bool allowRootSelection; + + TQString newAlbumString; + + TQMap<FolderItem*, PAlbum*> albumMap; + + FolderView *folderView; + + SearchTextBar *searchBar; +}; + +AlbumSelectDialog::AlbumSelectDialog(TQWidget* parent, PAlbum* albumToSelect, + const TQString& header, + const TQString& newAlbumString, + bool allowRootSelection ) + : KDialogBase(Plain, i18n("Select Album"), + Help|User1|Ok|Cancel, Ok, + parent, 0, true, true, + i18n("&New Album")) +{ + d = new AlbumSelectDialogPrivate; + setHelp("targetalbumdialog.anchor", "digikam"); + enableButtonOK(false); + + d->allowRootSelection = allowRootSelection; + d->newAlbumString = newAlbumString; + + // ------------------------------------------------------------- + + TQGridLayout* grid = new TQGridLayout(plainPage(), 2, 1, 0, spacingHint()); + + TQLabel *logo = new TQLabel(plainPage()); + TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader(); + logo->setPixmap(iconLoader->loadIcon("digikam", TDEIcon::NoGroup, 128, TDEIcon::DefaultState, 0, true)); + + TQLabel *message = new TQLabel(plainPage()); + if (!header.isEmpty()) + message->setText(header); + + d->folderView = new FolderView(plainPage()); + d->folderView->addColumn(i18n("My Albums")); + d->folderView->setColumnWidthMode( 0, TQListView::Maximum ); + d->folderView->setResizeMode( TQListView::AllColumns ); + d->folderView->setRootIsDecorated(true); + + d->searchBar = new SearchTextBar(plainPage(), "AlbumSelectDialogSearchBar"); + + // ------------------------------------------------------------- + + TQPixmap icon = iconLoader->loadIcon("folder", TDEIcon::NoGroup, + AlbumSettings::instance()->getDefaultTreeIconSize(), TDEIcon::DefaultState, 0, true); + + AlbumList aList = AlbumManager::instance()->allPAlbums(); + + for (AlbumList::const_iterator it = aList.begin(); it != aList.end(); ++it) + { + PAlbum* album = (PAlbum*)(*it); + + FolderItem* viewItem = 0; + + if (album->isRoot()) + { + viewItem = new FolderItem(d->folderView, album->title()); + viewItem->setOpen(true); + } + else + { + FolderItem* parentItem = (FolderItem*)(album->parent()->extraData(d->folderView)); + + if (!parentItem) + { + DWarning() << "Failed to find parent for Album " + << album->title() << endl; + continue; + } + + viewItem = new FolderItem(parentItem, album->title()); + } + + if (viewItem) + { + viewItem->setPixmap(0, icon); + album->setExtraData(d->folderView, viewItem); + d->albumMap.insert(viewItem, album); + + if (album == albumToSelect) + { + viewItem->setOpen(true); + d->folderView->setSelected(viewItem, true); + d->folderView->ensureItemVisible(viewItem); + } + } + } + + // ------------------------------------------------------------- + + grid->addMultiCellWidget(logo, 0, 0, 0, 0); + grid->addMultiCellWidget(message, 1, 1, 0, 0); + grid->addMultiCellWidget(d->folderView, 0, 2, 1, 1); + grid->addMultiCellWidget(d->searchBar, 3, 3, 1, 1); + grid->setRowStretch(2, 10); + + // ------------------------------------------------------------- + + connect(AlbumManager::instance(), TQ_SIGNAL(signalAlbumAdded(Album*)), + this, TQ_SLOT(slotAlbumAdded(Album*))); + + connect(AlbumManager::instance(), TQ_SIGNAL(signalAlbumDeleted(Album*)), + this, TQ_SLOT(slotAlbumDeleted(Album*))); + + connect(AlbumManager::instance(), TQ_SIGNAL(signalAlbumsCleared()), + this, TQ_SLOT(slotAlbumsCleared())); + + connect(d->folderView, TQ_SIGNAL(selectionChanged()), + this, TQ_SLOT(slotSelectionChanged())); + + connect(d->folderView, TQ_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)), + this, TQ_SLOT(slotContextMenu(TQListViewItem*, const TQPoint&, int))); + + connect(d->searchBar, TQ_SIGNAL(signalTextChanged(const TQString&)), + this, TQ_SLOT(slotSearchTextChanged(const TQString&))); + + // ------------------------------------------------------------- + + resize(650, 650); + slotSelectionChanged(); +} + +AlbumSelectDialog::~AlbumSelectDialog() +{ + delete d; +} + +void AlbumSelectDialog::slotAlbumAdded(Album* album) +{ + if (!album || album->type() != Album::PHYSICAL) + return; + + FolderItem* parentItem = (FolderItem*)(album->parent()->extraData(d->folderView)); + + if (!parentItem) + { + DWarning() << "Failed to find parent for Album " + << album->title() << endl; + return; + } + + TDEIconLoader *iconLoader = TDEApplication::kApplication()->iconLoader(); + TQPixmap icon = iconLoader->loadIcon("folder", TDEIcon::NoGroup, + AlbumSettings::instance()->getDefaultTreeIconSize(), + TDEIcon::DefaultState, 0, true); + + FolderItem* viewItem = new FolderItem(parentItem, album->title()); + viewItem->setPixmap(0, icon); + album->setExtraData(d->folderView, viewItem); + d->albumMap.insert(viewItem, (PAlbum*)album); +} + +void AlbumSelectDialog::slotAlbumDeleted(Album* album) +{ + if (!album || album->type() != Album::PHYSICAL) + return; + + FolderItem* viewItem = (FolderItem*)(album->extraData(d->folderView)); + + if (viewItem) + { + delete viewItem; + album->removeExtraData(d->folderView); + d->albumMap.remove(viewItem); + } +} + +void AlbumSelectDialog::slotAlbumsCleared() +{ + d->folderView->clear(); +} + +void AlbumSelectDialog::slotSelectionChanged() +{ + TQListViewItem* selItem = 0; + TQListViewItemIterator it(d->folderView); + + while (it.current()) + { + if (it.current()->isSelected()) + { + selItem = it.current(); + break; + } + ++it; + } + + if (!selItem || (selItem == d->folderView->firstChild()) && + !d->allowRootSelection) + { + enableButtonOK(false); + return; + } + + enableButtonOK(true); +} + +void AlbumSelectDialog::slotContextMenu(TQListViewItem *, const TQPoint &, int) +{ + TQPopupMenu popmenu(d->folderView); + TDEAction *action = new TDEAction(i18n( "Create New Album" ), + "albumfolder-new", 0, this, + TQ_SLOT( slotUser1() ), + &popmenu); + action->plug(&popmenu); + popmenu.exec(TQCursor::pos()); +} + +void AlbumSelectDialog::slotUser1() +{ + TQListViewItem* item = d->folderView->currentItem(); + if (!item) + item = d->folderView->firstChild(); + + if (!item) + return; + + PAlbum* album = d->albumMap[(FolderItem*)item]; + if (!album) + return; + + bool ok; + TQString newAlbumName = KInputDialog::getText(i18n("New Album Name"), + i18n("Creating new album in '%1'\n" + "Enter album name:") + .arg(album->prettyURL()), + d->newAlbumString, &ok, this); + if (!ok) + return; + + TQString errMsg; + PAlbum* newAlbum = AlbumManager::instance()->createPAlbum(album, newAlbumName, + TQString(), TQDate::currentDate(), + TQString(), errMsg); + if (!newAlbum) + { + KMessageBox::error(this, errMsg); + return; + } + + FolderItem* newItem = (FolderItem*)newAlbum->extraData(d->folderView); + if (newItem) + { + d->folderView->ensureItemVisible(newItem); + d->folderView->setSelected(newItem, true); + } +} + +PAlbum* AlbumSelectDialog::selectAlbum(TQWidget* parent, + PAlbum* albumToSelect, + const TQString& header, + const TQString& newAlbumString, + bool allowRootSelection ) +{ + AlbumSelectDialog dlg(parent, albumToSelect, + header, newAlbumString, + allowRootSelection); + + if (dlg.exec() != KDialogBase::Accepted) + return 0; + + FolderItem* item = (FolderItem*) dlg.d->folderView->currentItem(); + if (!item || (item == dlg.d->folderView->firstChild()) && + !allowRootSelection) + { + return 0; + } + + return dlg.d->albumMap[item]; +} + +void AlbumSelectDialog::slotSearchTextChanged(const TQString& filter) +{ + TQString search = filter.lower(); + + bool atleastOneMatch = false; + + AlbumList pList = AlbumManager::instance()->allPAlbums(); + for (AlbumList::iterator it = pList.begin(); it != pList.end(); ++it) + { + PAlbum* palbum = (PAlbum*)(*it); + + // don't touch the root Album + if (palbum->isRoot()) + continue; + + bool match = palbum->title().lower().contains(search); + if (!match) + { + // check if any of the parents match the search + Album* parent = palbum->parent(); + while (parent && !parent->isRoot()) + { + if (parent->title().lower().contains(search)) + { + match = true; + break; + } + + parent = parent->parent(); + } + } + + if (!match) + { + // check if any of the children match the search + AlbumIterator it(palbum); + while (it.current()) + { + if ((*it)->title().lower().contains(search)) + { + match = true; + break; + } + ++it; + } + } + + FolderItem* viewItem = (FolderItem*) palbum->extraData(d->folderView); + + if (match) + { + atleastOneMatch = true; + + if (viewItem) + viewItem->setVisible(true); + } + else + { + if (viewItem) + { + viewItem->setVisible(false); + } + } + } + + d->searchBar->slotSearchResult(atleastOneMatch); +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/albumselectdialog.h b/src/utilities/cameragui/albumselectdialog.h new file mode 100644 index 00000000..aea53319 --- /dev/null +++ b/src/utilities/cameragui/albumselectdialog.h @@ -0,0 +1,80 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-06-16 + * Description : a dialog to select a target album to download + * pictures from camera + * + * Copyright (C) 2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef ALBUMSELECTDIALOG_H +#define ALBUMSELECTDIALOG_H + +// TQt includes. + +#include <tqstring.h> + +// KDE includes. + +#include <kdialogbase.h> + +namespace Digikam +{ + +class PAlbum; +class AlbumSelectDialogPrivate; + +class AlbumSelectDialog : public KDialogBase +{ + TQ_OBJECT + + +public: + + AlbumSelectDialog(TQWidget* parent, PAlbum* albumToSelect, + const TQString& header=TQString(), + const TQString& newAlbumString=TQString(), + bool allowRootSelection=false); + ~AlbumSelectDialog(); + + + static PAlbum* selectAlbum(TQWidget* parent, + PAlbum* albumToSelect, + const TQString& header=TQString(), + const TQString& newAlbumString=TQString(), + bool allowRootSelection=false); + +private slots: + + void slotAlbumAdded(Album*); + void slotAlbumDeleted(Album*); + void slotAlbumsCleared(); + void slotSelectionChanged(); + void slotContextMenu(TQListViewItem *item, const TQPoint&, int); + void slotUser1(); + void slotSearchTextChanged(const TQString&); + +private: + + AlbumSelectDialogPrivate *d; +}; + +} // namespace Digikam + +#endif /* ALBUMSELECTDIALOG_H */ diff --git a/src/utilities/cameragui/animwidget.cpp b/src/utilities/cameragui/animwidget.cpp new file mode 100644 index 00000000..1d869cd9 --- /dev/null +++ b/src/utilities/cameragui/animwidget.cpp @@ -0,0 +1,131 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-21 + * Description : an animated busy widget + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqpalette.h> +#include <tqcolor.h> +#include <tqtimer.h> + +// Local includes. + +#include "animwidget.h" +#include "animwidget.moc" + +namespace Digikam +{ + +class AnimWidgetPriv +{ +public: + + AnimWidgetPriv() + { + timer = 0; + pos = 0; + } + + int pos; + int size; + + TQTimer *timer; + + TQPixmap pix; +}; + +AnimWidget::AnimWidget(TQWidget* parent, int size) + : TQWidget(parent, 0, WResizeNoErase|WRepaintNoErase) +{ + d = new AnimWidgetPriv; + setBackgroundMode(TQt::NoBackground); + + d->size = size; + d->pix = TQPixmap(d->size, d->size); + setFixedSize(d->size, d->size); + + d->timer = new TQTimer(this); + + connect(d->timer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotTimeout())); +} + +AnimWidget::~AnimWidget() +{ + delete d; +} + +void AnimWidget::start() +{ + d->pos = 0; + d->timer->start(100); +} + +void AnimWidget::stop() +{ + d->pos = 0; + d->timer->stop(); + repaint(); +} + +void AnimWidget::paintEvent(TQPaintEvent*) +{ + d->pix.fill(colorGroup().background()); + TQPainter p(&d->pix); + + p.translate(d->size/2, d->size/2); + + if (d->timer->isActive()) + { + p.setPen(TQPen(colorGroup().text())); + p.rotate( d->pos ); + } + else + { + p.setPen(TQPen(colorGroup().dark())); + } + + for ( int i=0 ; i<12 ; i++ ) + { + p.drawLine(d->size/2-4, 0, d->size/2-2, 0); + p.rotate(30); + } + + p.end(); + bitBlt(this, 0, 0, &d->pix); +} + +void AnimWidget::slotTimeout() +{ + d->pos = (d->pos + 10) % 360; + repaint(); +} + +bool AnimWidget::running() const +{ + return d->timer->isActive(); +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/animwidget.h b/src/utilities/cameragui/animwidget.h new file mode 100644 index 00000000..6a93f410 --- /dev/null +++ b/src/utilities/cameragui/animwidget.h @@ -0,0 +1,66 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-21 + * Description : an animated busy widget + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef ANIMWIDGET_H +#define ANIMWIDGET_H + +// TQt includes. + +#include <tqwidget.h> + +namespace Digikam +{ + +class AnimWidgetPriv; + +class AnimWidget : public TQWidget +{ + TQ_OBJECT + + +public: + + AnimWidget(TQWidget* parent, int size=28); + ~AnimWidget(); + + void start(); + void stop(); + bool running() const; + +protected: + + void paintEvent(TQPaintEvent*); + +private slots: + + void slotTimeout(); + +private: + + AnimWidgetPriv* d; +}; + +} // namespace Digikam + +#endif /* ANIMWIDGET_H */ diff --git a/src/utilities/cameragui/cameracontroller.cpp b/src/utilities/cameragui/cameracontroller.cpp new file mode 100644 index 00000000..34afa8ab --- /dev/null +++ b/src/utilities/cameragui/cameracontroller.cpp @@ -0,0 +1,1227 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-17 + * Description : digital camera controller + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +extern "C" +{ +#include <unistd.h> +} + +// C++ includes. + +#include <typeinfo> +#include <cstdio> + +// TQt includes. + +#include <tqthread.h> +#include <tqmutex.h> +#include <tqwaitcondition.h> +#include <tqevent.h> +#include <tqapplication.h> +#include <tqdeepcopy.h> +#include <tqvariant.h> +#include <tqimage.h> +#include <tqdatastream.h> +#include <tqfile.h> +#include <tqtimer.h> +#include <tqregexp.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kurl.h> +#include <tdemessagebox.h> +#include <tdeio/renamedlg.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "ddebug.h" +#include "thumbnailsize.h" +#include "imagewindow.h" +#include "gpcamera.h" +#include "umscamera.h" +#include "dmetadata.h" +#include "jpegutils.h" +#include "mtqueue.h" +#include "cameracontroller.h" +#include "cameracontroller.moc" + +namespace Digikam +{ + +class CameraThread; + +class CameraCommand +{ +public: + + enum Action + { + gp_none = 0, + gp_connect, + gp_cancel, + gp_cameraInformations, + gp_listfolders, + gp_listfiles, + gp_download, + gp_upload, + gp_delete, + gp_lock, + gp_thumbnail, + gp_exif, + gp_open + }; + + Action action; + TQStringVariantMap map; +}; + +class CameraEvent : public TQCustomEvent +{ +public: + + enum State + { + gp_connected = 0, + gp_busy, + gp_listedfolders, + gp_listedfiles, + gp_downloadstarted, + gp_downloaded, + gp_downloadFailed, + gp_opened, + gp_uploaded, + gp_uploadFailed, + gp_deleted, + gp_deleteFailed, + gp_locked, + gp_lockFailed, + gp_thumbnailed, + gp_exif, + gp_cameraInformations, + gp_infomsg, + gp_errormsg + }; + + CameraEvent(State state) : + TQCustomEvent(TQEvent::User+state) + {} + + bool result; + TQString msg; + TQStringVariantMap map; +}; + +class CameraControllerPriv +{ +public: + + CameraControllerPriv() + { + close = false; + overwriteAll = false; + skipAll = false; + canceled = false; + downloadTotal = 0; + parent = 0; + timer = 0; + camera = 0; + thread = 0; + } + + bool close; + bool overwriteAll; + bool skipAll; + bool canceled; + + int downloadTotal; + + TQWidget *parent; + + TQTimer *timer; + + CameraThread *thread; + + DKCamera *camera; + + MTQueue<CameraCommand> cmdQueue; +}; + +class CameraThread : public TQThread +{ +public: + + CameraThread(CameraController* controller); + ~CameraThread(); + + void sendBusy(bool busy); + void sendError(const TQString& msg); + void sendInfo(const TQString& msg); + +protected: + + void run(); + +private: + + CameraControllerPriv *d; + + TQObject *parent; +}; + +CameraThread::CameraThread(CameraController* controller) + : d(controller->d), parent(controller) +{ +} + +CameraThread::~CameraThread() +{ +} + +void CameraThread::run() +{ + if (d->close) + return; + + sendBusy(true); + + CameraCommand* cmd = d->cmdQueue.dequeue(); + if (cmd) + { + switch (cmd->action) + { + case(CameraCommand::gp_connect): + { + sendInfo(i18n("Connecting to camera...")); + + bool result = d->camera->doConnect(); + + CameraEvent* event = new CameraEvent(CameraEvent::gp_connected); + event->result = result; + TQApplication::postEvent(parent, event); + + if (result) + sendInfo(i18n("Connection established")); + else + sendInfo(i18n("Connection failed")); + + break; + } + case(CameraCommand::gp_cameraInformations): + { + sendInfo(i18n("Getting camera information...")); + + TQString summary, manual, about; + + d->camera->cameraSummary(summary); + d->camera->cameraManual(manual); + d->camera->cameraAbout(about); + + CameraEvent* event = new CameraEvent(CameraEvent::gp_cameraInformations); + event->map.insert("summary", TQVariant(summary)); + event->map.insert("manual", TQVariant(manual)); + event->map.insert("about", TQVariant(about)); + TQApplication::postEvent(parent, event); + break; + } + case(CameraCommand::gp_listfolders): + { + sendInfo(i18n("Listing folders...")); + + TQStringList folderList; + folderList.append(d->camera->path()); + d->camera->getAllFolders(d->camera->path(), folderList); + + /* TODO: ugly hack since qt <= 3.1.2 does not define + TQStringList with TQDeepCopy as a friend. */ + TQValueList<TQString> flist(folderList); + + CameraEvent* event = new CameraEvent(CameraEvent::gp_listedfolders); + event->map.insert("folders", TQVariant(flist)); + TQApplication::postEvent(parent, event); + + sendInfo(i18n("The folders have been listed.")); + + break; + } + case(CameraCommand::gp_listfiles): + { + TQString folder = cmd->map["folder"].asString(); + + sendInfo(i18n("The files in %1 have been listed.").arg(folder)); + + GPItemInfoList itemsList; + // setting getImageDimensions to false is a huge speedup for UMSCamera + if (!d->camera->getItemsInfoList(folder, itemsList, false)) + { + sendError(i18n("Failed to list files in %1").arg(folder)); + } + + if (!itemsList.isEmpty()) + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_listedfiles); + event->map.insert("folder", TQVariant(folder)); + + TQByteArray ba; + TQDataStream ds(ba, IO_WriteOnly); + ds << itemsList; + + event->map.insert("files", TQVariant(ba)); + TQApplication::postEvent(parent, event); + } + + sendInfo(i18n("Listing files in %1 is complete").arg(folder)); + + break; + } + case(CameraCommand::gp_thumbnail): + { + TQString folder = cmd->map["folder"].asString(); + TQString file = cmd->map["file"].asString(); + + sendInfo(i18n("Getting thumbnails...")); + + TQImage thumbnail; + d->camera->getThumbnail(folder, file, thumbnail); + + if (!thumbnail.isNull()) + { + thumbnail = thumbnail.smoothScale(ThumbnailSize::Huge, ThumbnailSize::Huge, TQImage::ScaleMin); + + CameraEvent* event = new CameraEvent(CameraEvent::gp_thumbnailed); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + event->map.insert("thumbnail", TQVariant(thumbnail)); + TQApplication::postEvent(parent, event); + } + + break; + } + case(CameraCommand::gp_exif): + { + TQString folder = cmd->map["folder"].asString(); + TQString file = cmd->map["file"].asString(); + + sendInfo(i18n("Getting EXIF information for %1/%2...").arg(folder).arg(file)); + + char* edata = 0; + int esize = 0; + d->camera->getExif(folder, file, &edata, esize); + + if (edata || esize) + { + TQByteArray ba; + TQDataStream ds(ba, IO_WriteOnly); + ds.writeRawBytes(edata, esize); + delete [] edata; + + CameraEvent* event = new CameraEvent(CameraEvent::gp_exif); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + event->map.insert("exifSize", TQVariant(esize)); + event->map.insert("exifData", TQVariant(ba)); + TQApplication::postEvent(parent, event); + } + break; + } + case(CameraCommand::gp_download): + { + TQString folder = cmd->map["folder"].asString(); + TQString file = cmd->map["file"].asString(); + TQString dest = cmd->map["dest"].asString(); + bool autoRotate = cmd->map["autoRotate"].asBool(); + bool fixDateTime = cmd->map["fixDateTime"].asBool(); + TQDateTime newDateTime = cmd->map["newDateTime"].asDateTime(); + bool setPhotographerId = cmd->map["setPhotographerId"].asBool(); + TQString author = cmd->map["author"].asString(); + TQString authorTitle = cmd->map["authorTitle"].asString(); + bool setCredits = cmd->map["setCredits"].asBool(); + TQString credit = cmd->map["credit"].asString(); + TQString source = cmd->map["source"].asString(); + TQString copyright = cmd->map["copyright"].asString(); + bool convertJpeg = cmd->map["convertJpeg"].asBool(); + TQString losslessFormat = cmd->map["losslessFormat"].asString(); + sendInfo(i18n("Downloading file %1...").arg(file)); + + // download to a temp file + + CameraEvent* event = new CameraEvent(CameraEvent::gp_downloadstarted); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + event->map.insert("dest", TQVariant(dest)); + TQApplication::postEvent(parent, event); + + KURL tempURL(dest); + tempURL = tempURL.upURL(); + tempURL.addPath( TQString(".digikam-camera-tmp1-%1").arg(getpid()).append(file)); + DDebug() << "Downloading: " << file << " using (" << tempURL.path() << ")" << endl; + TQString temp = tempURL.path(); + + bool result = d->camera->downloadItem(folder, file, tempURL.path()); + + if (result && isJpegImage(tempURL.path())) + { + if (autoRotate) + { + DDebug() << "Exif autorotate: " << file << " using (" << tempURL.path() << ")" << endl; + sendInfo(i18n("EXIF rotating file %1...").arg(file)); + exifRotate(tempURL.path(), file); + } + + if (fixDateTime || setPhotographerId || setCredits) + { + DDebug() << "Set Metadata from: " << file << " using (" << tempURL.path() << ")" << endl; + sendInfo(i18n("Setting Metadata tags to file %1...").arg(file)); + DMetadata metadata(tempURL.path()); + + if (fixDateTime) + metadata.setImageDateTime(newDateTime, true); + + if (setPhotographerId) + metadata.setImagePhotographerId(author, authorTitle); + + if (setCredits) + metadata.setImageCredits(credit, source, copyright); + + metadata.applyChanges(); + } + + // Convert Jpeg file to lossless format if necessary, + // and move converted image to destination. + + if (convertJpeg) + { + DDebug() << "Convert to LossLess: " << file << " using (" << tempURL.path() << ")" << endl; + sendInfo(i18n("Converting %1 to lossless file format...").arg(file)); + + KURL tempURL2(dest); + tempURL2 = tempURL2.upURL(); + tempURL2.addPath( TQString(".digikam-camera-tmp2-%1").arg(getpid()).append(file)); + temp = tempURL2.path(); + + if (!jpegConvert(tempURL.path(), tempURL2.path(), file, losslessFormat)) + { + // convert failed. delete the temp file + unlink(TQFile::encodeName(tempURL.path())); + unlink(TQFile::encodeName(tempURL2.path())); + result = false; + } + else + { + // Else remove only the first temp file. + unlink(TQFile::encodeName(tempURL.path())); + } + } + } + + if (result) + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_downloaded); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + event->map.insert("dest", TQVariant(dest)); + event->map.insert("temp", TQVariant(temp)); + TQApplication::postEvent(parent, event); + } + else + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_downloadFailed); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + event->map.insert("dest", TQVariant(dest)); + TQApplication::postEvent(parent, event); + } + break; + } + case(CameraCommand::gp_open): + { + TQString folder = cmd->map["folder"].asString(); + TQString file = cmd->map["file"].asString(); + TQString dest = cmd->map["dest"].asString(); + + sendInfo(i18n("Retrieving file %1 from camera...").arg(file)); + + bool result = d->camera->downloadItem(folder, file, dest); + + if (result) + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_opened); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + event->map.insert("dest", TQVariant(dest)); + TQApplication::postEvent(parent, event); + } + else + { + sendError(i18n("Failed to retrieve file %1 from camera").arg(file)); + } + break; + } + case(CameraCommand::gp_upload): + { + TQString folder = cmd->map["destFolder"].asString(); + + // We will using the same source file name to create the dest file + // name in camera. + TQString file = cmd->map["destFile"].asString(); + + // The source file path to download in camera. + TQString src = cmd->map["srcFilePath"].asString(); + + sendInfo(i18n("Uploading file %1 to camera...").arg(file)); + + GPItemInfo itemsInfo; + + bool result = d->camera->uploadItem(folder, file, src, itemsInfo); + + if (result) + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_uploaded); + TQByteArray ba; + TQDataStream ds(ba, IO_WriteOnly); + ds << itemsInfo; + event->map.insert("info", TQVariant(ba)); + + TQApplication::postEvent(parent, event); + } + else + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_uploadFailed); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + event->map.insert("src", TQVariant(src)); + TQApplication::postEvent(parent, event); + } + break; + } + case(CameraCommand::gp_delete): + { + TQString folder = cmd->map["folder"].asString(); + TQString file = cmd->map["file"].asString(); + + sendInfo(i18n("Deleting file %1...").arg(file)); + + bool result = d->camera->deleteItem(folder, file); + + if (result) + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_deleted); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + TQApplication::postEvent(parent, event); + } + else + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_deleteFailed); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + TQApplication::postEvent(parent, event); + } + break; + } + case(CameraCommand::gp_lock): + { + TQString folder = cmd->map["folder"].asString(); + TQString file = cmd->map["file"].asString(); + bool lock = cmd->map["lock"].asBool(); + + sendInfo(i18n("Toggle lock file %1...").arg(file)); + + bool result = d->camera->setLockItem(folder, file, lock); + + if (result) + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_locked); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + TQApplication::postEvent(parent, event); + } + else + { + CameraEvent* event = new CameraEvent(CameraEvent::gp_lockFailed); + event->map.insert("folder", TQVariant(folder)); + event->map.insert("file", TQVariant(file)); + TQApplication::postEvent(parent, event); + } + break; + } + default: + DWarning() << k_funcinfo << " unknown action specified" << endl; + } + + delete cmd; + } + + sendBusy(false); +} + +void CameraThread::sendBusy(bool val) +{ + CameraEvent* event = new CameraEvent(CameraEvent::gp_busy); + event->result = val; + TQApplication::postEvent(parent, event); +} + +void CameraThread::sendError(const TQString& msg) +{ + CameraEvent* event = new CameraEvent(CameraEvent::gp_errormsg); + event->msg = msg; + TQApplication::postEvent(parent, event); +} + +void CameraThread::sendInfo(const TQString& msg) +{ + CameraEvent* event = new CameraEvent(CameraEvent::gp_infomsg); + event->msg = msg; + TQApplication::postEvent(parent, event); +} + + +//-- Camera Controller ------------------------------------------------------ + + +CameraController::CameraController(TQWidget* parent, const TQString& title, const TQString& model, + const TQString& port, const TQString& path) + : TQObject(parent) +{ + d = new CameraControllerPriv; + d->parent = parent; + d->canceled = false; + d->close = false; + d->overwriteAll = false; + d->skipAll = false; + d->downloadTotal = 0; + d->camera = 0; + + // URL parsing (c) Stephan Kulow + if (path.startsWith("camera:/")) + { + KURL url(path); + DDebug() << "path " << path << " " << url << " " << url.host() << endl; + TQString xport = url.host(); + if (xport.startsWith("usb:")) + { + DDebug() << "xport " << xport << endl; + TQRegExp x = TQRegExp("(usb:[0-9,]*)"); + + if (x.search(xport) != -1) + { + TQString usbport = x.cap(1); + DDebug() << "USB " << xport << " " << usbport << endl; + // if ((xport == usbport) || ((count == 1) && (xport == "usb:"))) { + // model = xmodel; + d->camera = new GPCamera(title, url.user(), "usb:", "/"); + // } + } + } + } + + if (!d->camera) + { + if (model.lower() == "directory browse") + d->camera = new UMSCamera(title, model, port, path); + else + d->camera = new GPCamera(title, model, port, path); + } + + d->thread = new CameraThread(this); + d->timer = new TQTimer(this); + + connect(d->timer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotProcessNext())); + + d->timer->start(50, false); +} + +CameraController::~CameraController() +{ + if (d->timer->isActive()) + { + d->timer->stop(); + delete d->timer; + } + + d->camera->cancel(); + d->canceled = true; + d->close = true; + + while (d->thread->running()) + d->thread->wait(); + + delete d->thread; + delete d->camera; + delete d; +} + +TQString CameraController::getCameraPath() +{ + if (!d->camera) return TQString(); + return d->camera->path(); +} + +TQString CameraController::getCameraTitle() +{ + if (!d->camera) return TQString(); + return d->camera->title(); +} + +void CameraController::slotConnect() +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_connect; + d->cmdQueue.enqueue(cmd); +} + +void CameraController::listFolders() +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_listfolders; + d->cmdQueue.enqueue(cmd); +} + +void CameraController::listFiles(const TQString& folder) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_listfiles; + cmd->map.insert("folder", TQVariant(folder)); + d->cmdQueue.enqueue(cmd); +} + +void CameraController::getThumbnail(const TQString& folder, const TQString& file) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_thumbnail; + cmd->map.insert("folder", TQVariant(folder)); + cmd->map.insert("file", TQVariant(file)); + d->cmdQueue.enqueue(cmd); +} + +void CameraController::getExif(const TQString& folder, const TQString& file) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_exif; + cmd->map.insert("folder", TQVariant(folder)); + cmd->map.insert("file", TQVariant(file)); + d->cmdQueue.enqueue(cmd); +} + +void CameraController::getCameraInformations() +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_cameraInformations; + d->cmdQueue.enqueue(cmd); +} + +void CameraController::upload(const TQFileInfo& srcFileInfo, const TQString& destFile, const TQString& destFolder) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_upload; + cmd->map.insert("srcFilePath", TQVariant(srcFileInfo.filePath())); + cmd->map.insert("destFile", TQVariant(destFile)); + cmd->map.insert("destFolder", TQVariant(destFolder)); + d->cmdQueue.enqueue(cmd); + DDebug() << "Uploading '" << srcFileInfo.filePath() << "' into camera : '" << destFolder << + "' (" << destFile << ")" << endl; +} + +void CameraController::downloadPrep() +{ + d->overwriteAll = false; + d->skipAll = false; + d->downloadTotal = 0; +} + +void CameraController::download(DownloadSettingsContainer downloadSettings) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_download; + cmd->map.insert("folder", TQVariant(downloadSettings.folder)); + cmd->map.insert("file", TQVariant(downloadSettings.file)); + cmd->map.insert("dest", TQVariant(downloadSettings.dest)); + cmd->map.insert("autoRotate", TQVariant(downloadSettings.autoRotate)); + cmd->map.insert("fixDateTime", TQVariant(downloadSettings.fixDateTime)); + cmd->map.insert("newDateTime", TQVariant(downloadSettings.newDateTime)); + cmd->map.insert("setPhotographerId", TQVariant(downloadSettings.setPhotographerId)); + cmd->map.insert("author", TQVariant(downloadSettings.author)); + cmd->map.insert("authorTitle", TQVariant(downloadSettings.authorTitle)); + cmd->map.insert("setCredits", TQVariant(downloadSettings.setCredits)); + cmd->map.insert("credit", TQVariant(downloadSettings.credit)); + cmd->map.insert("source", TQVariant(downloadSettings.source)); + cmd->map.insert("copyright", TQVariant(downloadSettings.copyright)); + cmd->map.insert("convertJpeg", TQVariant(downloadSettings.convertJpeg)); + cmd->map.insert("losslessFormat", TQVariant(downloadSettings.losslessFormat)); + d->cmdQueue.enqueue(cmd); +} + +void CameraController::deleteFile(const TQString& folder, const TQString& file) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_delete; + cmd->map.insert("folder", TQVariant(folder)); + cmd->map.insert("file", TQVariant(file)); + d->cmdQueue.enqueue(cmd); +} + +void CameraController::lockFile(const TQString& folder, const TQString& file, bool lock) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_lock; + cmd->map.insert("folder", TQVariant(folder)); + cmd->map.insert("file", TQVariant(file)); + cmd->map.insert("lock", TQVariant(lock)); + d->cmdQueue.enqueue(cmd); +} + +void CameraController::openFile(const TQString& folder, const TQString& file) +{ + d->canceled = false; + CameraCommand *cmd = new CameraCommand; + cmd->action = CameraCommand::gp_open; + cmd->map.insert("folder", TQVariant(folder)); + cmd->map.insert("file", TQVariant(file)); + cmd->map.insert("dest", TQVariant(locateLocal("tmp", file))); + d->cmdQueue.enqueue(cmd); +} + +void CameraController::slotCancel() +{ + d->canceled = true; + d->cmdQueue.flush(); + d->camera->cancel(); +} + +void CameraController::customEvent(TQCustomEvent* e) +{ + CameraEvent* event = dynamic_cast<CameraEvent*>(e); + if (!event) + { + return; + } + + switch(event->type()-TQEvent::User) + { + case (CameraEvent::gp_connected) : + { + emit signalConnected(event->result); + break; + } + case (CameraEvent::gp_cameraInformations) : + { + TQString summary = TQDeepCopy<TQString>(event->map["summary"].asString()); + TQString manual = TQDeepCopy<TQString>(event->map["manual"].asString()); + TQString about = TQDeepCopy<TQString>(event->map["about"].asString()); + emit signalCameraInformations(summary, manual, about); + break; + } + case (CameraEvent::gp_errormsg) : + { + emit signalErrorMsg(TQDeepCopy<TQString>(event->msg)); + break; + } + case (CameraEvent::gp_busy) : + { + if (event->result) + emit signalBusy(true); + break; + } + case (CameraEvent::gp_infomsg) : + { + if (!d->canceled) + emit signalInfoMsg(TQDeepCopy<TQString>(event->msg)); + break; + } + case (CameraEvent::gp_listedfolders) : + { + /* TODO: ugly hack since qt <= 3.1.2 does not define + TQStringList with TQDeepCopy as a friend. */ + TQValueList<TQVariant> flist = TQDeepCopy< TQValueList<TQVariant> >(event->map["folders"].toList()); + + TQStringList folderList; + TQValueList<TQVariant>::Iterator it; + for (it = flist.begin(); it != flist.end(); ++it ) + { + folderList.append(TQDeepCopy<TQString>((*it).asString())); + } + + emit signalFolderList(folderList); + break; + } + case (CameraEvent::gp_listedfiles) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQByteArray ba = TQDeepCopy<TQByteArray>(event->map["files"].asByteArray()); + TQDataStream ds(ba, IO_ReadOnly); + GPItemInfoList items; + ds >> items; + emit signalFileList(items); + break; + } + case (CameraEvent::gp_thumbnailed) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + TQImage thumb = TQDeepCopy<TQImage>(event->map["thumbnail"].asImage()); + emit signalThumbnail(folder, file, thumb); + break; + } + case (CameraEvent::gp_exif) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + TQByteArray ba = TQDeepCopy<TQByteArray>(event->map["exifData"].asByteArray()); + emit signalExifData(ba); + break; + } + case (CameraEvent::gp_downloadstarted) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + emit signalDownloaded(folder, file, GPItemInfo::DownloadStarted); + break; + } + case (CameraEvent::gp_downloaded) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + TQString dest = TQDeepCopy<TQString>(event->map["dest"].asString()); + TQString temp = TQDeepCopy<TQString>(event->map["temp"].asString()); + + d->timer->stop(); + + bool skip = false; + bool cancel = false; + bool overwrite = false; + + // Check if dest file already exist. + + if (!d->overwriteAll) + { + TQFileInfo info(dest); + + while (info.exists()) + { + if (d->skipAll) + { + skip = true; + break; + } + + TDEIO::RenameDlg dlg(d->parent, i18n("Rename File"), + folder + TQString("/") + file, dest, + TDEIO::RenameDlg_Mode(TDEIO::M_MULTI | TDEIO::M_OVERWRITE | TDEIO::M_SKIP)); + + int result = dlg.exec(); + dest = dlg.newDestURL().path(); + info = TQFileInfo(dest); + + switch (result) + { + case TDEIO::R_CANCEL: + { + cancel = true; + break; + } + case TDEIO::R_SKIP: + { + skip = true; + break; + } + case TDEIO::R_AUTO_SKIP: + { + d->skipAll = true; + skip = true; + break; + } + case TDEIO::R_OVERWRITE: + { + overwrite = true; + break; + } + case TDEIO::R_OVERWRITE_ALL: + { + d->overwriteAll = true; + overwrite = true; + break; + } + default: + break; + } + + if (cancel || skip || overwrite) + break; + } + } + + if (cancel) + { + unlink(TQFile::encodeName(temp)); + slotCancel(); + d->timer->start(50); + emit signalSkipped(folder, file); + return; + } + else if (skip) + { + unlink(TQFile::encodeName(temp)); + d->timer->start(50); + emit signalInfoMsg(i18n("Skipped file %1").arg(file)); + emit signalSkipped(folder, file); + return; + } + + // move the file to the destination file + if (rename(TQFile::encodeName(temp), TQFile::encodeName(dest)) != 0) + { + // rename failed. delete the temp file + unlink(TQFile::encodeName(temp)); + d->timer->start(50); + emit signalDownloaded(folder, file, GPItemInfo::DownloadFailed); + } + else + { + d->timer->start(50); + emit signalDownloaded(folder, file, GPItemInfo::DownloadedYes); + } + break; + } + case (CameraEvent::gp_downloadFailed) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + + d->timer->stop(); + + TQString msg = i18n("Failed to download file \"%1\".").arg(file); + + if (!d->canceled) + { + if (d->cmdQueue.isEmpty()) + { + KMessageBox::error(d->parent, msg); + } + else + { + msg += i18n(" Do you want to continue?"); + int result = KMessageBox::warningContinueCancel(d->parent, msg); + if (result != KMessageBox::Continue) + slotCancel(); + } + } + + d->timer->start(50); + emit signalDownloaded(folder, file, GPItemInfo::DownloadFailed); + break; + } + case (CameraEvent::gp_uploaded) : + { + TQByteArray ba = TQDeepCopy<TQByteArray>(event->map["info"].asByteArray()); + TQDataStream ds(ba, IO_ReadOnly); + GPItemInfo itemInfo; + ds >> itemInfo; + + emit signalUploaded(itemInfo); + break; + } + case (CameraEvent::gp_uploadFailed) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + TQString src = TQDeepCopy<TQString>(event->map["src"].asString()); + + d->timer->stop(); + + TQString msg = i18n("Failed to upload file \"%1\".").arg(file); + + if (!d->canceled) + { + if (d->cmdQueue.isEmpty()) + { + KMessageBox::error(d->parent, msg); + } + else + { + msg += i18n(" Do you want to continue?"); + int result = KMessageBox::warningContinueCancel(d->parent, msg); + if (result != KMessageBox::Continue) + slotCancel(); + } + } + + d->timer->start(50); + break; + } + case (CameraEvent::gp_deleted) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + emit signalDeleted(folder, file, true); + break; + } + case (CameraEvent::gp_deleteFailed) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + + d->timer->stop(); + emit signalDeleted(folder, file, false); + + TQString msg = i18n("Failed to delete file \"%1\".").arg(file); + + if (!d->canceled) + { + if (d->cmdQueue.isEmpty()) + { + KMessageBox::error(d->parent, msg); + } + else + { + msg += i18n(" Do you want to continue?"); + int result = KMessageBox::warningContinueCancel(d->parent, msg); + if (result != KMessageBox::Continue) + slotCancel(); + } + } + + d->timer->start(50); + break; + } + case (CameraEvent::gp_locked) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + emit signalLocked(folder, file, true); + break; + } + case (CameraEvent::gp_lockFailed) : + { + TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString()); + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + + d->timer->stop(); + emit signalLocked(folder, file, false); + + TQString msg = i18n("Failed to toggle lock file \"%1\".").arg(file); + + if (!d->canceled) + { + if (d->cmdQueue.isEmpty()) + { + KMessageBox::error(d->parent, msg); + } + else + { + msg += i18n(" Do you want to continue?"); + int result = KMessageBox::warningContinueCancel(d->parent, msg); + if (result != KMessageBox::Continue) + slotCancel(); + } + } + + d->timer->start(50); + break; + } + case (CameraEvent::gp_opened) : + { + TQString file = TQDeepCopy<TQString>(event->map["file"].asString()); + TQString dest = TQDeepCopy<TQString>(event->map["dest"].asString()); + + KURL url(dest); + KURL::List urlList; + urlList << url; + + ImageWindow *im = ImageWindow::imagewindow(); + im->loadURL(urlList, url, i18n("Camera \"%1\"").arg(d->camera->model()), false); + + if (im->isHidden()) + im->show(); + else + im->raise(); + + im->setFocus(); + break; + } + default: + { + DWarning() << k_funcinfo << "Unknown event" << endl; + } + } +} + +void CameraController::slotProcessNext() +{ + if (d->thread->running()) + return; + + if (d->cmdQueue.isEmpty()) + { + emit signalBusy(false); + return; + } + + d->timer->stop(); + emit signalBusy(true); + + CameraCommand* cmd = d->cmdQueue.head(); + + TQString folder; + TQString file; + TQString dest; + + if ((cmd->action == CameraCommand::gp_exif) && + (typeid(*(d->camera)) == typeid(UMSCamera))) + { + folder = TQDeepCopy<TQString>(cmd->map["folder"].asString()); + file = TQDeepCopy<TQString>(cmd->map["file"].asString()); + + emit signalExifFromFile(folder, file); + + d->cmdQueue.dequeue(); + d->timer->start(50, false); + return; + } + + if (cmd->action == CameraCommand::gp_download) + { + folder = TQDeepCopy<TQString>(cmd->map["folder"].asString()); + file = TQDeepCopy<TQString>(cmd->map["file"].asString()); + dest = TQDeepCopy<TQString>(cmd->map["dest"].asString()); + cmd->map["dest"] = TQVariant(TQDeepCopy<TQString>(dest)); + } + + d->thread->start(); + d->timer->start(50, false); +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/cameracontroller.h b/src/utilities/cameragui/cameracontroller.h new file mode 100644 index 00000000..45e7fede --- /dev/null +++ b/src/utilities/cameragui/cameracontroller.h @@ -0,0 +1,111 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-17 + * Description : digital camera controller + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef CAMERACONTROLLER_H +#define CAMERACONTROLLER_H + +// TQt includes. + +#include <tqobject.h> +#include <tqstring.h> +#include <tqfileinfo.h> + +// Local includes. + +#include "downloadsettingscontainer.h" +#include "gpiteminfo.h" + +namespace Digikam +{ + +class CameraControllerPriv; + +class CameraController : public TQObject +{ + TQ_OBJECT + + +public: + + CameraController(TQWidget* parent, const TQString& title, const TQString& model, + const TQString& port, const TQString& path); + ~CameraController(); + + void listFolders(); + void listFiles(const TQString& folder); + void getThumbnail(const TQString& folder, const TQString& file); + void getExif(const TQString& folder, const TQString& file); + void getCameraInformations(); + TQString getCameraPath(); + TQString getCameraTitle(); + + void downloadPrep(); + void download(DownloadSettingsContainer downloadSettings); + void upload(const TQFileInfo& srcFileInfo, const TQString& destFile, const TQString& destFolder); + void deleteFile(const TQString& folder, const TQString& file); + void lockFile(const TQString& folder, const TQString& file, bool lock); + void openFile(const TQString& folder, const TQString& file); + +signals: + + void signalBusy(bool val); + void signalInfoMsg(const TQString& msg); + void signalErrorMsg(const TQString& msg); + void signalCameraInformations(const TQString& summary, const TQString& manual, const TQString& about); + + void signalConnected(bool val); + void signalFolderList(const TQStringList& folderList); + void signalFileList(const GPItemInfoList& infoList); + void signalUploaded(const GPItemInfo& itemInfo); + void signalDownloaded(const TQString& folder, const TQString& file, int status); + void signalSkipped(const TQString& folder, const TQString& file); + void signalDeleted(const TQString& folder, const TQString& file, bool status); + void signalLocked(const TQString& folder, const TQString& file, bool status); + void signalThumbnail(const TQString& folder, const TQString& file, const TQImage& thumb); + void signalExifFromFile(const TQString& folder, const TQString& file); + void signalExifData(const TQByteArray& exifData); + +protected: + + void customEvent(TQCustomEvent* e); + +public slots: + + void slotCancel(); + void slotConnect(); + +private slots: + + void slotProcessNext(); + +private: + + CameraControllerPriv *d; + + friend class CameraThread; +}; + +} // namespace Digikam + +#endif /* CAMERACONTROLLER_H */ diff --git a/src/utilities/cameragui/camerafolderdialog.cpp b/src/utilities/cameragui/camerafolderdialog.cpp new file mode 100644 index 00000000..93feb0ab --- /dev/null +++ b/src/utilities/cameragui/camerafolderdialog.cpp @@ -0,0 +1,138 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-07-24 + * Description : a dialog to select a camera folders. + * + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "cameraiconview.h" +#include "camerafolderitem.h" +#include "camerafolderview.h" +#include "camerafolderdialog.h" +#include "camerafolderdialog.moc" + +namespace Digikam +{ + +CameraFolderDialog::CameraFolderDialog(TQWidget *parent, CameraIconView *cameraView, + const TQStringList& cameraFolderList, + const TQString& cameraName, const TQString& rootPath) + : KDialogBase(parent, 0, true, + i18n("%1 - Select Camera Folder").arg(cameraName), + Help|Ok|Cancel, Ok, true) +{ + setHelp("camerainterface.anchor", "digikam"); + enableButtonOK(false); + + m_rootPath = rootPath; + + TQFrame *page = makeMainWidget(); + TQGridLayout* grid = new TQGridLayout(page, 2, 1, 0, spacingHint()); + + m_folderView = new CameraFolderView(page); + TQLabel *logo = new TQLabel(page); + TQLabel *message = new TQLabel(page); + + TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader(); + logo->setPixmap(iconLoader->loadIcon("digikam", TDEIcon::NoGroup, 128, TDEIcon::DefaultState, 0, true)); + message->setText(i18n("<p>Please select the camera folder " + "where you want to upload the images.</p>")); + + grid->addMultiCellWidget(logo, 0, 0, 0, 0); + grid->addMultiCellWidget(message, 1, 1, 0, 0); + grid->addMultiCellWidget(m_folderView, 0, 2, 1, 1); + grid->setRowStretch(2, 10); + + m_folderView->addVirtualFolder(cameraName); + m_folderView->addRootFolder("/", cameraView->countItemsByFolder(rootPath)); + + for (TQStringList::const_iterator it = cameraFolderList.begin(); + it != cameraFolderList.end(); ++it) + { + TQString folder(*it); + if (folder.startsWith(rootPath) && rootPath != TQString("/")) + folder.remove(0, rootPath.length()); + + if (folder != TQString("/") && !folder.isEmpty()) + { + TQString root = folder.section( '/', 0, -2 ); + if (root.isEmpty()) root = TQString("/"); + + TQString sub = folder.section( '/', -1 ); + m_folderView->addFolder(root, sub, cameraView->countItemsByFolder(*it)); + DDebug() << "Camera folder: '" << folder << "' (root='" << root << "', sub='" <<sub <<"')" << endl; + } + } + + connect(m_folderView, TQ_SIGNAL(signalFolderChanged(CameraFolderItem*)), + this, TQ_SLOT(slotFolderPathSelectionChanged(CameraFolderItem*))); + + resize(500, 500); +} + +CameraFolderDialog::~CameraFolderDialog() +{ +} + +TQString CameraFolderDialog::selectedFolderPath() +{ + TQListViewItem *item = m_folderView->currentItem(); + if (!item) return TQString(); + + CameraFolderItem *folderItem = static_cast<CameraFolderItem *>(item); + if (folderItem->isVirtualFolder()) + return TQString(m_rootPath); + + // Case of Gphoto2 cameras. No need to duplicate root '/'. + if (m_rootPath == TQString("/")) + return(folderItem->folderPath()); + + return(m_rootPath + folderItem->folderPath()); +} + +void CameraFolderDialog::slotFolderPathSelectionChanged(CameraFolderItem* item) +{ + if (item) + { + enableButtonOK(true); + DDebug() << "Camera folder path: " << selectedFolderPath() << endl; + } + else + { + enableButtonOK(false); + } +} + +} // namespace Digikam + diff --git a/src/utilities/cameragui/camerafolderdialog.h b/src/utilities/cameragui/camerafolderdialog.h new file mode 100644 index 00000000..efc7586a --- /dev/null +++ b/src/utilities/cameragui/camerafolderdialog.h @@ -0,0 +1,68 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-07-24 + * Description : a dialog to select a camera folders. + * + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef CAMERAFOLDERDIALOG_H +#define CAMERAFOLDERDIALOG_H + +// TQt includes. + +#include <tqstring.h> + +// KDE includes. + +#include <kdialogbase.h> + +namespace Digikam +{ + +class CameraIconView; +class CameraFolderView; +class CameraFolderItem; + +class CameraFolderDialog : public KDialogBase +{ + TQ_OBJECT + + +public: + + CameraFolderDialog(TQWidget *parent, CameraIconView *cameraView, const TQStringList& cameraFolderList, + const TQString& cameraName, const TQString& rootPath); + ~CameraFolderDialog(); + + TQString selectedFolderPath(); + +private slots: + + void slotFolderPathSelectionChanged(CameraFolderItem* item); + +private: + + TQString m_rootPath; + + CameraFolderView *m_folderView; +}; + +} // namespace Digikam + +#endif /* CAMERAFOLDERDIALOG_H */ diff --git a/src/utilities/cameragui/camerafolderitem.cpp b/src/utilities/cameragui/camerafolderitem.cpp new file mode 100644 index 00000000..f53508a6 --- /dev/null +++ b/src/utilities/cameragui/camerafolderitem.cpp @@ -0,0 +1,108 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-23 + * Description : A widget to display a camera folder. + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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 bythe Free Software Foundation; + * either version 2, 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. + * + * ============================================================ */ + +// Local includes. + +#include "camerafolderitem.h" + +namespace Digikam +{ + +class CameraFolderItemPriv +{ +public: + + CameraFolderItemPriv() + { + count = 0; + } + + bool virtualFolder; + + int count; + + TQString folderName; + TQString folderPath; + TQString name; +}; + +CameraFolderItem::CameraFolderItem(TQListView* parent, const TQString& name, const TQPixmap& pixmap) + : TQListViewItem(parent, name) +{ + d = new CameraFolderItemPriv; + d->virtualFolder = true; + d->name = name; + setPixmap(0, pixmap); +} + +CameraFolderItem::CameraFolderItem(TQListViewItem* parent, const TQString& folderName, + const TQString& folderPath, const TQPixmap& pixmap) + : TQListViewItem(parent, folderName) +{ + d = new CameraFolderItemPriv; + d->folderName = folderName; + d->folderPath = folderPath; + d->virtualFolder = false; + d->name = folderName; + setPixmap(0, pixmap); +} + +CameraFolderItem::~CameraFolderItem() +{ + delete d; +} + +bool CameraFolderItem::isVirtualFolder() +{ + return d->virtualFolder; +} + +TQString CameraFolderItem::folderName() +{ + return d->folderName; +} + +TQString CameraFolderItem::folderPath() +{ + return d->folderPath; +} + +void CameraFolderItem::changeCount(int val) +{ + d->count += val; + setText(0, TQString("%1 (%2)").arg(d->name).arg(TQString::number(d->count))); +} + +void CameraFolderItem::setCount(int val) +{ + d->count = val; + setText(0, TQString("%1 (%2)").arg(d->name).arg(TQString::number(d->count))); +} + +int CameraFolderItem::count() +{ + return d->count; +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/camerafolderitem.h b/src/utilities/cameragui/camerafolderitem.h new file mode 100644 index 00000000..dde2c5c6 --- /dev/null +++ b/src/utilities/cameragui/camerafolderitem.h @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-23 + * Description : A widget to display a camera folder. + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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 bythe Free Software Foundation; + * either version 2, 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. + * + * ============================================================ */ + +#ifndef CAMERAFOLDERITEM_H +#define CAMERAFOLDERITEM_H + +// TQt includes. + +#include <tqstring.h> +#include <tqlistview.h> + +// KDE includes. + +#include <kiconloader.h> + +namespace Digikam +{ + +class CameraFolderItemPriv; + +class CameraFolderItem : public TQListViewItem +{ + +public: + + CameraFolderItem(TQListView* parent, const TQString& name, + const TQPixmap& pixmap=SmallIcon("folder")); + + CameraFolderItem(TQListViewItem* parent, const TQString& folderName, const TQString& folderPath, + const TQPixmap& pixmap=SmallIcon("folder")); + + ~CameraFolderItem(); + + TQString folderName(); + TQString folderPath(); + bool isVirtualFolder(); + void changeCount(int val); + void setCount(int val); + int count(); + +private: + + CameraFolderItemPriv* d; +}; + +} // namespace Digikam + +#endif /* CAMERAFOLDERITEM_H */ diff --git a/src/utilities/cameragui/camerafolderview.cpp b/src/utilities/cameragui/camerafolderview.cpp new file mode 100644 index 00000000..877c4b51 --- /dev/null +++ b/src/utilities/cameragui/camerafolderview.cpp @@ -0,0 +1,169 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-23 + * Description : A widget to display a list of camera folders. + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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 bythe Free Software Foundation; + * either version 2, 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kiconloader.h> + +// Local includes. + +#include "ddebug.h" +#include "camerafolderitem.h" +#include "camerafolderview.h" +#include "camerafolderview.moc" + +namespace Digikam +{ + +class CameraFolderViewPriv +{ +public: + + CameraFolderViewPriv() + { + virtualFolder = 0; + rootFolder = 0; + cameraName = TQString("Camera"); + } + + TQString cameraName; + + CameraFolderItem *virtualFolder; + CameraFolderItem *rootFolder; +}; + +CameraFolderView::CameraFolderView(TQWidget* parent) + : TQListView(parent) +{ + d = new CameraFolderViewPriv; + + addColumn(i18n("Camera Folders")); + setColumnWidthMode( 0, TQListView::Maximum ); + setResizeMode( TQListView::AllColumns ); + setSelectionMode(TQListView::Single); + + connect(this, TQ_SIGNAL(currentChanged(TQListViewItem*)), + this, TQ_SLOT(slotCurrentChanged(TQListViewItem*))); + + connect(this, TQ_SIGNAL(clicked(TQListViewItem*)), + this, TQ_SLOT(slotCurrentChanged(TQListViewItem*))); +} + +CameraFolderView::~CameraFolderView() +{ + delete d; +} + +void CameraFolderView::addVirtualFolder(const TQString& name, const TQPixmap& pixmap) +{ + d->cameraName = name; + d->virtualFolder = new CameraFolderItem(this, d->cameraName, pixmap); + d->virtualFolder->setOpen(true); + d->virtualFolder->setSelected(false); + d->virtualFolder->setSelectable(false); +} + +void CameraFolderView::addRootFolder(const TQString& folder, int nbItems, const TQPixmap& pixmap) +{ + d->rootFolder = new CameraFolderItem(d->virtualFolder, folder, folder, pixmap); + d->rootFolder->setOpen(true); + d->rootFolder->setCount(nbItems); +} + +CameraFolderItem* CameraFolderView::addFolder(const TQString& folder, const TQString& subFolder, + int nbItems, const TQPixmap& pixmap) +{ + CameraFolderItem *parentItem = findFolder(folder); + + DDebug() << "CameraFolderView: Adding Subfolder " << subFolder + << " of folder " << folder << endl; + + if (parentItem) + { + TQString path(folder); + + if (!folder.endsWith("/")) + path += '/'; + + path += subFolder; + CameraFolderItem* item = new CameraFolderItem(parentItem, subFolder, path, pixmap); + + DDebug() << "CameraFolderView: Added ViewItem with path " + << item->folderPath() << endl; + + item->setCount(nbItems); + item->setOpen(true); + return item; + } + else + { + DWarning() << "CameraFolderView: Couldn't find parent for subFolder " + << subFolder << " of folder " << folder << endl; + return 0; + } +} + +CameraFolderItem* CameraFolderView::findFolder(const TQString& folderPath) +{ + + TQListViewItemIterator it(this); + for ( ; it.current(); ++it) + { + CameraFolderItem* item = static_cast<CameraFolderItem*>(it.current()); + + if (item->folderPath() == folderPath) + return item; + } + + return 0; +} + +void CameraFolderView::slotCurrentChanged(TQListViewItem* item) +{ + if (!item) + emit signalFolderChanged(0); + else + emit signalFolderChanged(static_cast<CameraFolderItem *>(item)); +} + +CameraFolderItem* CameraFolderView::virtualFolder() +{ + return d->virtualFolder; +} + +CameraFolderItem* CameraFolderView::rootFolder() +{ + return d->rootFolder; +} + +void CameraFolderView::clear() +{ + TQListView::clear(); + d->virtualFolder = 0; + d->rootFolder = 0; + emit signalCleared(); +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/camerafolderview.h b/src/utilities/cameragui/camerafolderview.h new file mode 100644 index 00000000..1b02fc9c --- /dev/null +++ b/src/utilities/cameragui/camerafolderview.h @@ -0,0 +1,83 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-23 + * Description : A widget to display a list of camera folders. + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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 bythe Free Software Foundation; + * either version 2, 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. + * + * ============================================================ */ + +#ifndef CAMERAFOLDERVIEW_H +#define CAMERAFOLDERVIEW_H + +// TQt includes. + +#include <tqstring.h> +#include <tqlistview.h> + +// KDE includes. + +#include <kiconloader.h> + +namespace Digikam +{ + +class CameraFolderItem; +class CameraFolderViewPriv; + +class CameraFolderView : public TQListView +{ + TQ_OBJECT + + +public: + + CameraFolderView(TQWidget* parent); + ~CameraFolderView(); + + void addVirtualFolder(const TQString& name, const TQPixmap& pixmap=SmallIcon("camera-photo")); + void addRootFolder(const TQString& folder, int nbItems, const TQPixmap& pixmap=SmallIcon("folder")); + + CameraFolderItem* addFolder(const TQString& folder, const TQString& subFolder, int nbItems, + const TQPixmap& pixmap=SmallIcon("folder")); + + CameraFolderItem* findFolder(const TQString& folderPath); + + CameraFolderItem* virtualFolder(); + CameraFolderItem* rootFolder(); + + virtual void clear(); + +signals: + + void signalFolderChanged(CameraFolderItem*); + void signalCleared(); + +private slots: + + void slotCurrentChanged(TQListViewItem*); + +private: + + CameraFolderViewPriv* d; + +}; + +} // namespace Digikam + +#endif /* CAMERAFOLDERVIEW_H */ diff --git a/src/utilities/cameragui/cameraiconitem.cpp b/src/utilities/cameragui/cameraiconitem.cpp new file mode 100644 index 00000000..c68f7855 --- /dev/null +++ b/src/utilities/cameragui/cameraiconitem.cpp @@ -0,0 +1,302 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-21 + * Description : camera icon view item + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqpainter.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <kiconloader.h> + +// Local includes. + +#include "iconview.h" +#include "thumbnailsize.h" +#include "albumiconitem.h" +#include "gpiteminfo.h" +#include "themeengine.h" +#include "cameraiconview.h" +#include "cameraiconitem.h" + +namespace Digikam +{ + +class CameraIconViewItemPriv +{ + +public: + + CameraIconViewItemPriv() + { + itemInfo = 0; + } + + TQString downloadName; + + TQPixmap pixmap; + TQPixmap thumbnail; + + TQRect pixRect; + TQRect textRect; + TQRect extraRect; + + GPItemInfo *itemInfo; +}; + +CameraIconViewItem::CameraIconViewItem(IconGroupItem* parent, const GPItemInfo& itemInfo, + const TQImage& thumbnail, const TQString& downloadName) + : IconItem(parent) +{ + d = new CameraIconViewItemPriv; + d->itemInfo = new GPItemInfo(itemInfo); + d->downloadName = downloadName; + setThumbnail(thumbnail); +} + +CameraIconViewItem::~CameraIconViewItem() +{ + delete d->itemInfo; + delete d; +} + +void CameraIconViewItem::setThumbnail(const TQImage& thumbnail) +{ + d->thumbnail = TQPixmap(thumbnail); +} + +GPItemInfo* CameraIconViewItem::itemInfo() const +{ + return d->itemInfo; +} + +void CameraIconViewItem::paintItem() +{ + CameraIconView* view = (CameraIconView*)iconView(); + TQFont fn(view->font()); + + TQPixmap pix; + TQRect r(rect()); + + if (isSelected()) + pix = *(view->itemBaseSelPixmap()); + else + pix = *(view->itemBaseRegPixmap()); + + ThemeEngine* te = ThemeEngine::instance(); + + TQPainter p(&pix); + + TQString itemName = AlbumIconItem::squeezedText(&p, r.width()-5, d->itemInfo->name); + TQString downloadName = AlbumIconItem::squeezedText(&p, r.width()-5, d->downloadName); + calcRect(itemName, downloadName); + + p.setPen(isSelected() ? te->textSelColor() : te->textRegColor()); + + p.drawPixmap(d->pixRect.x() + (d->pixRect.width() - d->pixmap.width()) /2, + d->pixRect.y() + (d->pixRect.height() - d->pixmap.height()) /2, + d->pixmap); + + p.drawText(d->textRect, TQt::AlignHCenter|TQt::AlignTop, itemName); + + if (!d->downloadName.isEmpty()) + { + if (fn.pointSize() > 0) + fn.setPointSize(TQMAX(fn.pointSize()-2, 6)); + + p.setFont(fn); + p.setPen(isSelected() ? te->textSpecialSelColor() : te->textSpecialRegColor()); + p.drawText(d->extraRect, TQt::AlignHCenter|TQt::AlignTop, downloadName); + } + + if (this == iconView()->currentItem()) + { + p.setPen(TQPen(isSelected() ? TQt::white : TQt::black, 1, TQt::DotLine)); + p.drawRect(0, 0, r.width(), r.height()); + } + + // Draw download status icon. + TQPixmap downloaded; + + switch (d->itemInfo->downloaded) + { + case GPItemInfo::NewPicture: + { + downloaded = TQPixmap(view->newPicturePixmap()); + break; + } + case GPItemInfo::DownloadedYes: + { + downloaded = SmallIcon( "button_ok" ); + break; + } + case GPItemInfo::DownloadStarted: + { + downloaded = SmallIcon( "system-run" ); + break; + } + case GPItemInfo::DownloadFailed: + { + downloaded = SmallIcon( "button_cancel" ); + break; + } + /* TODO: see B.K.O #107316 : disable temporally the unknow download status until + a new method to identify the already downloaded pictures from camera is + implemented. + + case GPItemInfo::DownloadUnknow: + { + downloaded = view->unknowPicturePixmap(); + break; + } + */ + } + + if (!downloaded.isNull()) + p.drawPixmap(rect().width() - downloaded.width() - 5, 5, downloaded); + + // If camera item is locked (read only), draw a "Lock" icon. + if (d->itemInfo->writePermissions == 0) + p.drawPixmap(5, 5, SmallIcon( "encrypted" )); + + p.end(); + + r = TQRect(view->contentsToViewport(TQPoint(r.x(), r.y())), + TQSize(r.width(), r.height())); + + bitBlt(view->viewport(), r.x(), r.y(), &pix); +} + +void CameraIconViewItem::setDownloadName(const TQString& downloadName) +{ + d->downloadName = downloadName; + repaint(); +} + +TQString CameraIconViewItem::getDownloadName() const +{ + return d->downloadName; +} + +void CameraIconViewItem::setDownloaded(int status) +{ + d->itemInfo->downloaded = status; + repaint(); +} + +bool CameraIconViewItem::isDownloaded() const +{ + return (d->itemInfo->downloaded == GPItemInfo::DownloadedYes); +} + +void CameraIconViewItem::toggleLock() +{ + if (d->itemInfo->writePermissions == 0) + d->itemInfo->writePermissions = 1; + else + d->itemInfo->writePermissions = 0; + + repaint(); +} + +void CameraIconViewItem::calcRect(const TQString& itemName, const TQString& downloadName) +{ + CameraIconView* view = (CameraIconView*)iconView(); + int thumbSize = view->thumbnailSize().size(); + d->pixmap = TQPixmap(d->thumbnail.convertToImage().smoothScale(thumbSize, thumbSize, TQImage::ScaleMin)); + d->pixRect = TQRect(0,0,0,0); + d->textRect = TQRect(0,0,0,0); + d->extraRect = TQRect(0,0,0,0); + TQRect itemRect = rect(); + itemRect.moveTopLeft(TQPoint(0, 0)); + + d->pixRect.setWidth(thumbSize); + d->pixRect.setHeight(thumbSize); + + TQFontMetrics fm(iconView()->font()); + TQRect r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF, + TQt::AlignHCenter | TQt::AlignTop, + itemName)); + d->textRect.setWidth(r.width()); + d->textRect.setHeight(r.height()); + + if (!d->downloadName.isEmpty()) + { + TQFont fn(iconView()->font()); + if (fn.pointSize() > 0) + { + fn.setPointSize(TQMAX(fn.pointSize()-2, 6)); + } + + fm = TQFontMetrics(fn); + r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF, + TQt::AlignHCenter | TQt::WordBreak, + downloadName)); + d->extraRect.setWidth(r.width()); + d->extraRect.setHeight(r.height()); + + d->textRect.setWidth(TQMAX(d->textRect.width(), d->extraRect.width())); + d->textRect.setHeight(d->textRect.height() + d->extraRect.height()); + } + + int w = TQMAX(d->textRect.width(), d->pixRect.width() ); + int h = d->textRect.height() + d->pixRect.height() ; + + itemRect.setWidth(w+4); + itemRect.setHeight(h+4); + + // Center the pix and text rect + d->pixRect = TQRect(2, 2, d->pixRect.width(), d->pixRect.height()); + d->textRect = TQRect((itemRect.width() - d->textRect.width())/2, + itemRect.height() - d->textRect.height(), + d->textRect.width(), d->textRect.height()); + + if (!d->extraRect.isEmpty()) + { + d->extraRect = TQRect((itemRect.width() - d->extraRect.width())/2, + itemRect.height() - d->extraRect.height(), + d->extraRect.width(), d->extraRect.height()); + } +} + +TQRect CameraIconViewItem::clickToOpenRect() +{ + TQRect r(rect()); + + if (d->pixmap.isNull()) + { + TQRect pixRect(d->pixRect); + pixRect.moveBy(r.x(), r.y()); + return pixRect; + } + + TQRect pixRect(d->pixRect.x() + (d->pixRect.width() - d->pixmap.width())/2, + d->pixRect.y() + (d->pixRect.height() - d->pixmap.height())/2, + d->pixmap.width(), d->pixmap.height()); + pixRect.moveBy(r.x(), r.y()); + return pixRect; +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/cameraiconitem.h b/src/utilities/cameragui/cameraiconitem.h new file mode 100644 index 00000000..961bc1a3 --- /dev/null +++ b/src/utilities/cameragui/cameraiconitem.h @@ -0,0 +1,81 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-21 + * Description : camera icon view item + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef CAMERAICONITEM_H +#define CAMERAICONITEM_H + +// TQt includes. + +#include <tqstring.h> +#include <tqimage.h> + +// Local includes. + +#include "iconitem.h" + +namespace Digikam +{ + +class GPItemInfo; +class CameraIconViewItemPriv; + +class CameraIconViewItem : public IconItem +{ + +public: + + CameraIconViewItem(IconGroupItem* parent, const GPItemInfo& itemInfo, + const TQImage& thumbnail, const TQString& downloadName=TQString()); + ~CameraIconViewItem(); + + void setThumbnail(const TQImage& thumbnail); + + void setDownloadName(const TQString& downloadName); + TQString getDownloadName() const; + void setDownloaded(int status); + bool isDownloaded() const; + + void toggleLock(); + + GPItemInfo* itemInfo() const; + + // reimplemented from IconItem + virtual TQRect clickToOpenRect(); + +protected: + + virtual void paintItem(); + +private: + + void calcRect(const TQString& itemName, const TQString& downloadName); + +private: + + CameraIconViewItemPriv* d; +}; + +} // namespace Digikam + +#endif /* CAMERAICONITEM_H */ diff --git a/src/utilities/cameragui/cameraiconview.cpp b/src/utilities/cameragui/cameraiconview.cpp new file mode 100644 index 00000000..ba496217 --- /dev/null +++ b/src/utilities/cameragui/cameraiconview.cpp @@ -0,0 +1,900 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-18 + * Description : camera icon view + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqfile.h> +#include <tqfileinfo.h> +#include <tqtimer.h> +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqcursor.h> +#include <tqfontmetrics.h> +#include <tqfont.h> +#include <tqdragobject.h> +#include <tqclipboard.h> + +// KDE includes. + +#include <kurldrag.h> +#include <kmimetype.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeaction.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "themeengine.h" +#include "thumbnailsize.h" +#include "gpiteminfo.h" +#include "renamecustomizer.h" +#include "icongroupitem.h" +#include "dpopupmenu.h" +#include "dragobjects.h" +#include "cameraui.h" +#include "cameraiconitem.h" +#include "cameraiconview.h" +#include "cameraiconview.moc" + +namespace Digikam +{ + +class CameraIconViewPriv +{ +public: + + CameraIconViewPriv() + { + renamer = 0; + groupItem = 0; + cameraUI = 0; + thumbSize = ThumbnailSize::Large; + pixmapNewPicture = TQPixmap(newPicture_xpm); + pixmapUnknowPicture = TQPixmap(unknowPicture_xpm); + } + + static const char *newPicture_xpm[]; + static const char *unknowPicture_xpm[]; + + TQDict<CameraIconViewItem> itemDict; + + TQRect itemRect; + + TQPixmap itemRegPixmap; + TQPixmap itemSelPixmap; + TQPixmap pixmapNewPicture; + TQPixmap pixmapUnknowPicture; + + RenameCustomizer *renamer; + + IconGroupItem *groupItem; + + ThumbnailSize thumbSize; + + CameraUI *cameraUI; +}; + +const char *CameraIconViewPriv::newPicture_xpm[] = +{ + "13 13 8 1", + " c None", + ". c #232300", + "+ c #F6F611", + "@ c #000000", + "# c #DBDA4D", + "$ c #FFFF00", + "% c #AAA538", + "& c #E8E540", + " . ", + " . .+. . ", + " @#@ .$. .#. ", + " @$@#$#@$. ", + " @$%&%$@ ", + " ..#%&&&%#.. ", + ".+$$&&&&&$$+@", + " ..#%&&&%#@@ ", + " @$%&%$@ ", + " .$@#$#@$. ", + " @#. @$@ @#. ", + " . @+@ . ", + " @ " +}; + +const char *CameraIconViewPriv::unknowPicture_xpm[] = +{ + "16 16 78 1", + " g None", + ". g #777777", + "+ g #7A7A7A", + "@ g #8C8C8C", + "# g #787878", + "$ g #707070", + "% g #878787", + "& g #C3C3C3", + "* g #EAEAEA", + "= g #E4E4E4", + "- g #E2E2E2", + "; g #E6E6E6", + "> g #CECECE", + ", g #888888", + "' g #6B6B6B", + ") g #969696", + "! g #DEDEDE", + "~ g #D8D8D8", + "{ g #FFFFFF", + "] g #F2F2F2", + "^ g #DFDFDF", + "/ g #9D9D9D", + "( g #686868", + "_ g #848484", + ": g #D0D0D0", + "< g #F1F1F1", + "[ g #F0F0F0", + "} g #EBEBEB", + "| g #FDFDFD", + "1 g #DDDDDD", + "2 g #D4D4D4", + "3 g #838383", + "4 g #ABABAB", + "5 g #C8C8C8", + "6 g #CCCCCC", + "7 g #F4F4F4", + "8 g #D6D6D6", + "9 g #E8E8E8", + "0 g #C4C4C4", + "a g #A4A4A4", + "b g #656565", + "c g #B4B4B4", + "d g #B9B9B9", + "e g #BDBDBD", + "f g #B7B7B7", + "g g #898989", + "h g #6D6D6D", + "i g #808080", + "j g #AAAAAA", + "k g #A9A9A9", + "l g #737373", + "m g #7F7F7F", + "n g #9A9A9A", + "o g #D3D3D3", + "p g #909090", + "q g #727272", + "r g #8F8F8F", + "s g #8E8E8E", + "t g #8D8D8D", + "u g #EEEEEE", + "v g #FAFAFA", + "w g #929292", + "x g #C5C5C5", + "y g #5F5F5F", + "z g #989898", + "A g #CFCFCF", + "B g #9C9C9C", + "C g #A0A0A0", + "D g #FEFEFE", + "E g #ACACAC", + "F g #5E5E5E", + "G g #868686", + "H g #AFAFAF", + "I g #C1C1C1", + "J g #818181", + "K g #7E7E7E", + "L g #7B7B7B", + "M g #636363", + " ", + " .+@@#$ ", + " .%&*=-;>,' ", + " .)!~={{]^-/( ", + " _::<{[}|{123 ", + " .456{7558{90ab ", + " +cde96df={&g,h ", + " ijjjjjk;{=@,,l ", + " mnnnnno{-pgggq ", + " #rprstuvwtttt' ", + " $tpppp6xpppp@y ", + " mnnnzA~Bnnn. ", + " 'taaCD{Eaa,F ", + " (GjHI0HjJF ", + " (K,,LM ", + " " +}; + +CameraIconView::CameraIconView(CameraUI* ui, TQWidget* parent) + : IconView(parent) +{ + d = new CameraIconViewPriv; + d->cameraUI = ui; + d->groupItem = new IconGroupItem(this); + + setHScrollBarMode(TQScrollView::AlwaysOff); + setMinimumSize(400, 300); + + setAcceptDrops(true); + viewport()->setAcceptDrops(true); + + // ---------------------------------------------------------------- + + connect(this, TQ_SIGNAL(signalSelectionChanged()), + this, TQ_SLOT(slotSelectionChanged())); + + connect(this, TQ_SIGNAL(signalNewSelection(bool)), + this, TQ_SLOT(slotUpdateDownloadNames(bool))); + + connect(this, TQ_SIGNAL(signalRightButtonClicked(IconItem*, const TQPoint&)), + this, TQ_SLOT(slotContextMenu(IconItem*, const TQPoint&))); + + connect(this, TQ_SIGNAL(signalRightButtonClicked(const TQPoint &)), + this, TQ_SLOT(slotRightButtonClicked(const TQPoint &))); + + connect(this, TQ_SIGNAL(signalDoubleClicked(IconItem*)), + this, TQ_SLOT(slotDoubleClicked(IconItem*))); + + connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), + this, TQ_SLOT(slotThemeChanged())); + + // ---------------------------------------------------------------- + + updateItemRectsPixmap(); + slotThemeChanged(); +} + +CameraIconView::~CameraIconView() +{ + clear(); + delete d; +} + +TQPixmap* CameraIconView::itemBaseRegPixmap() const +{ + return &d->itemRegPixmap; +} + +TQPixmap* CameraIconView::itemBaseSelPixmap() const +{ + return &d->itemSelPixmap; +} + +TQPixmap CameraIconView::newPicturePixmap() const +{ + return d->pixmapNewPicture; +} + +TQPixmap CameraIconView::unknowPicturePixmap() const +{ + return d->pixmapUnknowPicture; +} + +void CameraIconView::setRenameCustomizer(RenameCustomizer* renamer) +{ + d->renamer = renamer; + + connect(d->renamer, TQ_SIGNAL(signalChanged()), + this, TQ_SLOT(slotDownloadNameChanged())); +} + +void CameraIconView::addItem(const GPItemInfo& info) +{ + TQImage thumb; + // Just to have a generic image thumb from desktop with KDE < 3.5.0 + KMimeType::Ptr mime = KMimeType::mimeType(info.mime == TQString("image/x-raw") ? + TQString("image/tiff") : info.mime); + + if (mime) + { + thumb = TQImage(mime->pixmap(TDEIcon::Desktop, ThumbnailSize::Huge, TDEIcon::DefaultState) + .convertToImage()); + } + else + { + TDEIconLoader *iconLoader = TDEApplication::kApplication()->iconLoader(); + thumb = iconLoader->loadIcon("application-x-zerosize", TDEIcon::Desktop, + ThumbnailSize::Huge, TDEIcon::DefaultState, 0, true) + .convertToImage(); + } + + TQString downloadName; + + if (d->renamer) + { + if (!d->renamer->useDefault()) + { + downloadName = getTemplatedName( &info, d->itemDict.count() ); + } + else + { + downloadName = getCasedName( d->renamer->changeCase(), &info); + } + } + + CameraIconViewItem* item = new CameraIconViewItem(d->groupItem, info, thumb, downloadName); + d->itemDict.insert(info.folder+info.name, item); +} + +void CameraIconView::removeItem(const TQString& folder, const TQString& file) +{ + CameraIconViewItem* item = d->itemDict.find(folder+file); + if (!item) + return; + d->itemDict.remove(folder+file); + + setDelayedRearrangement(true); + delete item; + setDelayedRearrangement(false); +} + +CameraIconViewItem* CameraIconView::findItem(const TQString& folder, const TQString& file) +{ + return d->itemDict.find(folder+file); +} + +int CameraIconView::countItemsByFolder(TQString folder) +{ + int count = 0; + if (folder.endsWith("/")) folder.truncate(folder.length()-1); + + for (IconItem* item = firstItem(); item; item = item->nextItem()) + { + CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item); + TQString itemFolder = iconItem->itemInfo()->folder; + if (itemFolder.endsWith("/")) itemFolder.truncate(itemFolder.length()-1); + + if (folder == itemFolder) + count++; + } + + return count; +} + +void CameraIconView::setThumbnail(const TQString& folder, const TQString& filename, const TQImage& image) +{ + CameraIconViewItem* item = d->itemDict.find(folder+filename); + if (!item) + return; + + item->setThumbnail(image); + item->repaint(); +} + +void CameraIconView::ensureItemVisible(CameraIconViewItem *item) +{ + IconView::ensureItemVisible(item); +} + +void CameraIconView::ensureItemVisible(const GPItemInfo& itemInfo) +{ + ensureItemVisible(itemInfo.folder, itemInfo.name); +} + +void CameraIconView::ensureItemVisible(const TQString& folder, const TQString& file) +{ + CameraIconViewItem* item = d->itemDict.find(folder+file); + if (!item) + return; + + ensureItemVisible(item); +} + +void CameraIconView::slotDownloadNameChanged() +{ + bool hasSelection = false; + for (IconItem* item = firstItem(); item; item = item->nextItem()) + { + if (item->isSelected()) + { + hasSelection = true; + break; + } + } + + // connected to slotUpdateDownloadNames, and used externally + emit signalNewSelection(hasSelection); +} + +void CameraIconView::slotUpdateDownloadNames(bool hasSelection) +{ + bool useDefault = true; + int startIndex = 0; + + if (d->renamer) + { + useDefault = d->renamer->useDefault(); + startIndex = d->renamer->startIndex() -1; + } + + bool convertLossLessJpeg = d->cameraUI->convertLosslessJpegFiles(); + TQString losslessFormat = d->cameraUI->losslessFormat(); + + viewport()->setUpdatesEnabled(false); + + // NOTE: see B.K.O #182352: ordering of item count must be adapted sort of icon view, + // since items are ordered from the most rescent to the older one. + + if (hasSelection) + { + // Camera items selection. + + for (IconItem* item = lastItem(); item; item = item->prevItem()) + { + TQString downloadName; + CameraIconViewItem* viewItem = static_cast<CameraIconViewItem*>(item); + + if (item->isSelected()) + { + if (!useDefault) + downloadName = getTemplatedName( viewItem->itemInfo(), startIndex ); + else + downloadName = getCasedName( d->renamer->changeCase(), viewItem->itemInfo() ); + + startIndex++; + } + + if (convertLossLessJpeg && !downloadName.isEmpty()) + { + TQFileInfo fi(downloadName); + TQString ext = fi.extension(false).upper(); + if (ext == TQString("JPEG") || ext == TQString("JPG") || ext == TQString("JPE")) + { + downloadName.truncate(downloadName.length() - ext.length()); + downloadName.append(losslessFormat.lower()); + } + } + + viewItem->setDownloadName( downloadName ); + } + } + else + { + // No camera item selection. + + for (IconItem* item = lastItem(); item; item = item->prevItem()) + { + TQString downloadName; + CameraIconViewItem* viewItem = static_cast<CameraIconViewItem*>(item); + + if (!useDefault) + downloadName = getTemplatedName( viewItem->itemInfo(), startIndex ); + else + downloadName = getCasedName( d->renamer->changeCase(), viewItem->itemInfo() ); + + if (convertLossLessJpeg) + { + TQFileInfo fi(downloadName); + TQString ext = fi.extension(false).upper(); + if (ext == TQString("JPEG") || ext == TQString("JPG") || ext == TQString("JPE")) + { + downloadName.truncate(downloadName.length() - ext.length()); + downloadName.append(losslessFormat.lower()); + } + } + + viewItem->setDownloadName( downloadName ); + startIndex++; + } + } + + viewport()->setUpdatesEnabled(true); + viewport()->update(); +} + +TQString CameraIconView::defaultDownloadName(CameraIconViewItem *viewItem) +{ + RenameCustomizer::Case renamecase = RenameCustomizer::NONE; + if (d->renamer) + renamecase = d->renamer->changeCase(); + + return getCasedName( renamecase, viewItem->itemInfo() ); +} + +TQString CameraIconView::getTemplatedName(const GPItemInfo* itemInfo, int position) +{ + TQString ext = itemInfo->name; + int pos = ext.findRev('.'); + if (pos < 0) + ext = ""; + else + ext = ext.right( ext.length() - pos ); + + TQDateTime mtime; + mtime.setTime_t(itemInfo->mtime); + + return d->renamer->newName(mtime, position+1, ext); +} + +TQString CameraIconView::getCasedName(const RenameCustomizer::Case ccase, + const GPItemInfo* itemInfo) +{ + TQString dname; + + switch (ccase) + { + case(RenameCustomizer::UPPER): + { + dname = itemInfo->name.upper(); + break; + } + case(RenameCustomizer::LOWER): + { + dname = itemInfo->name.lower(); + break; + } + default: + { + dname = itemInfo->name; + break; + } + }; + + return dname; +} + +void CameraIconView::slotSelectionChanged() +{ + bool selected = false; + CameraIconViewItem* camItem = 0; + + for (IconItem* item = firstItem(); item; item = item->nextItem()) + { + if (item->isSelected()) + { + camItem = static_cast<CameraIconViewItem*>(item); + selected = true; + break; + } + } + + emit signalNewSelection(selected); + emit signalSelected(camItem, selected); + + viewport()->update(); +} + +void CameraIconView::slotContextMenu(IconItem * item, const TQPoint&) +{ + if (!item) + return; + + // don't popup context menu if the camera is busy + if (d->cameraUI->isBusy()) + return; + + CameraIconViewItem* camItem = static_cast<CameraIconViewItem*>(item); + + DPopupMenu menu(this); + menu.insertItem(SmallIcon("editimage"), i18n("&View"), 0); + menu.insertSeparator(-1); + menu.insertItem(SmallIcon("go-down"),i18n("Download"), 1); + menu.insertItem(SmallIcon("go-down"),i18n("Download && Delete"), 4); + menu.insertItem(SmallIcon("encrypted"), i18n("Toggle lock"), 3); + menu.insertSeparator(-1); + menu.insertItem(SmallIcon("edit-delete"), i18n("Delete"), 2); + + int result = menu.exec(TQCursor::pos()); + + switch (result) + { + case(0): + { + emit signalFileView(camItem); + break; + } + case(1): + { + emit signalDownload(); + break; + } + case(2): + { + emit signalDelete(); + break; + } + case(3): + { + emit signalToggleLock(); + break; + } + case(4): + { + emit signalDownloadAndDelete(); + break; + } + default: + break; + } +} + +void CameraIconView::slotDoubleClicked(IconItem* item) +{ + if (!item) + return; + + if (d->cameraUI->isBusy()) + return; + + emit signalFileView(static_cast<CameraIconViewItem*>(item)); +} + +void CameraIconView::slotSelectAll() +{ + selectAll(); +} + +void CameraIconView::slotSelectNone() +{ + clearSelection(); +} + +void CameraIconView::slotSelectInvert() +{ + invertSelection(); +} + +void CameraIconView::slotSelectNew() +{ + blockSignals(true); + clearSelection(); + + for (IconItem* item = firstItem(); item; + item = item->nextItem()) + { + CameraIconViewItem* viewItem = static_cast<CameraIconViewItem*>(item); + if (viewItem->itemInfo()->downloaded == GPItemInfo::NewPicture) + { + viewItem->setSelected(true, false); + } + } + + blockSignals(false); + emit signalSelectionChanged(); +} + +void CameraIconView::startDrag() +{ + TQStringList lst; + + for (IconItem* item = firstItem(); item; item = item->nextItem()) + { + if (!item->isSelected()) + continue; + + CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item); + TQString itemPath = iconItem->itemInfo()->folder + iconItem->itemInfo()->name; + lst.append(itemPath); + } + + TQDragObject * drag = new CameraItemListDrag(lst, d->cameraUI); + if (drag) + { + TQPixmap icon(DesktopIcon("image-x-generic", 48)); + int w = icon.width(); + int h = icon.height(); + + TQPixmap pix(w+4,h+4); + TQString text(TQString::number(lst.count())); + + TQPainter p(&pix); + p.fillRect(0, 0, w+4, h+4, TQColor(TQt::white)); + p.setPen(TQPen(TQt::black, 1)); + p.drawRect(0, 0, w+4, h+4); + p.drawPixmap(2, 2, icon); + TQRect r = p.boundingRect(2,2,w,h,TQt::AlignLeft|TQt::AlignTop,text); + r.setWidth(TQMAX(r.width(),r.height())); + r.setHeight(TQMAX(r.width(),r.height())); + p.fillRect(r, TQColor(0,80,0)); + p.setPen(TQt::white); + TQFont f(font()); + f.setBold(true); + p.setFont(f); + p.drawText(r, TQt::AlignCenter, text); + p.end(); + + drag->setPixmap(pix); + drag->drag(); + } +} + +void CameraIconView::contentsDropEvent(TQDropEvent *event) +{ + // don't popup context menu if the camera is busy + if (d->cameraUI->isBusy()) + return; + + if ( (!TQUriDrag::canDecode(event) && !CameraDragObject::canDecode(event) ) + || event->source() == this) + { + event->ignore(); + return; + } + + KURL::List srcURLs; + KURLDrag::decode(event, srcURLs); + uploadItemPopupMenu(srcURLs); +} + +void CameraIconView::slotRightButtonClicked(const TQPoint&) +{ + // don't popup context menu if the camera is busy + if (d->cameraUI->isBusy()) + return; + + TQMimeSource *data = kapp->clipboard()->data(TQClipboard::Clipboard); + if(!data || !TQUriDrag::canDecode(data)) + return; + + KURL::List srcURLs; + KURLDrag::decode(data, srcURLs); + uploadItemPopupMenu(srcURLs); +} + +void CameraIconView::uploadItemPopupMenu(const KURL::List& srcURLs) +{ + TDEPopupMenu popMenu(this); + popMenu.insertTitle(SmallIcon("digikam"), d->cameraUI->cameraTitle()); + popMenu.insertItem( SmallIcon("goto"), i18n("&Upload to camera"), 10 ); + popMenu.insertSeparator(-1); + popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") ); + + popMenu.setMouseTracking(true); + int id = popMenu.exec(TQCursor::pos()); + switch(id) + { + case 10: + { + emit signalUpload(srcURLs); + break; + } + default: + break; + } +} + +TQRect CameraIconView::itemRect() const +{ + return d->itemRect; +} + +void CameraIconView::setThumbnailSize(const ThumbnailSize& thumbSize) +{ + if ( d->thumbSize != thumbSize) + { + d->thumbSize = thumbSize; + updateItemRectsPixmap(); + triggerRearrangement(); + } +} + +ThumbnailSize CameraIconView::thumbnailSize() const +{ + return d->thumbSize; +} + +void CameraIconView::updateItemRectsPixmap() +{ + int thumbSize = d->thumbSize.size(); + + TQRect pixRect; + TQRect textRect; + TQRect extraRect; + + pixRect.setWidth(thumbSize); + pixRect.setHeight(thumbSize); + + TQFontMetrics fm(font()); + TQRect r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF, + TQt::AlignHCenter | TQt::AlignTop, + "XXXXXXXXX")); + textRect.setWidth(r.width()); + textRect.setHeight(r.height()); + + TQFont fn(font()); + if (fn.pointSize() > 0) + { + fn.setPointSize(TQMAX(fn.pointSize()-2, 6)); + } + + fm = TQFontMetrics(fn); + r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF, + TQt::AlignHCenter | TQt::AlignTop, + "XXXXXXXXX")); + extraRect.setWidth(r.width()); + extraRect.setHeight(r.height()); + + r = TQRect(); + r.setWidth(TQMAX(TQMAX(pixRect.width(), textRect.width()), extraRect.width()) + 4); + r.setHeight(pixRect.height() + textRect.height() + extraRect.height() + 4); + + d->itemRect = r; + + d->itemRegPixmap = ThemeEngine::instance()->thumbRegPixmap(d->itemRect.width(), + d->itemRect.height()); + + d->itemSelPixmap = ThemeEngine::instance()->thumbSelPixmap(d->itemRect.width(), + d->itemRect.height()); +} + +void CameraIconView::slotThemeChanged() +{ + updateItemRectsPixmap(); + viewport()->update(); +} + +int CameraIconView::itemsDownloaded() +{ + int downloaded = 0; + + for (IconItem* item = firstItem(); item; item = item->nextItem()) + { + CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item); + + if (iconItem->itemInfo()->downloaded == GPItemInfo::DownloadedYes) + downloaded++; + } + + return downloaded; +} + +void CameraIconView::itemsSelectionSizeInfo(unsigned long& fSizeKB, unsigned long& dSizeKB) +{ + long long fSize = 0; // Files size + long long dSize = 0; // Estimated space requires to download and process files. + for (IconItem* item = firstItem(); item; item = item->nextItem()) + { + if (item->isSelected()) + { + CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item); + long long size = iconItem->itemInfo()->size; + if (size < 0) // -1 if size is not provided by camera + continue; + fSize += size; + + if (iconItem->itemInfo()->mime == TQString("image/jpeg")) + { + if (d->cameraUI->convertLosslessJpegFiles()) + { + // Estimated size is aroud 5 x original size when JPEG=>PNG. + dSize += size*5; + } + else if (d->cameraUI->autoRotateJpegFiles()) + { + // We need a double size to perform rotation. + dSize += size*2; + } + else + { + // Real file size is added. + dSize += size; + } + } + else + dSize += size; + + } + } + + fSizeKB = fSize / 1024; + dSizeKB = dSize / 1024; +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/cameraiconview.h b/src/utilities/cameragui/cameraiconview.h new file mode 100644 index 00000000..f621fedf --- /dev/null +++ b/src/utilities/cameragui/cameraiconview.h @@ -0,0 +1,141 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-18 + * Description : camera icon view + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef CAMERAICONVIEW_H +#define CAMERAICONVIEW_H + +// TQt includes. + +#include <tqdict.h> +#include <tqrect.h> + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "iconview.h" +#include "renamecustomizer.h" + +class TQPixmap; + +namespace Digikam +{ + +class ThumbnailSize; +class GPItemInfo; +class RenameCustomizer; +class CameraUI; +class CameraIconViewItem; +class CameraIconViewPriv; + +class CameraIconView : public IconView +{ + TQ_OBJECT + + +public: + + CameraIconView(CameraUI* ui, TQWidget* parent); + ~CameraIconView(); + + void setRenameCustomizer(RenameCustomizer* renamer); + + void addItem(const GPItemInfo& itemInfo); + void removeItem(const TQString& folder, const TQString& file); + void setThumbnail(const TQString& folder, const TQString& filename, const TQImage& image); + + void ensureItemVisible(CameraIconViewItem *item); + void ensureItemVisible(const GPItemInfo& itemInfo); + void ensureItemVisible(const TQString& folder, const TQString& file); + + void setThumbnailSize(const ThumbnailSize& thumbSize); + ThumbnailSize thumbnailSize() const; + + CameraIconViewItem* findItem(const TQString& folder, const TQString& file); + + int countItemsByFolder(TQString folder); + int itemsDownloaded(); + + TQPixmap* itemBaseRegPixmap() const; + TQPixmap* itemBaseSelPixmap() const; + TQPixmap newPicturePixmap() const; + TQPixmap unknowPicturePixmap() const; + + virtual TQRect itemRect() const; + + TQString defaultDownloadName(CameraIconViewItem *item); + + void itemsSelectionSizeInfo(unsigned long& fSize, unsigned long& dSize); + +signals: + + void signalSelected(CameraIconViewItem*, bool); + void signalFileView(CameraIconViewItem*); + + void signalUpload(const KURL::List&); + void signalDownload(); + void signalDownloadAndDelete(); + void signalDelete(); + void signalToggleLock(); + void signalNewSelection(bool); + +public slots: + + void slotDownloadNameChanged(); + void slotSelectionChanged(); + void slotSelectAll(); + void slotSelectNone(); + void slotSelectInvert(); + void slotSelectNew(); + +private slots: + + void slotRightButtonClicked(const TQPoint& pos); + void slotContextMenu(IconItem* item, const TQPoint& pos); + void slotDoubleClicked(IconItem* item); + void slotThemeChanged(); + void slotUpdateDownloadNames(bool hasSelection); + +protected: + + void startDrag(); + void contentsDropEvent(TQDropEvent *event); + void updateItemRectsPixmap(); + +private: + + TQString getTemplatedName(const GPItemInfo* itemInfo, int position); + TQString getCasedName(const RenameCustomizer::Case ccase, const GPItemInfo* itemInfo); + void uploadItemPopupMenu(const KURL::List& srcURLs); + +private: + + CameraIconViewPriv* d; +}; + +} // namespace Digikam + +#endif /* CAMERAICONVIEW_H */ diff --git a/src/utilities/cameragui/camerainfodialog.cpp b/src/utilities/cameragui/camerainfodialog.cpp new file mode 100644 index 00000000..ba565a59 --- /dev/null +++ b/src/utilities/cameragui/camerainfodialog.cpp @@ -0,0 +1,85 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-28 + * Description : a dialog to display camera information. + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqframe.h> +#include <tqtextedit.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kiconloader.h> + +// Local includes. + +#include "camerainfodialog.h" + +namespace Digikam +{ + +CameraInfoDialog::CameraInfoDialog(TQWidget *parent, const TQString& summary, const TQString& manual, + const TQString& about) + : KDialogBase(IconList, i18n("Camera Information"), Help|Ok, Ok, parent, 0, true, true) +{ + setHelp("digitalstillcamera.anchor", "digikam"); + resize(500, 400); + + // ---------------------------------------------------------- + + TQFrame *p1 = addPage( i18n("Summary"), i18n("Camera Summary"), BarIcon("contents2", TDEIcon::SizeMedium) ); + TQVBoxLayout *p1layout = new TQVBoxLayout( p1, 0, 6 ); + + TQTextEdit *summaryView = new TQTextEdit(summary, TQString(), p1); + summaryView->setWordWrap(TQTextEdit::WidgetWidth); + summaryView->setReadOnly(true); + p1layout->addWidget(summaryView); + + // ---------------------------------------------------------- + + TQFrame *p2 = addPage( i18n("Manual"), i18n("Camera Manual"), BarIcon("contents", TDEIcon::SizeMedium) ); + TQVBoxLayout *p2layout = new TQVBoxLayout( p2, 0, 6 ); + + TQTextEdit *manualView = new TQTextEdit(manual, TQString(), p2); + manualView->setWordWrap(TQTextEdit::WidgetWidth); + manualView->setReadOnly(true); + p2layout->addWidget(manualView); + + // ---------------------------------------------------------- + + TQFrame *p3 = addPage( i18n("About"), i18n("About Driver"), BarIcon("camera-photo", TDEIcon::SizeMedium) ); + TQVBoxLayout *p3layout = new TQVBoxLayout( p3, 0, 6 ); + + TQTextEdit *aboutView = new TQTextEdit(about, TQString(), p3); + aboutView->setWordWrap(TQTextEdit::WidgetWidth); + aboutView->setReadOnly(true); + p3layout->addWidget(aboutView); +} + +CameraInfoDialog::~CameraInfoDialog() +{ +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/camerainfodialog.h b/src/utilities/cameragui/camerainfodialog.h new file mode 100644 index 00000000..7ec3120f --- /dev/null +++ b/src/utilities/cameragui/camerainfodialog.h @@ -0,0 +1,50 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-28 + * Description : a dialog to display camera information. + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef CAMERAINFODIALOG_H +#define CAMERAINFODIALOG_H + +// TQt includes. + +#include <tqstring.h> + +// KDE includes. + +#include <kdialogbase.h> + +namespace Digikam +{ + +class CameraInfoDialog : public KDialogBase +{ +public: + + CameraInfoDialog(TQWidget *parent, const TQString& summary, const TQString& manual, + const TQString& about); + ~CameraInfoDialog(); +}; + +} // namespace Digikam + +#endif /* CAMERAINFODIALOG_H */ diff --git a/src/utilities/cameragui/cameraui.cpp b/src/utilities/cameragui/cameraui.cpp new file mode 100644 index 00000000..8b531ea2 --- /dev/null +++ b/src/utilities/cameragui/cameraui.cpp @@ -0,0 +1,1734 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-16 + * Description : Camera interface dialog + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#define CAMERA_INFO_MENU_ID 255 + +// TQt includes. + +#include <tqvgroupbox.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqtoolbutton.h> +#include <tqiconview.h> +#include <tqvbox.h> +#include <tqhbox.h> +#include <tqpopupmenu.h> +#include <tqsplitter.h> +#include <tqpixmap.h> +#include <tqcombobox.h> +#include <tqtoolbox.h> +#include <tqframe.h> +#include <tqvbuttongroup.h> +#include <tqradiobutton.h> +#include <tqcheckbox.h> +#include <tqlineedit.h> +#include <tqtooltip.h> +#include <tqtimer.h> +#include <tqwhatsthis.h> +#include <tqfile.h> +#include <tqfileinfo.h> + +// KDE includes. + +#include <tdefiledialog.h> +#include <kimageio.h> +#include <tdeaboutdata.h> +#include <tdemessagebox.h> +#include <kprogress.h> +#include <tdeglobal.h> +#include <tdelocale.h> +#include <tdeconfig.h> +#include <tdeapplication.h> +#include <kiconloader.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <khelpmenu.h> +#include <kcalendarsystem.h> +#include <kurllabel.h> +#include <ksqueezedtextlabel.h> + +#if KDE_IS_VERSION(3,2,0) +#include <kinputdialog.h> +#else +#include <klineeditdlg.h> +#endif + +// LibKDcraw includes. + +#include <libkdcraw/version.h> +#include <libkdcraw/kdcraw.h> + +#if KDCRAW_VERSION < 0x000106 +#include <libkdcraw/dcrawbinary.h> +#endif + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "thumbnailsize.h" +#include "kdatetimeedit.h" +#include "sidebar.h" +#include "scanlib.h" +#include "downloadsettingscontainer.h" +#include "imagepropertiessidebarcamgui.h" +#include "albummanager.h" +#include "albumsettings.h" +#include "album.h" +#include "albumselectdialog.h" +#include "renamecustomizer.h" +#include "animwidget.h" +#include "freespacewidget.h" +#include "camerafolderdialog.h" +#include "camerainfodialog.h" +#include "cameraiconview.h" +#include "cameraiconitem.h" +#include "cameracontroller.h" +#include "cameralist.h" +#include "cameratype.h" +#include "cameraui.h" +#include "cameraui.moc" + +namespace Digikam +{ + +class CameraUIPriv +{ +public: + + enum SettingsTab + { + RENAMEFILEPAGE=0, + AUTOALBUMPAGE, + ONFLYPAGE + }; + + enum DateFormatOptions + { + IsoDateFormat=0, + TextDateFormat, + LocalDateFormat + }; + + CameraUIPriv() + { + deleteAfter = false; + busy = false; + closed = false; + helpMenu = 0; + advBox = 0; + downloadMenu = 0; + deleteMenu = 0; + imageMenu = 0; + cancelBtn = 0; + splitter = 0; + rightSidebar = 0; + fixDateTimeCheck = 0; + autoRotateCheck = 0; + autoAlbumDateCheck = 0; + autoAlbumExtCheck = 0; + status = 0; + progress = 0; + controller = 0; + view = 0; + renameCustomizer = 0; + anim = 0; + dateTimeEdit = 0; + setPhotographerId = 0; + setCredits = 0; + losslessFormat = 0; + convertJpegCheck = 0; + formatLabel = 0; + folderDateLabel = 0; + folderDateFormat = 0; + freeSpaceWidget = 0; + } + + bool deleteAfter; + bool busy; + bool closed; + + TQString cameraTitle; + + TQStringList currentlyDeleting; + TQStringList foldersToScan; + TQStringList cameraFolderList; + + TQPopupMenu *downloadMenu; + TQPopupMenu *deleteMenu; + TQPopupMenu *imageMenu; + + TQToolButton *cancelBtn; + + TQToolBox *advBox; + + TQCheckBox *autoRotateCheck; + TQCheckBox *autoAlbumDateCheck; + TQCheckBox *autoAlbumExtCheck; + TQCheckBox *fixDateTimeCheck; + TQCheckBox *setPhotographerId; + TQCheckBox *setCredits; + TQCheckBox *convertJpegCheck; + + TQLabel *formatLabel; + TQLabel *folderDateLabel; + + TQComboBox *losslessFormat; + TQComboBox *folderDateFormat; + + TQSplitter *splitter; + + TQDateTime lastAccess; + + KProgress *progress; + + KSqueezedTextLabel *status; + + KURL lastDestURL; + + KHelpMenu *helpMenu; + + KDateTimeEdit *dateTimeEdit; + + CameraController *controller; + + CameraIconView *view; + + RenameCustomizer *renameCustomizer; + + AnimWidget *anim; + + ImagePropertiesSideBarCamGui *rightSidebar; + + FreeSpaceWidget *freeSpaceWidget; +}; + +CameraUI::CameraUI(TQWidget* /*parent*/, const TQString& cameraTitle, + const TQString& model, const TQString& port, + const TQString& path, const TQDateTime lastAccess) + : KDialogBase(Plain, cameraTitle, + Help|User1|User2|User3|Close, Close, + 0, // B.K.O # 116485: no parent for this modal dialog. + 0, false, true, + i18n("D&elete"), + i18n("&Download"), + i18n("&Images")) +{ + d = new CameraUIPriv; + d->lastAccess = lastAccess; + d->cameraTitle = cameraTitle; + setHelp("camerainterface.anchor", "digikam"); + + // ------------------------------------------------------------------------- + + TQGridLayout* viewBoxLayout = new TQGridLayout(plainPage(), 2, 7); + + TQHBox* widget = new TQHBox(plainPage()); + d->splitter = new TQSplitter(widget); + d->view = new CameraIconView(this, d->splitter); + + TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); + d->view->setSizePolicy(rightSzPolicy); + + d->rightSidebar = new ImagePropertiesSideBarCamGui(widget, "CameraGui Sidebar Right", d->splitter, + Sidebar::Right, true); + d->splitter->setFrameStyle( TQFrame::NoFrame ); + d->splitter->setFrameShadow( TQFrame::Plain ); + d->splitter->setFrameShape( TQFrame::NoFrame ); + d->splitter->setOpaqueResize(false); + + // ------------------------------------------------------------------------- + + d->advBox = new TQToolBox(d->rightSidebar); + d->renameCustomizer = new RenameCustomizer(d->advBox, d->cameraTitle); + d->view->setRenameCustomizer(d->renameCustomizer); + + TQWhatsThis::add( d->advBox, i18n("<p>Set how digiKam will rename files as they are downloaded.")); + + d->advBox->insertItem(CameraUIPriv::RENAMEFILEPAGE, d->renameCustomizer, + SmallIconSet("fileimport"), i18n("File Renaming Options")); + + // -- Albums Auto-creation options ----------------------------------------- + + TQWidget* albumBox = new TQWidget(d->advBox); + TQVBoxLayout* albumVlay = new TQVBoxLayout(albumBox, marginHint(), spacingHint()); + d->autoAlbumExtCheck = new TQCheckBox(i18n("Extension-based sub-albums"), albumBox); + d->autoAlbumDateCheck = new TQCheckBox(i18n("Date-based sub-albums"), albumBox); + TQHBox *hbox1 = new TQHBox(albumBox); + d->folderDateLabel = new TQLabel(i18n("Date format:"), hbox1); + d->folderDateFormat = new TQComboBox(hbox1); + d->folderDateFormat->insertItem(i18n("ISO"), CameraUIPriv::IsoDateFormat); + d->folderDateFormat->insertItem(i18n("Full Text"), CameraUIPriv::TextDateFormat); + d->folderDateFormat->insertItem(i18n("Local Settings"), CameraUIPriv::LocalDateFormat); + albumVlay->addWidget(d->autoAlbumExtCheck); + albumVlay->addWidget(d->autoAlbumDateCheck); + albumVlay->addWidget(hbox1); + albumVlay->addStretch(); + + TQWhatsThis::add( albumBox, i18n("<p>Set how digiKam creates albums automatically when downloading.")); + TQWhatsThis::add( d->autoAlbumExtCheck, i18n("<p>Enable this option if you want to download your " + "pictures into automatically created file extension-based sub-albums of the destination " + "album. This way, you can separate JPEG and RAW files as they are downloaded from your camera.")); + TQWhatsThis::add( d->autoAlbumDateCheck, i18n("<p>Enable this option if you want to " + "download your pictures into automatically created file date-based sub-albums " + "of the destination album.")); + TQWhatsThis::add( d->folderDateFormat, i18n("<p>Select your preferred date format used to " + "create new albums. The options available are:<p>" + "<b>ISO</b>: the date format is in accordance with ISO 8601 " + "(YYYY-MM-DD). E.g.: <i>2006-08-24</i><p>" + "<b>Full Text</b>: the date format is in a user-readable string. " + "E.g.: <i>Thu Aug 24 2006</i><p>" + "<b>Local Settings</b>: the date format depending on TDE control panel settings.<p>")); + + d->advBox->insertItem(CameraUIPriv::AUTOALBUMPAGE, albumBox, SmallIconSet("folder-new"), + i18n("Auto-creation of Albums")); + + // -- On the Fly options --------------------------------------------------- + + TQWidget* onFlyBox = new TQWidget(d->advBox); + TQVBoxLayout* onFlyVlay = new TQVBoxLayout(onFlyBox, marginHint(), spacingHint()); + d->setPhotographerId = new TQCheckBox(i18n("Set default photographer identity"), onFlyBox); + d->setCredits = new TQCheckBox(i18n("Set default credit and copyright"), onFlyBox); + d->fixDateTimeCheck = new TQCheckBox(i18n("Fix internal date && time"), onFlyBox); + d->dateTimeEdit = new KDateTimeEdit(onFlyBox, "datepicker"); + d->autoRotateCheck = new TQCheckBox(i18n("Auto-rotate/flip image"), onFlyBox); + d->convertJpegCheck = new TQCheckBox(i18n("Convert to lossless file format"), onFlyBox); + TQHBox *hbox2 = new TQHBox(onFlyBox); + d->formatLabel = new TQLabel(i18n("New image format:"), hbox2); + d->losslessFormat = new TQComboBox(hbox2); + d->losslessFormat->insertItem("PNG", 0); + onFlyVlay->addWidget(d->setPhotographerId); + onFlyVlay->addWidget(d->setCredits); + onFlyVlay->addWidget(d->fixDateTimeCheck); + onFlyVlay->addWidget(d->dateTimeEdit); + onFlyVlay->addWidget(d->autoRotateCheck); + onFlyVlay->addWidget(d->convertJpegCheck); + onFlyVlay->addWidget(hbox2); + onFlyVlay->addStretch(); + + TQWhatsThis::add( onFlyBox, i18n("<p>Set here all options to fix/transform JPEG files automatically " + "as they are downloaded.")); + TQWhatsThis::add( d->autoRotateCheck, i18n("<p>Enable this option if you want images automatically " + "rotated or flipped using EXIF information provided by the camera.")); + TQWhatsThis::add( d->setPhotographerId, i18n("<p>Enable this option to store the default " + "photographer identity in the IPTC tags using digiKam's metadata settings.")); + TQWhatsThis::add( d->setCredits, i18n("<p>Enable this option to store the default credit " + "and copyright information in the IPTC tags using digiKam's metadata settings.")); + TQWhatsThis::add( d->fixDateTimeCheck, i18n("<p>Enable this option to set date and time metadata " + "tags to the right values if your camera does not set " + "these tags correctly when pictures are taken. The values will " + "be saved in the DateTimeDigitized and DateTimeCreated EXIF/IPTC fields.")); + TQWhatsThis::add( d->convertJpegCheck, i18n("<p>Enable this option to automatically convert " + "all JPEG files to a lossless image format. <b>Note:</b> Image conversion can take a " + "while on a slow computer.")); + TQWhatsThis::add( d->losslessFormat, i18n("<p>Select your preferred lossless image file format to " + "convert to. <b>Note:</b> All metadata will be preserved during the conversion.")); + + d->advBox->insertItem(CameraUIPriv::ONFLYPAGE, onFlyBox, SmallIconSet("system-run"), + i18n("On the Fly Operations (JPEG only)")); + + d->rightSidebar->appendTab(d->advBox, SmallIcon("configure"), i18n("Settings")); + d->rightSidebar->loadViewState(); + + // ------------------------------------------------------------------------- + + d->cancelBtn = new TQToolButton(plainPage()); + d->cancelBtn->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ) ); + d->cancelBtn->setPixmap( SmallIcon( "cancel" ) ); + d->cancelBtn->setEnabled(false); + + d->status = new KSqueezedTextLabel(plainPage()); + d->progress = new KProgress(plainPage()); + d->progress->setMaximumHeight( fontMetrics().height()+4 ); + d->progress->hide(); + + TQWidget *frame = new TQWidget(plainPage()); + TQHBoxLayout* layout = new TQHBoxLayout(frame); + frame->setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum)); + + KURLLabel *pixmapLogo = new KURLLabel( Digikam::webProjectUrl(), TQString(), frame ); + pixmapLogo->setMargin(0); + pixmapLogo->setScaledContents( false ); + pixmapLogo->setSizePolicy(TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum)); + TQToolTip::add(pixmapLogo, i18n("Visit digiKam project website")); + TDEGlobal::dirs()->addResourceType("logo-digikam", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("logo-digikam", "logo-digikam.png"); + pixmapLogo->setPixmap( TQPixmap( directory + "logo-digikam.png" ) ); + pixmapLogo->setFocusPolicy(TQWidget::NoFocus); + + d->anim = new AnimWidget(frame, pixmapLogo->height()-2); + + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget( pixmapLogo ); + layout->addWidget( d->anim ); + + d->freeSpaceWidget = new FreeSpaceWidget(plainPage(), 100); + + viewBoxLayout->addMultiCellWidget(widget, 0, 0, 0, 7); + viewBoxLayout->addMultiCellWidget(d->cancelBtn, 2, 2, 0, 0); + viewBoxLayout->addMultiCellWidget(d->status, 2, 2, 2, 2); + viewBoxLayout->addMultiCellWidget(d->progress, 2, 2, 3, 3); + viewBoxLayout->addMultiCellWidget(d->freeSpaceWidget, 2, 2, 5, 5); + viewBoxLayout->addMultiCellWidget(frame, 2, 2, 7, 7); + viewBoxLayout->setRowSpacing(1, spacingHint()); + viewBoxLayout->setColSpacing(1, spacingHint()); + viewBoxLayout->setColSpacing(4, spacingHint()); + viewBoxLayout->setColSpacing(6, spacingHint()); + viewBoxLayout->setColStretch( 0, 0 ); + viewBoxLayout->setColStretch( 1, 0 ); + viewBoxLayout->setColStretch( 2, 3 ); + viewBoxLayout->setColStretch( 3, 1 ); + viewBoxLayout->setColStretch( 4, 0 ); + viewBoxLayout->setColStretch( 5, 0 ); + viewBoxLayout->setColStretch( 6, 0 ); + viewBoxLayout->setColStretch( 7, 0 ); + + // ------------------------------------------------------------------------- + + d->imageMenu = new TQPopupMenu(this); + d->imageMenu->insertItem(i18n("Select &All"), d->view, TQ_SLOT(slotSelectAll()), CTRL+Key_A, 0); + d->imageMenu->insertItem(i18n("Select N&one"), d->view, TQ_SLOT(slotSelectNone()), CTRL+Key_U, 1); + d->imageMenu->insertItem(i18n("&Invert Selection"), d->view, TQ_SLOT(slotSelectInvert()), CTRL+Key_Asterisk, 2); + d->imageMenu->insertSeparator(); + d->imageMenu->insertItem(i18n("Select &New Items"), d->view, TQ_SLOT(slotSelectNew()), 0, 3); + d->imageMenu->insertSeparator(); + d->imageMenu->insertItem(i18n("Increase Thumbnail Size"), this, TQ_SLOT(slotIncreaseThumbSize()), CTRL+Key_Plus, 4); + d->imageMenu->insertItem(i18n("Decrease Thumbnail Size"), this, TQ_SLOT(slotDecreaseThumbSize()), CTRL+Key_Minus, 5); + d->imageMenu->insertSeparator(); + d->imageMenu->insertItem(i18n("Toggle Lock"), this, TQ_SLOT(slotToggleLock()), 0, 6); + actionButton(User3)->setPopup(d->imageMenu); + + // ------------------------------------------------------------------------- + + d->downloadMenu = new TQPopupMenu(this); + d->downloadMenu->insertItem(i18n("Download Selected"), + this, TQ_SLOT(slotDownloadSelected()), 0, 0); + d->downloadMenu->insertItem(i18n("Download All"), + this, TQ_SLOT(slotDownloadAll()), 0, 1); + d->downloadMenu->insertSeparator(); + d->downloadMenu->insertItem(i18n("Download/Delete Selected"), + this, TQ_SLOT(slotDownloadAndDeleteSelected()), 0, 2); + d->downloadMenu->insertItem(i18n("Download/Delete All"), + this, TQ_SLOT(slotDownloadAndDeleteAll()), 0, 3); + d->downloadMenu->insertSeparator(); + d->downloadMenu->insertItem(i18n("Upload..."), + this, TQ_SLOT(slotUpload()), 0, 4); + d->downloadMenu->setItemEnabled(0, false); + d->downloadMenu->setItemEnabled(2, false); + actionButton(User2)->setPopup(d->downloadMenu); + + // ------------------------------------------------------------------------- + + d->deleteMenu = new TQPopupMenu(this); + d->deleteMenu->insertItem(i18n("Delete Selected"), this, TQ_SLOT(slotDeleteSelected()), 0, 0); + d->deleteMenu->insertItem(i18n("Delete All"), this, TQ_SLOT(slotDeleteAll()), 0, 1); + d->deleteMenu->setItemEnabled(0, false); + actionButton(User1)->setPopup(d->deleteMenu); + + // ------------------------------------------------------------------------- + + TQPushButton *helpButton = actionButton( Help ); + d->helpMenu = new KHelpMenu(this, kapp->aboutData(), false); + d->helpMenu->menu()->insertItem(SmallIcon("camera-photo"), i18n("Camera Information"), + this, TQ_SLOT(slotInformations()), 0, CAMERA_INFO_MENU_ID, 0); + helpButton->setPopup( d->helpMenu->menu() ); + + // ------------------------------------------------------------------------- + + connect(d->autoAlbumDateCheck, TQ_SIGNAL(toggled(bool)), + d->folderDateFormat, TQ_SLOT(setEnabled(bool))); + + connect(d->autoAlbumDateCheck, TQ_SIGNAL(toggled(bool)), + d->folderDateLabel, TQ_SLOT(setEnabled(bool))); + + connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)), + d->losslessFormat, TQ_SLOT(setEnabled(bool))); + + connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)), + d->formatLabel, TQ_SLOT(setEnabled(bool))); + + connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)), + d->view, TQ_SLOT(slotDownloadNameChanged())); + + connect(d->fixDateTimeCheck, TQ_SIGNAL(toggled(bool)), + d->dateTimeEdit, TQ_SLOT(setEnabled(bool))); + + connect(pixmapLogo, TQ_SIGNAL(leftClickedURL(const TQString&)), + this, TQ_SLOT(slotProcessURL(const TQString&))); + + // ------------------------------------------------------------------------- + + connect(d->view, TQ_SIGNAL(signalSelected(CameraIconViewItem*, bool)), + this, TQ_SLOT(slotItemsSelected(CameraIconViewItem*, bool))); + + connect(d->view, TQ_SIGNAL(signalFileView(CameraIconViewItem*)), + this, TQ_SLOT(slotFileView(CameraIconViewItem*))); + + connect(d->view, TQ_SIGNAL(signalUpload(const KURL::List&)), + this, TQ_SLOT(slotUploadItems(const KURL::List&))); + + connect(d->view, TQ_SIGNAL(signalDownload()), + this, TQ_SLOT(slotDownloadSelected())); + + connect(d->view, TQ_SIGNAL(signalDownloadAndDelete()), + this, TQ_SLOT(slotDownloadAndDeleteSelected())); + + connect(d->view, TQ_SIGNAL(signalDelete()), + this, TQ_SLOT(slotDeleteSelected())); + + connect(d->view, TQ_SIGNAL(signalToggleLock()), + this, TQ_SLOT(slotToggleLock())); + + connect(d->view, TQ_SIGNAL(signalNewSelection(bool)), + this, TQ_SLOT(slotNewSelection(bool))); + + // ------------------------------------------------------------------------- + + connect(d->rightSidebar, TQ_SIGNAL(signalFirstItem()), + this, TQ_SLOT(slotFirstItem())); + + connect(d->rightSidebar, TQ_SIGNAL(signalNextItem()), + this, TQ_SLOT(slotNextItem())); + + connect(d->rightSidebar, TQ_SIGNAL(signalPrevItem()), + this, TQ_SLOT(slotPrevItem())); + + connect(d->rightSidebar, TQ_SIGNAL(signalLastItem()), + this, TQ_SLOT(slotLastItem())); + + // ------------------------------------------------------------------------- + + connect(d->cancelBtn, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCancelButton())); + + // -- Read settings & Check free space availability on album root path ----- + + readSettings(); + + // -- camera controller ---------------------------------------------------- + + d->controller = new CameraController(this, d->cameraTitle, model, port, path); + + connect(d->controller, TQ_SIGNAL(signalConnected(bool)), + this, TQ_SLOT(slotConnected(bool))); + + connect(d->controller, TQ_SIGNAL(signalInfoMsg(const TQString&)), + d->status, TQ_SLOT(setText(const TQString&))); + + connect(d->controller, TQ_SIGNAL(signalErrorMsg(const TQString&)), + this, TQ_SLOT(slotErrorMsg(const TQString&))); + + connect(d->controller, TQ_SIGNAL(signalCameraInformations(const TQString&, const TQString&, const TQString&)), + this, TQ_SLOT(slotCameraInformations(const TQString&, const TQString&, const TQString&))); + + connect(d->controller, TQ_SIGNAL(signalBusy(bool)), + this, TQ_SLOT(slotBusy(bool))); + + connect(d->controller, TQ_SIGNAL(signalFolderList(const TQStringList&)), + this, TQ_SLOT(slotFolderList(const TQStringList&))); + + connect(d->controller, TQ_SIGNAL(signalFileList(const GPItemInfoList&)), + this, TQ_SLOT(slotFileList(const GPItemInfoList&))); + + connect(d->controller, TQ_SIGNAL(signalThumbnail(const TQString&, const TQString&, const TQImage&)), + this, TQ_SLOT(slotThumbnail(const TQString&, const TQString&, const TQImage&))); + + connect(d->controller, TQ_SIGNAL(signalDownloaded(const TQString&, const TQString&, int)), + this, TQ_SLOT(slotDownloaded(const TQString&, const TQString&, int))); + + connect(d->controller, TQ_SIGNAL(signalSkipped(const TQString&, const TQString&)), + this, TQ_SLOT(slotSkipped(const TQString&, const TQString&))); + + connect(d->controller, TQ_SIGNAL(signalDeleted(const TQString&, const TQString&, bool)), + this, TQ_SLOT(slotDeleted(const TQString&, const TQString&, bool))); + + connect(d->controller, TQ_SIGNAL(signalLocked(const TQString&, const TQString&, bool)), + this, TQ_SLOT(slotLocked(const TQString&, const TQString&, bool))); + + connect(d->controller, TQ_SIGNAL(signalExifFromFile(const TQString&, const TQString&)), + this, TQ_SLOT(slotExifFromFile(const TQString&, const TQString&))); + + connect(d->controller, TQ_SIGNAL(signalExifData(const TQByteArray&)), + this, TQ_SLOT(slotExifFromData(const TQByteArray&))); + + connect(d->controller, TQ_SIGNAL(signalUploaded(const GPItemInfo&)), + this, TQ_SLOT(slotUploaded(const GPItemInfo&))); + + // ------------------------------------------------------------------------- + + d->view->setFocus(); + TQTimer::singleShot(0, d->controller, TQ_SLOT(slotConnect())); +} + +CameraUI::~CameraUI() +{ + delete d->rightSidebar; + delete d->controller; + delete d; +} + +void CameraUI::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("Camera Settings"); + d->advBox->setCurrentIndex(config->readNumEntry("Settings Tab", CameraUIPriv::RENAMEFILEPAGE)); + d->autoRotateCheck->setChecked(config->readBoolEntry("AutoRotate", true)); + d->autoAlbumDateCheck->setChecked(config->readBoolEntry("AutoAlbumDate", false)); + d->autoAlbumExtCheck->setChecked(config->readBoolEntry("AutoAlbumExt", false)); + d->fixDateTimeCheck->setChecked(config->readBoolEntry("FixDateTime", false)); + d->setPhotographerId->setChecked(config->readBoolEntry("SetPhotographerId", false)); + d->setCredits->setChecked(config->readBoolEntry("SetCredits", false)); + d->convertJpegCheck->setChecked(config->readBoolEntry("ConvertJpeg", false)); + d->losslessFormat->setCurrentItem(config->readNumEntry("LossLessFormat", 0)); // PNG by default + d->folderDateFormat->setCurrentItem(config->readNumEntry("FolderDateFormat", CameraUIPriv::IsoDateFormat)); + + d->view->setThumbnailSize(ThumbnailSize((ThumbnailSize::Size)config->readNumEntry("ThumbnailSize", + ThumbnailSize::Large))); + + if(config->hasKey("Splitter Sizes")) + d->splitter->setSizes(config->readIntListEntry("Splitter Sizes")); + + d->dateTimeEdit->setEnabled(d->fixDateTimeCheck->isChecked()); + d->losslessFormat->setEnabled(convertLosslessJpegFiles()); + d->formatLabel->setEnabled(convertLosslessJpegFiles()); + d->folderDateFormat->setEnabled(d->autoAlbumDateCheck->isChecked()); + d->folderDateLabel->setEnabled(d->autoAlbumDateCheck->isChecked()); + + resize(configDialogSize("Camera Settings")); +} + +void CameraUI::saveSettings() +{ + saveDialogSize("Camera Settings"); + + TDEConfig* config = kapp->config(); + config->setGroup("Camera Settings"); + config->writeEntry("Settings Tab", d->advBox->currentIndex()); + config->writeEntry("AutoRotate", d->autoRotateCheck->isChecked()); + config->writeEntry("AutoAlbumDate", d->autoAlbumDateCheck->isChecked()); + config->writeEntry("AutoAlbumExt", d->autoAlbumExtCheck->isChecked()); + config->writeEntry("FixDateTime", d->fixDateTimeCheck->isChecked()); + config->writeEntry("SetPhotographerId", d->setPhotographerId->isChecked()); + config->writeEntry("SetCredits", d->setCredits->isChecked()); + config->writeEntry("ConvertJpeg", convertLosslessJpegFiles()); + config->writeEntry("LossLessFormat", d->losslessFormat->currentItem()); + config->writeEntry("ThumbnailSize", d->view->thumbnailSize().size()); + config->writeEntry("Splitter Sizes", d->splitter->sizes()); + config->writeEntry("FolderDateFormat", d->folderDateFormat->currentItem()); + config->sync(); +} + +void CameraUI::slotProcessURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +bool CameraUI::isBusy() const +{ + return d->busy; +} + +bool CameraUI::isClosed() const +{ + return d->closed; +} + +bool CameraUI::convertLosslessJpegFiles() const +{ + return d->convertJpegCheck->isChecked(); +} + +bool CameraUI::autoRotateJpegFiles() const +{ + return d->autoRotateCheck->isChecked(); +} + +TQString CameraUI::losslessFormat() +{ + return d->losslessFormat->currentText(); +} + +TQString CameraUI::cameraTitle() const +{ + return d->cameraTitle; +} + +void CameraUI::slotCancelButton() +{ + d->status->setText(i18n("Cancelling current operation, please wait...")); + d->progress->hide(); + TQTimer::singleShot(0, d->controller, TQ_SLOT(slotCancel())); + d->currentlyDeleting.clear(); +} + +void CameraUI::closeEvent(TQCloseEvent* e) +{ + if (dialogClosed()) + e->accept(); + else + e->ignore(); +} + +void CameraUI::slotClose() +{ + if (dialogClosed()) + reject(); +} + +bool CameraUI::dialogClosed() +{ + if (d->closed) + return true; + + if (isBusy()) + { + if (KMessageBox::questionYesNo(this, + i18n("Do you want to close the dialog " + "and cancel the current operation?")) + == KMessageBox::No) + return false; + } + + d->status->setText(i18n("Disconnecting from camera, please wait...")); + d->progress->hide(); + + if (isBusy()) + { + d->controller->slotCancel(); + // will be read in slotBusy later and finishDialog + // will be called only when everything is finished + d->closed = true; + } + else + { + d->closed = true; + finishDialog(); + } + + return true; +} + +void CameraUI::finishDialog() +{ + // Look if an item have been downloaded to computer during camera gui session. + // If yes, update the lastAccess date property of camera in digiKam camera list. + + if (d->view->itemsDownloaded() > 0) + { + CameraList* clist = CameraList::instance(); + if (clist) + clist->changeCameraAccessTime(d->cameraTitle, TQDateTime::TQDateTime::currentDateTime()); + } + + // When a directory is created, a watch is put on it to spot new files + // but it can occur that the file is copied there before the watch is + // completely setup. That is why as an extra safeguard run scanlib + // over the folders we used. Bug: 119201 + + d->status->setText(i18n("Scanning for new files, please wait...")); + ScanLib sLib; + for (TQStringList::iterator it = d->foldersToScan.begin(); + it != d->foldersToScan.end(); ++it) + { + //DDebug() << "Scanning " << (*it) << endl; + sLib.findMissingItems( (*it) ); + } + + // Never call finalScan after deleteLater() - ScanLib will call processEvent(), + // and the delete event may be executed! + deleteLater(); + + if(!d->lastDestURL.isEmpty()) + emit signalLastDestination(d->lastDestURL); + + saveSettings(); +} + +void CameraUI::slotBusy(bool val) +{ + if (!val) + { + if (!d->busy) + return; + + d->busy = false; + d->cancelBtn->setEnabled(false); + d->view->viewport()->setEnabled(true); + + d->advBox->setEnabled(true); + // B.K.O #127614: The Focus need to be restored in custom prefix widget. + //commenting this out again: If we do not disable, no need to restore focus + //d->renameCustomizer->restoreFocus(); + + enableButton(User3, true); + enableButton(User2, true); + enableButton(User1, true); + d->helpMenu->menu()->setItemEnabled(CAMERA_INFO_MENU_ID, true); + + d->anim->stop(); + d->status->setText(i18n("Ready")); + d->progress->hide(); + + // like WDestructiveClose, but after camera controller operation has safely finished + if (d->closed) + { + finishDialog(); + } + } + else + { + if (d->busy) + return; + + if (!d->anim->running()) + d->anim->start(); + + d->busy = true; + d->cancelBtn->setEnabled(true); + + // Has camera icon view item selection is used to control download post processing, + // all selection actions are disable when camera interface is busy. + d->view->viewport()->setEnabled(false); + + // Settings tab is disabled in slotDownload, selectively when downloading + // Fast dis/enabling would create the impression of flicker, e.g. when retrieving EXIF from camera + //d->advBox->setEnabled(false); + + enableButton(User3, false); + enableButton(User2, false); + enableButton(User1, false); + d->helpMenu->menu()->setItemEnabled(CAMERA_INFO_MENU_ID, false); + } +} + +void CameraUI::slotIncreaseThumbSize() +{ + int thumbSize = d->view->thumbnailSize().size(); + if (thumbSize >= ThumbnailSize::Huge) return; + + thumbSize += ThumbnailSize::Step; + + if (thumbSize >= ThumbnailSize::Huge) + { + d->imageMenu->setItemEnabled(4, false); + } + d->imageMenu->setItemEnabled(5, true); + + d->view->setThumbnailSize(thumbSize); +} + +void CameraUI::slotDecreaseThumbSize() +{ + int thumbSize = d->view->thumbnailSize().size(); + if (thumbSize <= ThumbnailSize::Small) return; + + thumbSize -= ThumbnailSize::Step; + + if (thumbSize <= ThumbnailSize::Small) + { + d->imageMenu->setItemEnabled(5, false); + } + d->imageMenu->setItemEnabled(4, true); + + d->view->setThumbnailSize(thumbSize); +} + +void CameraUI::slotConnected(bool val) +{ + if (!val) + { + if (KMessageBox::warningYesNo(this, + i18n("Failed to connect to the camera. " + "Please make sure it is connected " + "properly and turned on. " + "Would you like to try again?"), + i18n("Connection Failed"), + i18n("Retry"), + i18n("Abort")) + == KMessageBox::Yes) + TQTimer::singleShot(0, d->controller, TQ_SLOT(slotConnect())); + else + close(); + } + else + { + d->controller->listFolders(); + } +} + +void CameraUI::slotFolderList(const TQStringList& folderList) +{ + if (d->closed) + return; + + d->progress->setProgress(0); + d->progress->setTotalSteps(0); + d->progress->show(); + + d->cameraFolderList = folderList; + for (TQStringList::const_iterator it = folderList.begin(); + it != folderList.end(); ++it) + { + d->controller->listFiles(*it); + } +} + +void CameraUI::slotFileList(const GPItemInfoList& fileList) +{ + if (d->closed) + return; + + if (fileList.empty()) + return; + + kdDebug() << fileList.count() << endl; + + // We sort the map by time stamp + // and we remove internal camera files which are not image/video/sounds. + TQStringList fileNames, fileExts; + TQFileInfo info; + + // JVC camera (see B.K.O #133185). + fileNames.append("mgr_data"); + fileNames.append("pgr_mgr"); + + // HP Photosmart camera (see B.K.O #156338). + fileExts.append("dsp"); + + // Minolta camera in PTP mode + fileExts.append("dps"); + + // We sort the map by time stamp. + GPItemInfoList sfileList; + GPItemInfoList::const_iterator it; + GPItemInfoList::iterator it2; + + for(it = fileList.begin() ; it != fileList.end() ; ++it) + { + info.setFile((*it).name); + if (!fileNames.contains(info.fileName().lower()) && + !fileExts.contains(info.extension(false).lower())) + { + kdDebug() << info.fileName() << " : " << (*it).mtime << endl; + + for(it2 = sfileList.begin() ; it2 != sfileList.end() ; ++it2) + if ((*it2).mtime <= (*it).mtime) break; + + sfileList.insert(it2, *it); + } + } + + if (sfileList.empty()) + return; + + kdDebug() << sfileList.count() << endl; + + GPItemInfoList::const_iterator it3 = sfileList.begin(); + + do + { + GPItemInfo item = *it3; + + if (item.mtime > (time_t)d->lastAccess.toTime_t() && item.downloaded == GPItemInfo::DownloadUnknow) + item.downloaded = GPItemInfo::NewPicture; + + d->view->addItem(item); + d->controller->getThumbnail(item.folder, item.name); + ++it3; + } + while(it3 != sfileList.end()); + + d->progress->setTotalSteps(d->progress->totalSteps() + fileList.count()); +} + +void CameraUI::slotThumbnail(const TQString& folder, const TQString& file, + const TQImage& thumbnail) +{ + d->view->setThumbnail(folder, file, thumbnail); + int curr = d->progress->progress(); + d->progress->setProgress(curr+1); +} + +void CameraUI::slotInformations() +{ + if (d->busy) + return; + + d->controller->getCameraInformations(); +} + +void CameraUI::slotCameraInformations(const TQString& summary, const TQString& manual, const TQString& about) +{ + CameraInfoDialog *infoDlg = new CameraInfoDialog(this, summary, manual, about); + infoDlg->show(); +} + +void CameraUI::slotErrorMsg(const TQString& msg) +{ + KMessageBox::error(this, msg); +} + +void CameraUI::slotUpload() +{ + if (d->busy) + return; + + TQString fileformats; + + TQStringList patternList = TQStringList::split('\n', KImageIO::pattern(KImageIO::Reading)); + + // All Images from list must been always the first entry given by KDE API + TQString allPictures = patternList[0]; + + // Add RAW file format to All Images" type mime and remplace current. +#if KDCRAW_VERSION < 0x000106 + allPictures.insert(allPictures.find("|"), TQString(KDcrawIface::DcrawBinary::instance()->rawFiles())); +#else + allPictures.insert(allPictures.find("|"), TQString(KDcrawIface::KDcraw::rawFiles())); +#endif + patternList.remove(patternList[0]); + patternList.prepend(allPictures); + + // Added RAW file formats supported by dcraw program like a type mime. + // Nota: we cannot use here "image/x-raw" type mime from KDE because it uncomplete + // or unavailable(dcraw_0)(see file #121242 in B.K.O). +#if KDCRAW_VERSION < 0x000106 + patternList.append(TQString("\n%1|Camera RAW files").arg(TQString(KDcrawIface::DcrawBinary::instance()->rawFiles()))); +#else + patternList.append(TQString("\n%1|Camera RAW files").arg(TQString(KDcrawIface::KDcraw::rawFiles()))); +#endif + + fileformats = patternList.join("\n"); + + DDebug () << "fileformats=" << fileformats << endl; + + KURL::List urls = KFileDialog::getOpenURLs(AlbumManager::instance()->getLibraryPath(), + fileformats, this, i18n("Select Image to Upload")); + if (!urls.isEmpty()) + slotUploadItems(urls); +} + +void CameraUI::slotUploadItems(const KURL::List& urls) +{ + if (d->busy) + return; + + if (urls.isEmpty()) + return; + + CameraFolderDialog dlg(this, d->view, d->cameraFolderList, d->controller->getCameraTitle(), + d->controller->getCameraPath()); + + if (dlg.exec() != TQDialog::Accepted) + return; + + TQString cameraFolder = dlg.selectedFolderPath(); + + for (KURL::List::const_iterator it = urls.begin() ; it != urls.end() ; ++it) + { + TQFileInfo fi((*it).path()); + if (!fi.exists()) continue; + if (fi.isDir()) continue; + + TQString ext = TQString(".") + fi.extension(); + TQString name = fi.fileName(); + name.truncate(fi.fileName().length() - ext.length()); + + bool ok; + + while (d->view->findItem(cameraFolder, name + ext)) + { + TQString msg(i18n("Camera Folder <b>%1</b> already contains item <b>%2</b><br>" + "Please enter a new file name (without extension):") + .arg(cameraFolder).arg(fi.fileName())); +#if KDE_IS_VERSION(3,2,0) + name = KInputDialog::getText(i18n("File already exists"), msg, name, &ok, this); + +#else + name = KLineEditDlg::getText(i18n("File already exists"), msg, name, &ok, this); +#endif + if (!ok) + return; + } + + d->controller->upload(fi, name + ext, cameraFolder); + } +} + +void CameraUI::slotUploaded(const GPItemInfo& itemInfo) +{ + if (d->closed) + return; + + d->view->addItem(itemInfo); + d->controller->getThumbnail(itemInfo.folder, itemInfo.name); +} + +void CameraUI::slotDownloadSelected() +{ + slotDownload(true, false); +} + +void CameraUI::slotDownloadAndDeleteSelected() +{ + slotDownload(true, true); +} + +void CameraUI::slotDownloadAll() +{ + slotDownload(false, false); +} + +void CameraUI::slotDownloadAndDeleteAll() +{ + slotDownload(false, true); +} + +void CameraUI::slotDownload(bool onlySelected, bool deleteAfter, Album *album) +{ + // See B.K.O #143934: force to select all items to prevent problem + // when !renameCustomizer->useDefault() ==> iconItem->getDownloadName() + // can return an empty string in this case because it depends on selection. + if (!onlySelected) + d->view->slotSelectAll(); + + // See B.K.O #139519: Always check free space available before to + // download items selection from camera. + unsigned long fSize = 0; + unsigned long dSize = 0; + d->view->itemsSelectionSizeInfo(fSize, dSize); + if (d->freeSpaceWidget->isValid() && (dSize >= d->freeSpaceWidget->kBAvail())) + { + KMessageBox::error(this, i18n("There is no enough free space on Album Library Path " + "to download and process selected pictures from camera.\n\n" + "Estimated space require: %1\n" + "Available free space: %2") + .arg(TDEIO::convertSizeFromKB(dSize)) + .arg(TDEIO::convertSizeFromKB(d->freeSpaceWidget->kBAvail()))); + return; + } + + TQString newDirName; + IconItem* firstItem = d->view->firstItem(); + if (firstItem) + { + CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(firstItem); + + TQDateTime dateTime; + dateTime.setTime_t(iconItem->itemInfo()->mtime); + + switch(d->folderDateFormat->currentItem()) + { + case CameraUIPriv::TextDateFormat: + newDirName = dateTime.date().toString(TQt::TextDate); + break; + case CameraUIPriv::LocalDateFormat: + newDirName = dateTime.date().toString(TQt::LocalDate); + break; + default: // IsoDateFormat + newDirName = dateTime.date().toString(TQt::ISODate); + break; + } + } + + // -- Get the destination album from digiKam library if necessary --------------- + + if (!album) + { + AlbumManager* man = AlbumManager::instance(); + album = man->currentAlbum(); + + if (album && album->type() != Album::PHYSICAL) + album = 0; + + TQString header(i18n("<p>Please select the destination album from the digiKam library to " + "import the camera pictures into.</p>")); + + album = AlbumSelectDialog::selectAlbum(this, (PAlbum*)album, header, newDirName, + d->autoAlbumDateCheck->isChecked()); + + if (!album) return; + } + + PAlbum *pAlbum = dynamic_cast<PAlbum*>(album); + if (!pAlbum) return; + + // -- Prepare downloading of camera items ------------------------ + + KURL url; + url.setPath(pAlbum->folderPath()); + + d->controller->downloadPrep(); + + DownloadSettingsContainer downloadSettings; + TQString downloadName; + time_t mtime; + int total = 0; + + downloadSettings.autoRotate = d->autoRotateCheck->isChecked(); + downloadSettings.fixDateTime = d->fixDateTimeCheck->isChecked(); + downloadSettings.newDateTime = d->dateTimeEdit->dateTime(); + downloadSettings.setPhotographerId = d->setPhotographerId->isChecked(); + downloadSettings.setCredits = d->setCredits->isChecked(); + downloadSettings.convertJpeg = convertLosslessJpegFiles(); + downloadSettings.losslessFormat = losslessFormat(); + + AlbumSettings* settings = AlbumSettings::instance(); + if (settings) + { + downloadSettings.author = settings->getIptcAuthor(); + downloadSettings.authorTitle = settings->getIptcAuthorTitle(); + downloadSettings.credit = settings->getIptcCredit(); + downloadSettings.source = settings->getIptcSource(); + downloadSettings.copyright = settings->getIptcCopyright(); + } + + // -- Download camera items ------------------------------- + // Since we show camera items in reverse order, downloading need to be done also in reverse order. + + for (IconItem* item = d->view->lastItem(); item; + item = item->prevItem()) + { + if (onlySelected && !(item->isSelected())) + continue; + + CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item); + downloadSettings.folder = iconItem->itemInfo()->folder; + downloadSettings.file = iconItem->itemInfo()->name; + downloadName = iconItem->getDownloadName(); + mtime = iconItem->itemInfo()->mtime; + + KURL u(url); + TQString errMsg; + TQDateTime dateTime; + dateTime.setTime_t(mtime); + + // Auto sub-albums creation based on file date. + + if (d->autoAlbumDateCheck->isChecked()) + { + TQString dirName; + + switch(d->folderDateFormat->currentItem()) + { + case CameraUIPriv::TextDateFormat: + dirName = dateTime.date().toString(TQt::TextDate); + break; + case CameraUIPriv::LocalDateFormat: + dirName = dateTime.date().toString(TQt::LocalDate); + break; + default: // IsoDateFormat + dirName = dateTime.date().toString(TQt::ISODate); + break; + } + // See B.K.O #136927 : we need to support file system which do not + // handle upper case properly. + dirName = dirName.lower(); + if (!createAutoAlbum(url, dirName, dateTime.date(), errMsg)) + { + KMessageBox::error(this, errMsg); + return; + } + + u.addPath(dirName); + } + + // Auto sub-albums creation based on file extensions. + + if (d->autoAlbumExtCheck->isChecked()) + { + // We use the target file name to compute sub-albums name to take a care about + // convertion on the fly option. + TQFileInfo fi(downloadName); + + TQString subAlbum = fi.extension(false).upper(); + if (fi.extension(false).upper() == TQString("JPEG") || + fi.extension(false).upper() == TQString("JPE")) + subAlbum = TQString("JPG"); + if (fi.extension(false).upper() == TQString("TIFF")) + subAlbum = TQString("TIF"); + if (fi.extension(false).upper() == TQString("MPEG") || + fi.extension(false).upper() == TQString("MPE") || + fi.extension(false).upper() == TQString("MPO")) + subAlbum = TQString("MPG"); + + // See B.K.O #136927 : we need to support file system which do not + // handle upper case properly. + subAlbum = subAlbum.lower(); + if (!createAutoAlbum(u, subAlbum, dateTime.date(), errMsg)) + { + KMessageBox::error(this, errMsg); + return; + } + + u.addPath(subAlbum); + } + + d->foldersToScan.append(u.path()); + u.addPath(downloadName.isEmpty() ? downloadSettings.file : downloadName); + + downloadSettings.dest = u.path(); + + d->controller->download(downloadSettings); + addFileExtension(TQFileInfo(u.path()).extension(false)); + total++; + } + + if (total <= 0) + return; + + d->lastDestURL = url; + d->progress->setProgress(0); + d->progress->setTotalSteps(total); + d->progress->show(); + + // disable settings tab here instead of slotBusy: + // Only needs to be disabled while downloading + d->advBox->setEnabled(false); + + d->deleteAfter = deleteAfter; +} + +void CameraUI::slotDownloaded(const TQString& folder, const TQString& file, int status) +{ + CameraIconViewItem* iconItem = d->view->findItem(folder, file); + if (iconItem) + iconItem->setDownloaded(status); + + if (status == GPItemInfo::DownloadedYes || status == GPItemInfo::DownloadFailed) + { + int curr = d->progress->progress(); + d->progress->setProgress(curr+1); + } + + // Download all items is complete. + if (d->progress->progress() == d->progress->totalSteps()) + { + if (d->deleteAfter) + deleteItems(true, true); + } +} + +void CameraUI::slotSkipped(const TQString& folder, const TQString& file) +{ + CameraIconViewItem* iconItem = d->view->findItem(folder, file); + if (iconItem) + iconItem->setDownloaded(GPItemInfo::DownloadedNo); + + int curr = d->progress->progress(); + d->progress->setProgress(curr+1); +} + +void CameraUI::slotToggleLock() +{ + int count = 0; + for (IconItem* item = d->view->firstItem(); item; + item = item->nextItem()) + { + CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item); + if (iconItem->isSelected()) + { + TQString folder = iconItem->itemInfo()->folder; + TQString file = iconItem->itemInfo()->name; + int writePerm = iconItem->itemInfo()->writePermissions; + bool lock = true; + + // If item is currently locked, unlock it. + if (writePerm == 0) + lock = false; + + d->controller->lockFile(folder, file, lock); + count++; + } + } + + if (count > 0) + { + d->progress->setProgress(0); + d->progress->setTotalSteps(count); + d->progress->show(); + } +} + +void CameraUI::slotLocked(const TQString& folder, const TQString& file, bool status) +{ + if (status) + { + CameraIconViewItem* iconItem = d->view->findItem(folder, file); + if (iconItem) + { + iconItem->toggleLock(); + //if (iconItem->isSelected()) + // slotItemsSelected(iconItem, true); + } + } + + int curr = d->progress->progress(); + d->progress->setProgress(curr+1); +} + +void CameraUI::checkItem4Deletion(CameraIconViewItem* iconItem, TQStringList& folders, TQStringList& files, + TQStringList& deleteList, TQStringList& lockedList) +{ + if (iconItem->itemInfo()->writePermissions != 0) // Item not locked ? + { + TQString folder = iconItem->itemInfo()->folder; + TQString file = iconItem->itemInfo()->name; + folders.append(folder); + files.append(file); + deleteList.append(folder + TQString("/") + file); + } + else + { + lockedList.append(iconItem->itemInfo()->name); + } +} + +void CameraUI::deleteItems(bool onlySelected, bool onlyDownloaded) +{ + TQStringList folders; + TQStringList files; + TQStringList deleteList; + TQStringList lockedList; + + for (IconItem* item = d->view->firstItem(); item; item = item->nextItem()) + { + CameraIconViewItem* iconItem = dynamic_cast<CameraIconViewItem*>(item); + if (iconItem) + { + if (onlySelected) + { + if (iconItem->isSelected()) + { + if (onlyDownloaded) + { + if (iconItem->isDownloaded()) + checkItem4Deletion(iconItem, folders, files, deleteList, lockedList); + } + else + { + checkItem4Deletion(iconItem, folders, files, deleteList, lockedList); + } + } + } + else // All items + { + if (onlyDownloaded) + { + if (iconItem->isDownloaded()) + checkItem4Deletion(iconItem, folders, files, deleteList, lockedList); + } + else + { + checkItem4Deletion(iconItem, folders, files, deleteList, lockedList); + } + } + } + } + + // If we want to delete some locked files, just give a feedback to user. + if (!lockedList.isEmpty()) + { + TQString infoMsg(i18n("The items listed below are locked by camera (read-only). " + "These items will not be deleted. If you really want to delete these items, " + "please unlock them and try again.")); + KMessageBox::informationList(this, infoMsg, lockedList, i18n("Information")); + } + + if (folders.isEmpty()) + return; + + TQString warnMsg(i18n("About to delete this image. " + "Deleted files are unrecoverable. " + "Are you sure?", + "About to delete these %n images. " + "Deleted files are unrecoverable. " + "Are you sure?", + deleteList.count())); + if (KMessageBox::warningContinueCancelList(this, warnMsg, + deleteList, + i18n("Warning"), + i18n("Delete")) + == KMessageBox::Continue) + { + TQStringList::iterator itFolder = folders.begin(); + TQStringList::iterator itFile = files.begin(); + + d->progress->setProgress(0); + d->progress->setTotalSteps(deleteList.count()); + d->progress->show(); + + for ( ; itFolder != folders.end(); ++itFolder, ++itFile) + { + d->controller->deleteFile(*itFolder, *itFile); + // the currentlyDeleting list is used to prevent loading items which + // will immenently be deleted into the sidebar and wasting time + d->currentlyDeleting.append(*itFolder + *itFile); + } + } +} + +void CameraUI::slotDeleteSelected() +{ + deleteItems(true, false); +} + +void CameraUI::slotDeleteAll() +{ + deleteItems(false, false); +} + +void CameraUI::slotDeleted(const TQString& folder, const TQString& file, bool status) +{ + if (status) + { + d->view->removeItem(folder, file); + // do this after removeItem, which will signal to slotItemsSelected, which checks for the list + d->currentlyDeleting.remove(folder + file); + } + + int curr = d->progress->progress(); + d->progress->setProgress(curr+1); +} + +void CameraUI::slotFileView(CameraIconViewItem* item) +{ + d->controller->openFile(item->itemInfo()->folder, item->itemInfo()->name); +} + +void CameraUI::slotExifFromFile(const TQString& folder, const TQString& file) +{ + CameraIconViewItem* item = d->view->findItem(folder, file); + if (!item) + return; + + d->rightSidebar->itemChanged(item->itemInfo(), folder + TQString("/") + file, + TQByteArray(), d->view, item); +} + +void CameraUI::slotExifFromData(const TQByteArray& exifData) +{ + CameraIconViewItem* item = dynamic_cast<CameraIconViewItem*>(d->view->currentItem()); + + if (!item) + return; + + KURL url(item->itemInfo()->folder + '/' + item->itemInfo()->name); + + // Sometimes, GPhoto2 drivers return complete APP1 JFIF section. Exiv2 cannot + // decode (yet) exif metadata from APP1. We will find Exif header to get data at this place + // to please with Exiv2... + + DDebug() << "Size of Exif metadata from camera = " << exifData.size() << endl; + char exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + + if (!exifData.isEmpty()) + { + int i = exifData.find(*exifHeader); + if (i != -1) + { + DDebug() << "Exif header found at position " << i << endl; + i = i + sizeof(exifHeader); + TQByteArray data(exifData.size()-i); + memcpy(data.data(), exifData.data()+i, data.size()); + d->rightSidebar->itemChanged(item->itemInfo(), url, data, d->view, item); + return; + } + } + + d->rightSidebar->itemChanged(item->itemInfo(), url, exifData, d->view, item); +} + +void CameraUI::slotNewSelection(bool hasSelection) +{ + if (!d->renameCustomizer->useDefault()) + { + d->downloadMenu->setItemEnabled(0, hasSelection); + d->downloadMenu->setItemEnabled(2, hasSelection); + } + else + { + d->downloadMenu->setItemEnabled(0, hasSelection); + d->downloadMenu->setItemEnabled(2, hasSelection); + } + + unsigned long fSize = 0; + unsigned long dSize = 0; + d->view->itemsSelectionSizeInfo(fSize, dSize); + d->freeSpaceWidget->setEstimatedDSizeKb(dSize); +} + +void CameraUI::slotItemsSelected(CameraIconViewItem* item, bool selected) +{ + d->downloadMenu->setItemEnabled(0, selected); + d->downloadMenu->setItemEnabled(2, selected); + d->deleteMenu->setItemEnabled(0, selected); + + if (selected) + { + // if selected item is in the list of item which will be deleted, set no current item + if (d->currentlyDeleting.find(item->itemInfo()->folder + item->itemInfo()->name) + == d->currentlyDeleting.end()) + { + KURL url(item->itemInfo()->folder + '/' + item->itemInfo()->name); + d->rightSidebar->itemChanged(item->itemInfo(), url, TQByteArray(), d->view, item); + d->controller->getExif(item->itemInfo()->folder, item->itemInfo()->name); + } + else + { + d->rightSidebar->slotNoCurrentItem(); + } + } + else + d->rightSidebar->slotNoCurrentItem(); +} + +bool CameraUI::createAutoAlbum(const KURL& parentURL, const TQString& sub, + const TQDate& date, TQString& errMsg) +{ + KURL u(parentURL); + u.addPath(sub); + + // first stat to see if the album exists + TQFileInfo info(u.path()); + if (info.exists()) + { + // now check if its really a directory + if (info.isDir()) + return true; + else + { + errMsg = i18n("A file with same name (%1) exists in folder %2") + .arg(sub) + .arg(parentURL.path()); + return false; + } + } + + // looks like the directory does not exist, try to create it + + AlbumManager* aman = AlbumManager::instance(); + PAlbum* parent = aman->findPAlbum(parentURL); + if (!parent) + { + errMsg = i18n("Failed to find Album for path '%1'") + .arg(parentURL.path()); + return false; + } + + return aman->createPAlbum(parent, sub, TQString(""), date, TQString(""), errMsg); +} + +void CameraUI::addFileExtension(const TQString& ext) +{ + AlbumSettings* settings = AlbumSettings::instance(); + if (!settings) + return; + + if (settings->getImageFileFilter().upper().contains(ext.upper()) || + settings->getMovieFileFilter().upper().contains(ext.upper()) || + settings->getAudioFileFilter().upper().contains(ext.upper()) || + settings->getRawFileFilter().upper().contains(ext.upper())) + return; + + settings->setImageFileFilter(settings->getImageFileFilter() + TQString(" *.") + ext); + emit signalAlbumSettingsChanged(); +} + +void CameraUI::slotFirstItem() +{ + CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->firstItem()); + d->view->clearSelection(); + d->view->updateContents(); + if (currItem) + d->view->setCurrentItem(currItem); +} + +void CameraUI::slotPrevItem() +{ + CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->currentItem()); + d->view->clearSelection(); + d->view->updateContents(); + if (currItem) + d->view->setCurrentItem(currItem->prevItem()); +} + +void CameraUI::slotNextItem() +{ + CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->currentItem()); + d->view->clearSelection(); + d->view->updateContents(); + if (currItem) + d->view->setCurrentItem(currItem->nextItem()); +} + +void CameraUI::slotLastItem(void) +{ + CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->lastItem()); + d->view->clearSelection(); + d->view->updateContents(); + if (currItem) + d->view->setCurrentItem(currItem); +} + +// Backport KDialog::keyPressEvent() implementation from KDELibs to ignore Enter/Return Key events +// to prevent any conflicts between dialog keys events and SpinBox keys events. + +void CameraUI::keyPressEvent(TQKeyEvent *e) +{ + if ( e->state() == 0 ) + { + switch ( e->key() ) + { + case Key_Escape: + e->accept(); + reject(); + break; + case Key_Enter: + case Key_Return: + e->ignore(); + break; + default: + e->ignore(); + return; + } + } + else + { + // accept the dialog when Ctrl-Return is pressed + if ( e->state() == ControlButton && + (e->key() == Key_Return || e->key() == Key_Enter) ) + { + e->accept(); + accept(); + } + else + { + e->ignore(); + } + } +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/cameraui.h b/src/utilities/cameragui/cameraui.h new file mode 100644 index 00000000..df9c7885 --- /dev/null +++ b/src/utilities/cameragui/cameraui.h @@ -0,0 +1,155 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-16 + * Description : Camera interface dialog + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef CAMERAUI_H +#define CAMERAUI_H + +// TQt includes. + +#include <tqdatetime.h> +#include <tqstring.h> +#include <tqimage.h> + +// KDE includes. + +#include <kdialogbase.h> +#include <kurl.h> + +// Local includes. + +#include "gpiteminfo.h" + +namespace Digikam +{ + +class Album; +class CameraIconViewItem; +class CameraUIPriv; + +class CameraUI : public KDialogBase +{ + TQ_OBJECT + + +public: + + CameraUI(TQWidget* parent, const TQString& cameraTitle, + const TQString& model, const TQString& port, + const TQString& path, const TQDateTime lastAccess); + ~CameraUI(); + + bool isBusy() const; + bool isClosed() const; + + bool autoRotateJpegFiles() const; + + /** Get status of JPEG conversion files to lossless format during download.*/ + bool convertLosslessJpegFiles() const; + TQString losslessFormat(); + + TQString cameraTitle() const; + +signals: + + void signalLastDestination(const KURL&); + void signalAlbumSettingsChanged(); + +public slots: + + void slotDownload(bool onlySelected, bool deleteAfter, Album *album=0); + +protected: + + void closeEvent(TQCloseEvent* e); + void keyPressEvent(TQKeyEvent *e); + +private: + + void readSettings(); + void saveSettings(); + bool dialogClosed(); + bool createAutoAlbum(const KURL& parentURL, const TQString& sub, + const TQDate& date, TQString& errMsg); + void addFileExtension(const TQString& ext); + void finishDialog(); + void deleteItems(bool onlySelected, bool onlyDownloaded); + void checkItem4Deletion(CameraIconViewItem* iconItem, TQStringList& folders, TQStringList& files, + TQStringList& deleteList, TQStringList& lockedList); + +private slots: + + void slotClose(); + void slotCancelButton(); + void slotProcessURL(const TQString& url); + + void slotConnected(bool val); + void slotBusy(bool val); + void slotErrorMsg(const TQString& msg); + void slotInformations(); + void slotCameraInformations(const TQString&, const TQString&, const TQString&); + + void slotFolderList(const TQStringList& folderList); + void slotFileList(const GPItemInfoList& fileList); + void slotThumbnail(const TQString&, const TQString&, const TQImage&); + + void slotIncreaseThumbSize(); + void slotDecreaseThumbSize(); + + void slotUpload(); + void slotUploadItems(const KURL::List&); + void slotDownloadSelected(); + void slotDownloadAll(); + void slotDeleteSelected(); + void slotDownloadAndDeleteSelected(); + void slotDeleteAll(); + void slotDownloadAndDeleteAll(); + void slotToggleLock(); + + void slotFileView(CameraIconViewItem* item); + + void slotUploaded(const GPItemInfo&); + void slotDownloaded(const TQString&, const TQString&, int); + void slotSkipped(const TQString&, const TQString&); + void slotDeleted(const TQString&, const TQString&, bool); + void slotLocked(const TQString&, const TQString&, bool); + + void slotNewSelection(bool); + void slotItemsSelected(CameraIconViewItem* item, bool selected); + + void slotExifFromFile(const TQString& folder, const TQString& file); + void slotExifFromData(const TQByteArray& exifData); + + void slotFirstItem(void); + void slotPrevItem(void); + void slotNextItem(void); + void slotLastItem(void); + +private: + + CameraUIPriv* d; +}; + +} // namespace Digikam + +#endif /* CAMERAUI_H */ diff --git a/src/utilities/cameragui/dkcamera.cpp b/src/utilities/cameragui/dkcamera.cpp new file mode 100644 index 00000000..8f318855 --- /dev/null +++ b/src/utilities/cameragui/dkcamera.cpp @@ -0,0 +1,113 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-21 + * Description : abstract camera interface class + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqdeepcopy.h> + +// Local includes. + +#include "albumsettings.h" +#include "dkcamera.h" + +namespace Digikam +{ + +DKCamera::DKCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path) +{ + m_title = title; + m_model = model; + m_port = port; + m_path = path; + + AlbumSettings* settings = AlbumSettings::instance(); + m_imageFilter = TQDeepCopy<TQString>(settings->getImageFileFilter()); + m_movieFilter = TQDeepCopy<TQString>(settings->getMovieFileFilter()); + m_audioFilter = TQDeepCopy<TQString>(settings->getAudioFileFilter()); + m_rawFilter = TQDeepCopy<TQString>(settings->getRawFileFilter()); + + m_imageFilter = m_imageFilter.lower(); + m_movieFilter = m_movieFilter.lower(); + m_audioFilter = m_audioFilter.lower(); + m_rawFilter = m_rawFilter.lower(); +} + +DKCamera::~DKCamera() +{ +} + +TQString DKCamera::title() const +{ + return m_title; +} + +TQString DKCamera::model() const +{ + return m_model; +} + +TQString DKCamera::port() const +{ + return m_port; +} + +TQString DKCamera::path() const +{ + return m_path; +} + +TQString DKCamera::mimeType(const TQString& fileext) const +{ + if (fileext.isEmpty()) return TQString(); + + TQString ext = fileext; + TQString mime; + + // Massage known variations of known mimetypes into KDE specific ones + if (ext == "jpg" || ext == "jpe") + ext = "jpeg"; + else if (ext == "tif") + ext = "tiff"; + + if (m_rawFilter.contains(ext)) + { + mime = TQString("image/x-raw"); + } + else if (m_imageFilter.contains(ext)) + { + mime = TQString("image/") + ext; + } + else if (m_movieFilter.contains(ext)) + { + mime = TQString("video/") + ext; + } + else if (m_audioFilter.contains(ext)) + { + mime = TQString("audio/") + ext; + } + + return mime; +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/dkcamera.h b/src/utilities/cameragui/dkcamera.h new file mode 100644 index 00000000..2ef76723 --- /dev/null +++ b/src/utilities/cameragui/dkcamera.h @@ -0,0 +1,97 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-21 + * Description : abstract camera interface class + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef DKCAMERA_H +#define DKCAMERA_H + +// TQt includes. + +#include <tqstring.h> + +// Local includes. + +#include "gpiteminfo.h" + +class TQStringList; +class TQImage; + +namespace Digikam +{ + +class DKCamera +{ +public: + + DKCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path); + virtual ~DKCamera(); + + virtual bool doConnect() = 0; + virtual void cancel() = 0; + + virtual void getAllFolders(const TQString& folder, TQStringList& subFolderList) = 0; + + /// If getImageDimensions is false, the camera shall set width and height to -1 + /// if the values are not immediately available + virtual bool getItemsInfoList(const TQString& folder, GPItemInfoList& infoList, bool getImageDimensions = true) = 0; + + virtual bool getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail) = 0; + virtual bool getExif(const TQString& folder, const TQString& itemName, char **edata, int& esize) = 0; + + virtual bool downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile) = 0; + virtual bool deleteItem(const TQString& folder, const TQString& itemName) = 0; + virtual bool uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile, + GPItemInfo& itemInfo, bool getImageDimensions=true) = 0; + virtual bool cameraSummary(TQString& summary) = 0; + virtual bool cameraManual(TQString& manual) = 0; + virtual bool cameraAbout(TQString& about) = 0; + + virtual bool setLockItem(const TQString& folder, const TQString& itemName, bool lock) = 0; + + TQString title() const; + TQString model() const; + TQString port() const; + TQString path() const; + +protected: + + TQString mimeType(const TQString& fileext) const; + +protected: + + TQString m_imageFilter; + TQString m_movieFilter; + TQString m_audioFilter; + TQString m_rawFilter; + +private: + + TQString m_title; + TQString m_model; + TQString m_port; + TQString m_path; +}; + +} // namespace Digikam + +#endif /* DKCAMERA_H */ diff --git a/src/utilities/cameragui/downloadsettingscontainer.h b/src/utilities/cameragui/downloadsettingscontainer.h new file mode 100644 index 00000000..b3e59501 --- /dev/null +++ b/src/utilities/cameragui/downloadsettingscontainer.h @@ -0,0 +1,79 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-21-07 + * Description : Camera item download settings container. + * + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef DOWNLOADSETTINGSCONTAINER_H +#define DOWNLOADSETTINGSCONTAINER_H + +// TQt includes. + +#include <tqstring.h> +#include <tqdatetime.h> + +namespace Digikam +{ + +class DownloadSettingsContainer +{ + +public: + + DownloadSettingsContainer() + { + autoRotate = true; + fixDateTime = false; + setPhotographerId = false; + setCredits = false; + convertJpeg = false; + }; + + ~DownloadSettingsContainer(){}; + +public: + + bool autoRotate; + bool fixDateTime; + bool setPhotographerId; + bool setCredits; + bool convertJpeg; + + TQDateTime newDateTime; + + // File path to download. + TQString folder; + TQString file; + TQString dest; + + // New format to convert Jpeg files. + TQString losslessFormat; + + // IPTC settings + TQString author; + TQString authorTitle; + TQString credit; + TQString source; + TQString copyright; +}; + +} // namespace Digikam + +#endif // DOWNLOADSETTINGSCONTAINER_H diff --git a/src/utilities/cameragui/freespacewidget.cpp b/src/utilities/cameragui/freespacewidget.cpp new file mode 100644 index 00000000..0d7a26b1 --- /dev/null +++ b/src/utilities/cameragui/freespacewidget.cpp @@ -0,0 +1,252 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-08-31 + * Description : a widget to display free space for a mount-point. + * + * Copyright (C) 2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqpalette.h> +#include <tqcolor.h> +#include <tqtimer.h> +#include <tqfont.h> +#include <tqfontmetrics.h> + +// KDE includes. + +#include <kurl.h> +#include <tdelocale.h> +#include <kdiskfreesp.h> +#include <tdeio/global.h> +#include <kiconloader.h> + +// Local includes. + +#include "albumsettings.h" +#include "freespacewidget.h" +#include "freespacewidget.moc" + +namespace Digikam +{ + +class FreeSpaceWidgetPriv +{ +public: + + FreeSpaceWidgetPriv() + { + timer = 0; + isValid = false; + kBSize = 0; + kBUsed = 0; + kBAvail = 0; + dSizeKb = 0; + percentUsed = 0; + } + + bool isValid; + + int percentUsed; + + unsigned long dSizeKb; + unsigned long kBSize; + unsigned long kBUsed; + unsigned long kBAvail; + + TQString mountPoint; + + TQTimer *timer; + + TQPixmap pix; +}; + +FreeSpaceWidget::FreeSpaceWidget(TQWidget* parent, int width) + : TQWidget(parent, 0, WResizeNoErase|WRepaintNoErase) +{ + d = new FreeSpaceWidgetPriv; + setBackgroundMode(TQt::NoBackground); + setFixedWidth(width); + setMaximumHeight(fontMetrics().height()+4); + slotTimeout(); + + d->timer = new TQTimer(this); + + connect(d->timer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotTimeout())); + + d->timer->start(10000); +} + +FreeSpaceWidget::~FreeSpaceWidget() +{ + d->timer->stop(); + delete d->timer; + delete d; +} + +void FreeSpaceWidget::setEstimatedDSizeKb(unsigned long dSize) +{ + d->dSizeKb = dSize; + updatePixmap(); + repaint(); +} + +unsigned long FreeSpaceWidget::estimatedDSizeKb() +{ + return d->dSizeKb; +} + +bool FreeSpaceWidget::isValid() +{ + return d->isValid; +} + +int FreeSpaceWidget::percentUsed() +{ + return d->percentUsed; +} + +unsigned long FreeSpaceWidget::kBSize() +{ + return d->kBSize; +} + +unsigned long FreeSpaceWidget::kBUsed() +{ + return d->kBUsed; +} + +unsigned long FreeSpaceWidget::kBAvail() +{ + return d->kBAvail; +} + +TQString FreeSpaceWidget::mountPoint() +{ + return d->mountPoint; +} + +void FreeSpaceWidget::updatePixmap() +{ + TQPixmap fimgPix = SmallIcon("folder_image"); + d->pix = TQPixmap(size()); + d->pix.fill(colorGroup().background()); + + TQPainter p(&d->pix); + p.setPen(colorGroup().mid()); + p.drawRect(0, 0, d->pix.width(), d->pix.height()); + p.drawPixmap(2, d->pix.height()/2-fimgPix.height()/2, + fimgPix, 0, 0, fimgPix.width(), fimgPix.height()); + + if (isValid()) + { + // We will compute the estimated % of space size used to download and process. + unsigned long eUsedKb = d->dSizeKb + d->kBUsed; + int peUsed = (int)(100.0*((double)eUsedKb/(double)d->kBSize)); + int pClamp = peUsed > 100 ? 100 : peUsed; + p.setBrush(peUsed > 95 ? TQt::red : TQt::darkGreen); + p.setPen(TQt::white); + TQRect gRect(fimgPix.height()+2, 1, + (int)(((double)d->pix.width()-2.0-fimgPix.width()-2.0)*(pClamp/100.0)), + d->pix.height()-2); + p.drawRect(gRect); + + TQRect tRect(fimgPix.height()+2, 1, d->pix.width()-2-fimgPix.width()-2, d->pix.height()-2); + TQString text = TQString("%1%").arg(peUsed); + p.setPen(colorGroup().text()); + TQFontMetrics fontMt = p.fontMetrics(); + TQRect fontRect = fontMt.boundingRect(tRect.x(), tRect.y(), + tRect.width(), tRect.height(), 0, text); + p.drawText(tRect, TQt::AlignCenter, text); + + TQString tipText, value; + TQString header = i18n("Album Library"); + TQString headBeg("<tr bgcolor=\"orange\"><td colspan=\"2\">" + "<nobr><font size=\"-1\" color=\"black\"><b>"); + TQString headEnd("</b></font></nobr></td></tr>"); + TQString cellBeg("<tr><td><nobr><font size=-1>"); + TQString cellMid("</font></nobr></td><td><nobr><font size=-1>"); + TQString cellEnd("</font></nobr></td></tr>"); + tipText = "<table cellspacing=0 cellpadding=0>"; + tipText += headBeg + header + headEnd; + + if (d->dSizeKb > 0) + { + tipText += cellBeg + i18n("Capacity:") + cellMid; + tipText += TDEIO::convertSizeFromKB(d->kBSize) + cellEnd; + + tipText += cellBeg + i18n("Available:") + cellMid; + tipText += TDEIO::convertSizeFromKB(d->kBAvail) + cellEnd; + + tipText += cellBeg + i18n("Require:") + cellMid; + tipText += TDEIO::convertSizeFromKB(d->dSizeKb) + cellEnd; + } + else + { + tipText += cellBeg + i18n("Capacity:") + cellMid; + tipText += TDEIO::convertSizeFromKB(d->kBSize) + cellEnd; + + tipText += cellBeg + i18n("Available:") + cellMid; + tipText += TDEIO::convertSizeFromKB(d->kBAvail) + cellEnd; + } + + tipText += "</table>"; + + TQWhatsThis::add(this, tipText); + TQToolTip::add(this, tipText); + } + + p.end(); +} + +void FreeSpaceWidget::paintEvent(TQPaintEvent*) +{ + bitBlt(this, 0, 0, &d->pix); +} + +void FreeSpaceWidget::slotTimeout() +{ + TQString mountPoint = TDEIO::findPathMountPoint(AlbumSettings::instance()->getAlbumLibraryPath()); + KDiskFreeSp *job = new KDiskFreeSp; + connect(job, TQ_SIGNAL(foundMountPoint(const unsigned long&, const unsigned long&, + const unsigned long&, const TQString&)), + this, TQ_SLOT(slotAvailableFreeSpace(const unsigned long&, const unsigned long&, + const unsigned long&, const TQString&))); + job->readDF(mountPoint); +} + +void FreeSpaceWidget::slotAvailableFreeSpace(const unsigned long& kBSize, const unsigned long& kBUsed, + const unsigned long& kBAvail, const TQString& mountPoint) +{ + d->mountPoint = mountPoint; + d->kBSize = kBSize; + d->kBUsed = kBUsed; + d->kBAvail = kBAvail; + d->percentUsed = 100 - (int)(100.0*kBAvail/kBSize); + d->isValid = true; + updatePixmap(); + repaint(); +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/freespacewidget.h b/src/utilities/cameragui/freespacewidget.h new file mode 100644 index 00000000..2111791a --- /dev/null +++ b/src/utilities/cameragui/freespacewidget.h @@ -0,0 +1,75 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-08-31 + * Description : a widget to display free space for a mount-point. + * + * Copyright (C) 2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef FREESPACEWIDGET_H +#define FREESPACEWIDGET_H + +// TQt includes. + +#include <tqstring.h> +#include <tqwidget.h> + +namespace Digikam +{ + +class FreeSpaceWidgetPriv; + +class FreeSpaceWidget : public TQWidget +{ + TQ_OBJECT + + +public: + + FreeSpaceWidget(TQWidget* parent, int width); + ~FreeSpaceWidget(); + + void setEstimatedDSizeKb(unsigned long dSize); + unsigned long estimatedDSizeKb(); + + bool isValid() ; + int percentUsed(); + unsigned long kBSize(); + unsigned long kBUsed(); + unsigned long kBAvail(); + TQString mountPoint(); + +protected: + + void paintEvent(TQPaintEvent*); + void updatePixmap(); + +private slots: + + void slotTimeout(); + void slotAvailableFreeSpace(const unsigned long& kBSize, const unsigned long& kBUsed, + const unsigned long& kBAvail, const TQString& mountPoint); + +private: + + FreeSpaceWidgetPriv* d; +}; + +} // namespace Digikam + +#endif /* FREESPACEWIDGET_H */ diff --git a/src/utilities/cameragui/gpcamera.cpp b/src/utilities/cameragui/gpcamera.cpp new file mode 100644 index 00000000..e03d92d0 --- /dev/null +++ b/src/utilities/cameragui/gpcamera.cpp @@ -0,0 +1,1223 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-21 + * Description : Gphoto2 camera interface + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdio> +#include <iostream> + +// TQt includes. + +#include <tqstring.h> +#include <tqstringlist.h> +#include <tqimage.h> +#include <tqpixmap.h> +#include <tqdom.h> +#include <tqfile.h> + +// KDE includes. + +#include <tdelocale.h> + +// C Ansi includes. +extern "C" +{ +#include <gphoto2.h> +} + +// Local includes. + +#include "ddebug.h" +#include "gpcamera.h" + +namespace Digikam +{ + +class GPCameraPrivate +{ + +public: + + GPCameraPrivate() + { + camera = 0; + } + + bool cameraInitialized; + + bool thumbnailSupport; + bool deleteSupport; + bool uploadSupport; + bool mkDirSupport; + bool delDirSupport; + + TQString model; + TQString port; + TQString globalPath; + + Camera *camera; + CameraAbilities cameraAbilities; +}; + +class GPStatus +{ + +public: + + GPStatus() + { + context = gp_context_new(); + cancel = false; + gp_context_set_cancel_func(context, cancel_func, 0); + } + + ~GPStatus() + { + gp_context_unref(context); + cancel = false; + } + + GPContext *context; + static bool cancel; + + static GPContextFeedback cancel_func(GPContext *, void *) + { + return (cancel ? GP_CONTEXT_FEEDBACK_CANCEL : + GP_CONTEXT_FEEDBACK_OK); + } +}; + +bool GPStatus::cancel = false; + +GPCamera::GPCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path) + : DKCamera(title, model, port, path) +{ + m_status = 0; + + d = new GPCameraPrivate; + d->camera = 0; + d->model = model; + d->port = port; + d->globalPath = path; + d->cameraInitialized = false; + d->thumbnailSupport = false; + d->deleteSupport = false; + d->uploadSupport = false; + d->mkDirSupport = false; + d->delDirSupport = false; +} + +GPCamera::~GPCamera() +{ + if (d->camera) + { + gp_camera_unref(d->camera); + d->camera = 0; + } + + delete d; +} + +TQString GPCamera::model() const +{ + return d->model; +} + +TQString GPCamera::port() const +{ + return d->port; +} + +TQString GPCamera::path() const +{ + return d->globalPath; +} + +bool GPCamera::thumbnailSupport() +{ + return d->thumbnailSupport; +} + +bool GPCamera::deleteSupport() +{ + return d->deleteSupport; +} + +bool GPCamera::uploadSupport() +{ + return d->uploadSupport; +} + +bool GPCamera::mkDirSupport() +{ + return d->mkDirSupport; +} + +bool GPCamera::delDirSupport() +{ + return d->delDirSupport; +} + +bool GPCamera::doConnect() +{ + int errorCode; + // -- first step - setup the camera -------------------- + + if (d->camera) + { + gp_camera_unref(d->camera); + d->camera = 0; + } + + CameraAbilitiesList *abilList; + GPPortInfoList *infoList; + GPPortInfo info; + + gp_camera_new(&d->camera); + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus(); + + gp_abilities_list_new(&abilList); + gp_abilities_list_load(abilList, m_status->context); + gp_port_info_list_new(&infoList); + gp_port_info_list_load(infoList); + + delete m_status; + m_status = 0; + + int modelNum = -1, portNum = -1; + modelNum = gp_abilities_list_lookup_model(abilList, d->model.latin1()); + portNum = gp_port_info_list_lookup_path (infoList, d->port.latin1()); + + gp_abilities_list_get_abilities(abilList, modelNum, &d->cameraAbilities); + + errorCode = gp_camera_set_abilities(d->camera, d->cameraAbilities); + if (errorCode != GP_OK) + { + DDebug() << "Failed to set camera Abilities!" << endl; + printGphotoErrorDescription(errorCode); + gp_camera_unref(d->camera); + d->camera = 0; + gp_abilities_list_free(abilList); + gp_port_info_list_free(infoList); + return false; + } + + if (d->model != "Directory Browse") + { + gp_port_info_list_get_info(infoList, portNum, &info); + errorCode = gp_camera_set_port_info(d->camera, info); + if (errorCode != GP_OK) + { + DDebug() << "Failed to set camera port!" << endl; + printGphotoErrorDescription(errorCode); + gp_camera_unref(d->camera); + d->camera = 0; + gp_abilities_list_free (abilList); + gp_port_info_list_free (infoList); + return false; + } + } + + gp_abilities_list_free (abilList); + gp_port_info_list_free (infoList); + + if (d->cameraAbilities.file_operations & + GP_FILE_OPERATION_PREVIEW) + d->thumbnailSupport = true; + + if (d->cameraAbilities.file_operations & + GP_FILE_OPERATION_DELETE) + d->deleteSupport = true; + + if (d->cameraAbilities.folder_operations & + GP_FOLDER_OPERATION_PUT_FILE) + d->uploadSupport = true; + + if (d->cameraAbilities.folder_operations & + GP_FOLDER_OPERATION_MAKE_DIR) + d->mkDirSupport = true; + + if (d->cameraAbilities.folder_operations & + GP_FOLDER_OPERATION_REMOVE_DIR) + d->delDirSupport = true; + + // -- Now try to initialize the camera ----------------- + + m_status = new GPStatus(); + + // Try and initialize the camera to see if its connected + errorCode = gp_camera_init(d->camera, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to initialize camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_camera_unref(d->camera); + d->camera = 0; + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + + d->cameraInitialized = true; + return true; +} + +void GPCamera::cancel() +{ + if (!m_status) + return; + m_status->cancel = true; +} + +void GPCamera::getAllFolders(const TQString& rootFolder, + TQStringList& folderList) +{ + TQStringList subfolders; + getSubFolders(rootFolder, subfolders); + + for (TQStringList::iterator it = subfolders.begin(); + it != subfolders.end(); ++it) + { + *it = rootFolder + TQString(rootFolder.endsWith("/") ? "" : "/") + (*it); + folderList.append(*it); + } + + for (TQStringList::iterator it = subfolders.begin(); + it != subfolders.end(); ++it) + { + getAllFolders(*it, folderList); + } +} + +bool GPCamera::getSubFolders(const TQString& folder, TQStringList& subFolderList) +{ + int errorCode; + CameraList *clist; + gp_list_new(&clist); + + if (m_status) + { + delete m_status; + m_status = 0; + } + m_status = new GPStatus(); + + errorCode = gp_camera_folder_list_folders(d->camera, TQFile::encodeName(folder), clist, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get folders list from camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_list_unref(clist); + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + + int count = gp_list_count(clist); + for (int i = 0 ; i < count ; i++) + { + const char* subFolder; + errorCode = gp_list_get_name(clist, i, &subFolder); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get folder name from camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_list_unref(clist); + return false; + } + + subFolderList.append(TQFile::decodeName(subFolder)); + } + + gp_list_unref(clist); + return true; +} + +bool GPCamera::getItemsList(const TQString& folder, TQStringList& itemsList) +{ + int errorCode; + CameraList *clist; + const char *cname; + + if (m_status) + { + delete m_status; + m_status = 0; + } + m_status = new GPStatus; + + gp_list_new(&clist); + + errorCode = gp_camera_folder_list_files(d->camera, TQFile::encodeName(folder), clist, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get folder files list from camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_list_unref(clist); + delete m_status; + m_status = 0; + return false; + } + + int count = gp_list_count(clist); + for (int i = 0 ; i < count ; i++) + { + errorCode = gp_list_get_name(clist, i, &cname); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get file name from camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_list_unref(clist); + delete m_status; + m_status = 0; + return false; + } + + itemsList.append(TQFile::decodeName(cname)); + } + + gp_list_unref(clist); + + delete m_status; + m_status = 0; + + return true; +} + +bool GPCamera::getItemsInfoList(const TQString& folder, GPItemInfoList& items, bool /*getImageDimensions*/) +{ + int errorCode; + CameraList *clist; + const char *cname; + + if (m_status) + { + delete m_status; + m_status = 0; + } + m_status = new GPStatus; + + gp_list_new(&clist); + + errorCode = gp_camera_folder_list_files(d->camera, TQFile::encodeName(folder), clist, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get folder files list from camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_list_unref(clist); + delete m_status; + m_status = 0; + return false; + } + + int count = gp_list_count(clist); + for (int i = 0 ; i < count ; i++) + { + errorCode = gp_list_get_name(clist, i, &cname); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get file name from camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_list_unref(clist); + delete m_status; + m_status = 0; + return false; + } + + GPItemInfo itemInfo; + + itemInfo.name = TQFile::decodeName(cname); + itemInfo.folder = folder; + + CameraFileInfo info; + gp_camera_file_get_info(d->camera, TQFile::encodeName(folder), + cname, &info, m_status->context); + + itemInfo.mtime = -1; + itemInfo.mime = ""; + itemInfo.size = -1; + itemInfo.width = -1; + itemInfo.height = -1; + itemInfo.downloaded = GPItemInfo::DownloadUnknow; + itemInfo.readPermissions = -1; + itemInfo.writePermissions = -1; + + /* The mime type returned by Gphoto2 is dummy with all RAW files. + if (info.file.fields & GP_FILE_INFO_TYPE) + itemInfo.mime = info.file.type;*/ + + itemInfo.mime = mimeType(TQString(itemInfo.name.section('.', -1)).lower()); + + if (info.file.fields & GP_FILE_INFO_MTIME) + itemInfo.mtime = info.file.mtime; + + if (info.file.fields & GP_FILE_INFO_SIZE) + itemInfo.size = info.file.size; + + if (info.file.fields & GP_FILE_INFO_WIDTH) + itemInfo.width = info.file.width; + + if (info.file.fields & GP_FILE_INFO_HEIGHT) + itemInfo.height = info.file.height; + + if (info.file.fields & GP_FILE_INFO_STATUS) + { + if (info.file.status == GP_FILE_STATUS_DOWNLOADED) + itemInfo.downloaded = GPItemInfo::DownloadedYes; + } + + if (info.file.fields & GP_FILE_INFO_PERMISSIONS) + { + if (info.file.permissions & GP_FILE_PERM_READ) + itemInfo.readPermissions = 1; + else + itemInfo.readPermissions = 0; + if (info.file.permissions & GP_FILE_PERM_DELETE) + itemInfo.writePermissions = 1; + else + itemInfo.writePermissions = 0; + } + + items.append(itemInfo); + } + + gp_list_unref(clist); + + delete m_status; + m_status = 0; + + return true; +} + +bool GPCamera::getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail) +{ + int errorCode; + CameraFile *cfile; + const char *data; + unsigned long int size; + + gp_file_new(&cfile); + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_file_get(d->camera, TQFile::encodeName(folder), + TQFile::encodeName(itemName), + GP_FILE_TYPE_PREVIEW, + cfile, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get camera item!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + + errorCode = gp_file_get_data_and_size(cfile, &data, &size); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get thumbnail from camera item!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + return false; + } + + thumbnail.loadFromData((const uchar*) data, (uint) size); + + gp_file_unref(cfile); + return true; +} + +bool GPCamera::getExif(const TQString& folder, const TQString& itemName, + char **edata, int& esize) +{ + int errorCode; + CameraFile *cfile; + const char *data; + unsigned long int size; + + gp_file_new(&cfile); + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_file_get(d->camera, TQFile::encodeName(folder), + TQFile::encodeName(itemName), + GP_FILE_TYPE_EXIF, + cfile, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get camera item!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + + errorCode = gp_file_get_data_and_size(cfile, &data, &size); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get Exif data from camera item!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + return false; + } + + *edata = new char[size]; + esize = size; + memcpy(*edata, data, size); + + gp_file_unref(cfile); + return true; +} + +bool GPCamera::downloadItem(const TQString& folder, const TQString& itemName, + const TQString& saveFile) +{ + int errorCode; + CameraFile *cfile; + + gp_file_new(&cfile); + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_file_get(d->camera, TQFile::encodeName(folder), + TQFile::encodeName(itemName), + GP_FILE_TYPE_NORMAL, cfile, + m_status->context); + if ( errorCode != GP_OK) + { + DDebug() << "Failed to get camera item!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + + errorCode = gp_file_save(cfile, TQFile::encodeName(saveFile)); + if (errorCode != GP_OK) + { + DDebug() << "Failed to save camera item!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + return false; + } + + gp_file_unref(cfile); + return true; +} + +bool GPCamera::setLockItem(const TQString& folder, const TQString& itemName, bool lock) +{ + int errorCode; + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + CameraFileInfo info; + errorCode = gp_camera_file_get_info(d->camera, TQFile::encodeName(folder), + TQFile::encodeName(itemName), &info, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get camera item properties!" << endl; + printGphotoErrorDescription(errorCode); + delete m_status; + m_status = 0; + return false; + } + + if (info.file.fields & GP_FILE_INFO_PERMISSIONS) + { + if (lock) + { + // Lock the file to set read only flag + info.file.permissions = (CameraFilePermissions)GP_FILE_PERM_READ; + } + else + { + // Unlock the file to set read/write flag + info.file.permissions = (CameraFilePermissions)(GP_FILE_PERM_READ | GP_FILE_PERM_DELETE); + } + } + + // Some gphoto2 drivers need to have only the right flag at on to process properties update in camera. + info.file.fields = GP_FILE_INFO_PERMISSIONS; + info.preview.fields = GP_FILE_INFO_NONE; + info.audio.fields = GP_FILE_INFO_NONE; + + errorCode = gp_camera_file_set_info(d->camera, TQFile::encodeName(folder), + TQFile::encodeName(itemName), info, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to set camera item lock properties!" << endl; + printGphotoErrorDescription(errorCode); + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + return true; +} + +bool GPCamera::deleteItem(const TQString& folder, const TQString& itemName) +{ + int errorCode; + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_file_delete(d->camera, TQFile::encodeName(folder), + TQFile::encodeName(itemName), + m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to delete camera item!" << endl; + printGphotoErrorDescription(errorCode); + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + + return true; +} + +// recursively delete all items +bool GPCamera::deleteAllItems(const TQString& folder) +{ + int errorCode; + TQStringList folderList; + + // Get all subfolders in this folder + getSubFolders(folder, folderList); + + if (folderList.count() > 0) + { + for (unsigned int i = 0 ; i < folderList.count() ; i++) + { + TQString subFolder(folder); + + if (!subFolder.endsWith("/")) + subFolder += '/'; + + subFolder += folderList[i]; + deleteAllItems(subFolder); + } + } + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_folder_delete_all(d->camera, TQFile::encodeName(folder), + m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to delete camera folder!" << endl; + printGphotoErrorDescription(errorCode); + delete m_status; + m_status = 0; + return false; + } + + delete m_status; + m_status = 0; + + return true; +} + +bool GPCamera::uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile, + GPItemInfo& itemInfo, bool /*getImageDimensions*/) +{ + int errorCode; + CameraFile *cfile; + + errorCode = gp_file_new(&cfile); + if (errorCode != GP_OK) + { + DDebug() << "Failed to init new camera file instance!" << endl; + printGphotoErrorDescription(errorCode); + return false; + } + + errorCode = gp_file_open(cfile, TQFile::encodeName(localFile)); + if (errorCode != GP_OK) + { + DDebug() << "Failed to open file!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + return false; + } + + errorCode = gp_file_set_name(cfile, TQFile::encodeName(itemName)); + if (errorCode != GP_OK) + { + DDebug() << "Failed to rename item from camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + return false; + } + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + +#ifdef HAVE_GPHOTO25 + errorCode = gp_camera_folder_put_file(d->camera, + TQFile::encodeName(folder), + TQFile::encodeName(itemName), + GP_FILE_TYPE_NORMAL, + cfile, + m_status->context); +#else + errorCode = gp_camera_folder_put_file(d->camera, + TQFile::encodeName(folder), + cfile, + m_status->context); +#endif + if (errorCode != GP_OK) + { + DDebug() << "Failed to upload item to camera!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + delete m_status; + m_status = 0; + return false; + } + + // Get new camera item information. + + itemInfo.name = itemName; + itemInfo.folder = folder; + + CameraFileInfo info; + errorCode = gp_camera_file_get_info(d->camera, TQFile::encodeName(folder), + TQFile::encodeName(itemName), &info, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get camera item information!" << endl; + printGphotoErrorDescription(errorCode); + gp_file_unref(cfile); + delete m_status; + m_status = 0; + return false; + } + + itemInfo.mtime = -1; + itemInfo.mime = ""; + itemInfo.size = -1; + itemInfo.width = -1; + itemInfo.height = -1; + itemInfo.downloaded = GPItemInfo::DownloadUnknow; + itemInfo.readPermissions = -1; + itemInfo.writePermissions = -1; + + /* The mime type returned by Gphoto2 is dummy with all RAW files. + if (info.file.fields & GP_FILE_INFO_TYPE) + itemInfo.mime = info.file.type;*/ + + itemInfo.mime = mimeType(TQString(itemInfo.name.section('.', -1)).lower()); + + if (info.file.fields & GP_FILE_INFO_MTIME) + itemInfo.mtime = info.file.mtime; + + if (info.file.fields & GP_FILE_INFO_SIZE) + itemInfo.size = info.file.size; + + if (info.file.fields & GP_FILE_INFO_WIDTH) + itemInfo.width = info.file.width; + + if (info.file.fields & GP_FILE_INFO_HEIGHT) + itemInfo.height = info.file.height; + + if (info.file.fields & GP_FILE_INFO_STATUS) + { + if (info.file.status == GP_FILE_STATUS_DOWNLOADED) + itemInfo.downloaded = GPItemInfo::DownloadedYes; + else + itemInfo.downloaded = GPItemInfo::DownloadedNo; + } + + if (info.file.fields & GP_FILE_INFO_PERMISSIONS) + { + if (info.file.permissions & GP_FILE_PERM_READ) + itemInfo.readPermissions = 1; + else + itemInfo.readPermissions = 0; + if (info.file.permissions & GP_FILE_PERM_DELETE) + itemInfo.writePermissions = 1; + else + itemInfo.writePermissions = 0; + } + + gp_file_unref(cfile); + delete m_status; + m_status = 0; + return true; +} + +bool GPCamera::cameraSummary(TQString& summary) +{ + int errorCode; + CameraText sum; + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_get_summary(d->camera, &sum, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get camera summary!" << endl; + printGphotoErrorDescription(errorCode); + delete m_status; + m_status = 0; + return false; + } + + summary = i18n("Title: %1\n" + "Model: %2\n" + "Port: %3\n" + "Path: %4\n\n" + "Thumbnails: %5\n" + "Delete items: %6\n" + "Upload items: %7\n" + "Create directories: %8\n" + "Delete directories: %9\n\n") + .arg(title()) + .arg(model()) + .arg(port()) + .arg(path()) + .arg(thumbnailSupport() ? i18n("yes") : i18n("no")) + .arg(deleteSupport() ? i18n("yes") : i18n("no")) + .arg(uploadSupport() ? i18n("yes") : i18n("no")) + .arg(mkDirSupport() ? i18n("yes") : i18n("no")) + .arg(delDirSupport() ? i18n("yes") : i18n("no")); + + summary.append(TQString(sum.text)); + + delete m_status; + m_status = 0; + return true; +} + +bool GPCamera::cameraManual(TQString& manual) +{ + int errorCode; + CameraText man; + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_get_manual(d->camera, &man, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get camera manual!" << endl; + printGphotoErrorDescription(errorCode); + delete m_status; + m_status = 0; + return false; + } + + manual = TQString(man.text); + + delete m_status; + m_status = 0; + return true; +} + +bool GPCamera::cameraAbout(TQString& about) +{ + int errorCode; + CameraText abt; + + if (m_status) + { + delete m_status; + m_status = 0; + } + + m_status = new GPStatus; + + errorCode = gp_camera_get_about(d->camera, &abt, m_status->context); + if (errorCode != GP_OK) + { + DDebug() << "Failed to get information about camera!" << endl; + printGphotoErrorDescription(errorCode); + delete m_status; + m_status = 0; + return false; + } + + about = TQString(abt.text); + about.append(i18n("\n\nTo report problems about this driver, please contact " + "the gphoto2 team at:\n\nhttp://gphoto.org/bugs")); + + delete m_status; + m_status = 0; + return true; +} + +// -- Static methods --------------------------------------------------------------------- + +void GPCamera::printGphotoErrorDescription(int errorCode) +{ + DDebug() << "Libgphoto2 error: " << gp_result_as_string(errorCode) + << " (" << errorCode << ")" << endl; +} + +void GPCamera::getSupportedCameras(int& count, TQStringList& clist) +{ + clist.clear(); + count = 0; + + CameraAbilitiesList *abilList; + CameraAbilities abil; + GPContext *context; + + context = gp_context_new(); + + gp_abilities_list_new( &abilList ); + gp_abilities_list_load( abilList, context ); + + count = gp_abilities_list_count( abilList ); + if ( count < 0 ) + { + DDebug() << "Failed to get list of cameras!" << endl; + printGphotoErrorDescription(count); + gp_context_unref( context ); + return; + } + else + { + for (int i = 0 ; i < count ; i++) + { + gp_abilities_list_get_abilities( abilList, i, &abil ); + const char *cname = abil.model; + clist.append( TQString( cname ) ); + } + } + + gp_abilities_list_free( abilList ); + gp_context_unref( context ); +} + +void GPCamera::getSupportedPorts(TQStringList& plist) +{ + GPPortInfoList *list; + GPPortInfo info; + + plist.clear(); + + gp_port_info_list_new( &list ); + gp_port_info_list_load( list ); + + int numPorts = gp_port_info_list_count( list ); + if ( numPorts < 0) + { + DDebug() << "Failed to get list of port!" << endl; + printGphotoErrorDescription(numPorts); + gp_port_info_list_free( list ); + return; + } + else + { + for (int i = 0 ; i < numPorts ; i++) + { + gp_port_info_list_get_info( list, i, &info ); +#ifdef HAVE_GPHOTO25 + char *xpath; + gp_port_info_get_name( info, &xpath ); + plist.append( xpath ); +#else + plist.append( info.path ); +#endif + } + } + + gp_port_info_list_free( list ); +} + +void GPCamera::getCameraSupportedPorts(const TQString& model, TQStringList& plist) +{ + int i = 0; + plist.clear(); + + CameraAbilities abilities; + CameraAbilitiesList *abilList; + GPContext *context; + + context = gp_context_new(); + + gp_abilities_list_new (&abilList); + gp_abilities_list_load (abilList, context); + i = gp_abilities_list_lookup_model (abilList, model.local8Bit().data()); + gp_abilities_list_get_abilities (abilList, i, &abilities); + gp_abilities_list_free (abilList); + + if (abilities.port & GP_PORT_SERIAL) + plist.append("serial"); + + if (abilities.port & GP_PORT_USB) + plist.append("usb"); + + gp_context_unref( context ); +} + +int GPCamera::autoDetect(TQString& model, TQString& port) +{ + CameraList *camList; + CameraAbilitiesList *abilList; + GPPortInfoList *infoList; + const char *camModel_, *camPort_; + GPContext *context; + + context = gp_context_new(); + gp_list_new(&camList); + + gp_abilities_list_new(&abilList); + gp_abilities_list_load(abilList, context); + gp_port_info_list_new(&infoList); + gp_port_info_list_load(infoList); + gp_abilities_list_detect(abilList, infoList, camList, context); + gp_abilities_list_free(abilList); + gp_port_info_list_free(infoList); + + gp_context_unref(context); + + int count = gp_list_count(camList); + + if (count <= 0) + { + DDebug() << "Failed to autodetect camera!" << endl; + printGphotoErrorDescription(count); + gp_list_free(camList); + return -1; + } + + camModel_ = 0; + camPort_ = 0; + + for (int i = 0; i < count; i++) + { + if (gp_list_get_name(camList, i, &camModel_) != GP_OK) + { + DDebug() << "Failed to autodetect camera!" << endl; + gp_list_free(camList); + return -1; + } + + if (gp_list_get_value(camList, i, &camPort_) != GP_OK) + { + DDebug() << "Failed to autodetect camera!" << endl; + gp_list_free(camList); + return -1; + } + + if (camModel_ && camPort_) + { + model = TQString::fromLatin1(camModel_); + port = TQString::fromLatin1(camPort_); + gp_list_free(camList); + return 0; + } + } + + DDebug() << "Failed to autodetect camera!" << endl; + gp_list_free(camList); + return -1; +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/gpcamera.h b/src/utilities/cameragui/gpcamera.h new file mode 100644 index 00000000..7071e972 --- /dev/null +++ b/src/utilities/cameragui/gpcamera.h @@ -0,0 +1,107 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-21 + * Description : Gphoto2 camera interface + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef GPCAMERA_H +#define GPCAMERA_H + +// Local includes. + +#include "dkcamera.h" + +class TQImage; + +namespace Digikam +{ + +class GPCameraPrivate; +class GPStatus; + +// Gphoto2 camera Implementation of abstract type DKCamera + +class GPCamera : public DKCamera +{ + +public: + + GPCamera(const TQString& title, const TQString& model, + const TQString& port, const TQString& path); + ~GPCamera(); + + bool thumbnailSupport(); + bool deleteSupport(); + bool uploadSupport(); + bool mkDirSupport(); + bool delDirSupport(); + + bool doConnect(); + + void cancel(); + + void getAllFolders(const TQString& folder, TQStringList& subFolderList); + bool getSubFolders(const TQString& folder, TQStringList& subFolderList); + bool getItemsList(const TQString& folder, TQStringList& itemsList); + bool getItemsInfoList(const TQString& folder, GPItemInfoList& items, bool getImageDimensions = true); + bool getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail); + bool getExif(const TQString& folder, const TQString& itemName, char **edata, int& esize); + + bool setLockItem(const TQString& folder, const TQString& itemName, bool lock); + + bool downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile); + bool deleteItem(const TQString& folder, const TQString& itemName); + + // recursively delete all items + bool deleteAllItems(const TQString& folder); + + bool uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile, + GPItemInfo& itemInfo, bool getImageDimensions=true); + + bool cameraSummary(TQString& summary); + bool cameraManual(TQString& manual); + bool cameraAbout(TQString& about); + + TQString model() const; + TQString port() const; + TQString path() const; + + // Public static methods shared with Camera Setup + + static int autoDetect(TQString& model, TQString& port); + static void getSupportedCameras(int& count, TQStringList& clist); + static void getSupportedPorts(TQStringList& plist); + static void getCameraSupportedPorts(const TQString& model, TQStringList& plist); + +private: + + int setup(); + static void printGphotoErrorDescription(int errorCode); + +private: + + GPCameraPrivate *d; + GPStatus *m_status; +}; + +} // namespace Digikam + +#endif /* GPCAMERA_H */ diff --git a/src/utilities/cameragui/gpiteminfo.cpp b/src/utilities/cameragui/gpiteminfo.cpp new file mode 100644 index 00000000..3a1d53e1 --- /dev/null +++ b/src/utilities/cameragui/gpiteminfo.cpp @@ -0,0 +1,68 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-19 + * Description : camera item info container + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqdatastream.h> + +// Local includes. + +#include "gpiteminfo.h" + +namespace Digikam +{ + +TQDataStream& operator<<( TQDataStream& ds, const GPItemInfo& info) +{ + ds << info.name; + ds << info.folder; + ds << info.mtime; + ds << info.mime; + ds << info.size; + ds << info.width; + ds << info.height; + ds << info.downloaded; + ds << info.readPermissions; + ds << info.writePermissions; + + return ds; +} + +TQDataStream& operator>>(TQDataStream& ds, GPItemInfo& info) +{ + ds >> info.name; + ds >> info.folder; + ds >> info.mtime; + ds >> info.mime; + ds >> info.size; + ds >> info.width; + ds >> info.height; + ds >> info.downloaded; + ds >> info.readPermissions; + ds >> info.writePermissions; + + return ds; +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/gpiteminfo.h b/src/utilities/cameragui/gpiteminfo.h new file mode 100644 index 00000000..02b28693 --- /dev/null +++ b/src/utilities/cameragui/gpiteminfo.h @@ -0,0 +1,80 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-18 + * Description : camera item info container + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef GPITEMINFO_H +#define GPITEMINFO_H + +// C++ includes. + +#include <ctime> + +// TQt includes. + +#include <tqvaluelist.h> +#include <tqcstring.h> + +class TQDataStream; + +namespace Digikam +{ + +class GPItemInfo +{ + +public: + + enum DownloadStatus + { + DownloadUnknow = -1, + DownloadedNo = 0, + DownloadedYes = 1, + DownloadFailed = 2, + DownloadStarted = 3, + NewPicture = 4 + }; + +public: + + long size; + int width; + int height; + int downloaded; // See DownloadStatus enum. + int readPermissions; + int writePermissions; + + TQString name; + TQString folder; + TQString mime; + + time_t mtime; +}; + +TQDataStream& operator<<( TQDataStream &, const GPItemInfo & ); +TQDataStream& operator>>( TQDataStream &, GPItemInfo & ); + +typedef TQValueList<GPItemInfo> GPItemInfoList; + +} // namespace Digikam + +#endif /* GPITEMINFO_H */ diff --git a/src/utilities/cameragui/mtqueue.h b/src/utilities/cameragui/mtqueue.h new file mode 100644 index 00000000..0fb80e5c --- /dev/null +++ b/src/utilities/cameragui/mtqueue.h @@ -0,0 +1,116 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-30 + * Description : camera download multi-threading handler. + * + * Copyright (C) 2004 by Renchi Raju <[email protected]> + + * 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, 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. + * + * ============================================================ */ + +#ifndef COMMAND_QUEUE_H +#define COMMAND_QUEUE_H + +// TQt includes. + +#include <tqptrqueue.h> +#include <tqmutex.h> + +namespace Digikam +{ + +template<class Type> class MTQueue +{ + +public: + + MTQueue() + { + queue_.setAutoDelete(true); + } + + ~MTQueue() + { + flush(); + } + + bool isEmpty() + { + mutex_.lock(); + bool empty = queue_.isEmpty(); + mutex_.unlock(); + return empty; + } + + void flush() + { + mutex_.lock(); + queue_.clear(); + mutex_.unlock(); + } + + void enqueue(Type * t) + { + mutex_.lock(); + queue_.enqueue(t); + mutex_.unlock(); + } + + Type * dequeue() + { + mutex_.lock(); + Type * i = queue_.dequeue(); + mutex_.unlock(); + return i; + } + + Type * head(bool lock=true) + { + if (lock) + mutex_.lock(); + Type * i = queue_.head(); + if (lock) + mutex_.unlock(); + return i; + } + + int count() + { + mutex_.lock(); + int c = queue_.count(); + mutex_.unlock(); + return c; + } + + void lock() + { + mutex_.lock(); + } + + void unlock() + { + mutex_.unlock(); + } + +private: + + TQPtrQueue<Type> queue_; + TQMutex mutex_; +}; + +} // namespace Digikam + +#endif // COMMAND_QUEUE_H diff --git a/src/utilities/cameragui/renamecustomizer.cpp b/src/utilities/cameragui/renamecustomizer.cpp new file mode 100644 index 00000000..a906ccb1 --- /dev/null +++ b/src/utilities/cameragui/renamecustomizer.cpp @@ -0,0 +1,532 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-19 + * Description : a options group to set renaming files + * operations during camera downloading + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqdatetime.h> +#include <tqlayout.h> +#include <tqradiobutton.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqhbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqtimer.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeconfig.h> +#include <tdeapplication.h> +#include <kiconloader.h> +#include <klineedit.h> +#include <knuminput.h> +#include <kdialogbase.h> +#if KDE_IS_VERSION(3,2,0) +#include <kinputdialog.h> +#else +#include <klineeditdlg.h> +#endif + +// Local includes. + +#include "renamecustomizer.h" +#include "renamecustomizer.moc" + +namespace Digikam +{ + +class RenameCustomizerPriv +{ +public: + + enum DateFormatOptions + { + DigikamStandard = 0, + IsoDateFormat, + TextDateFormat, + LocalDateFormat, + Advanced + }; + + RenameCustomizerPriv() + { + renameDefault = 0; + renameCustom = 0; + renameDefaultBox = 0; + renameCustomBox = 0; + renameDefaultCase = 0; + renameDefaultCaseType = 0; + addDateTimeBox = 0; + addCameraNameBox = 0; + addSeqNumberBox = 0; + changedTimer = 0; + renameCustomPrefix = 0; + renameCustomSuffix = 0; + startIndexLabel = 0; + startIndexInput = 0; + focusedWidget = 0; + dateTimeButton = 0; + dateTimeLabel = 0; + dateTimeFormat = 0; +} + + TQWidget *focusedWidget; + + TQString cameraTitle; + + TQRadioButton *renameDefault; + TQRadioButton *renameCustom; + + TQGroupBox *renameDefaultBox; + TQGroupBox *renameCustomBox; + + TQLabel *renameDefaultCase; + TQLabel *startIndexLabel; + TQLabel *dateTimeLabel; + + TQComboBox *renameDefaultCaseType; + TQComboBox *dateTimeFormat; + + TQCheckBox *addDateTimeBox; + TQCheckBox *addCameraNameBox; + TQCheckBox *addSeqNumberBox; + + TQPushButton *dateTimeButton; + TQString dateTimeFormatString; + + TQTimer *changedTimer; + + KLineEdit *renameCustomPrefix; + KLineEdit *renameCustomSuffix; + + KIntNumInput *startIndexInput; +}; + +RenameCustomizer::RenameCustomizer(TQWidget* parent, const TQString& cameraTitle) + : TQButtonGroup(parent) +{ + d = new RenameCustomizerPriv; + d->changedTimer = new TQTimer(this); + d->cameraTitle = cameraTitle; + + setFrameStyle( TQFrame::NoFrame ); + setRadioButtonExclusive(true); + setColumnLayout(0, TQt::Vertical); + TQGridLayout* mainLayout = new TQGridLayout(layout(), 4, 1); + + // ---------------------------------------------------------------- + + d->renameDefault = new TQRadioButton(i18n("Camera filenames"), this); + TQWhatsThis::add( d->renameDefault, i18n("<p>Turn on this option to use camera " + "provided image filenames without modifications.")); + mainLayout->addMultiCellWidget(d->renameDefault, 0, 0, 0, 1); + + d->renameDefaultBox = new TQGroupBox( this ); + d->renameDefaultBox->setFrameStyle(TQFrame::NoFrame|TQFrame::Plain); + d->renameDefaultBox->setInsideMargin(0); + d->renameDefaultBox->setColumnLayout(0, TQt::Vertical); + + d->renameDefaultCase = new TQLabel( i18n("Change case to:"), d->renameDefaultBox ); + d->renameDefaultCase->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + + d->renameDefaultCaseType = new TQComboBox( d->renameDefaultBox ); + d->renameDefaultCaseType->insertItem(i18n("Leave as Is"), 0); + d->renameDefaultCaseType->insertItem(i18n("Upper"), 1); + d->renameDefaultCaseType->insertItem(i18n("Lower"), 2); + d->renameDefaultCaseType->setSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Preferred); + TQWhatsThis::add( d->renameDefaultCaseType, i18n("<p>Set the method to use to change the case " + "of image filenames.")); + + TQHBoxLayout* boxLayout1 = new TQHBoxLayout( d->renameDefaultBox->layout() ); + boxLayout1->addSpacing( 10 ); + boxLayout1->addWidget( d->renameDefaultCase ); + boxLayout1->addWidget( d->renameDefaultCaseType ); + + mainLayout->addMultiCellWidget(d->renameDefaultBox, 1, 1, 0, 1); + + // ------------------------------------------------------------- + + d->renameCustom = new TQRadioButton(i18n("Customize"), this); + mainLayout->addMultiCellWidget(d->renameCustom, 2, 2, 0, 1); + TQWhatsThis::add( d->renameCustom, i18n("<p>Turn on this option to customize image filenames " + "during download.")); + + d->renameCustomBox = new TQGroupBox(this); + d->renameCustomBox->setFrameStyle(TQFrame::NoFrame|TQFrame::Plain); + d->renameCustomBox->setInsideMargin(0); + d->renameCustomBox->setColumnLayout(0, TQt::Vertical); + + TQGridLayout* renameCustomBoxLayout = new TQGridLayout(d->renameCustomBox->layout(), + 6, 2, KDialogBase::spacingHint()); + renameCustomBoxLayout->setColSpacing( 0, 10 ); + + TQLabel* prefixLabel = new TQLabel(i18n("Prefix:"), d->renameCustomBox); + renameCustomBoxLayout->addMultiCellWidget(prefixLabel, 0, 0, 1, 1); + d->renameCustomPrefix = new KLineEdit(d->renameCustomBox); + d->focusedWidget = d->renameCustomPrefix; + renameCustomBoxLayout->addMultiCellWidget(d->renameCustomPrefix, 0, 0, 2, 2); + TQWhatsThis::add( d->renameCustomPrefix, i18n("<p>Set the prefix which will be added to " + "image filenames.")); + + TQLabel* suffixLabel = new TQLabel(i18n("Suffix:"), d->renameCustomBox); + renameCustomBoxLayout->addMultiCellWidget(suffixLabel, 1, 1, 1, 1); + d->renameCustomSuffix = new KLineEdit(d->renameCustomBox); + renameCustomBoxLayout->addMultiCellWidget(d->renameCustomSuffix, 1, 1, 2, 2); + TQWhatsThis::add( d->renameCustomSuffix, i18n("<p>Set the suffix which will be added to " + "image filenames.")); + + d->addDateTimeBox = new TQCheckBox( i18n("Add Date && Time"), d->renameCustomBox ); + renameCustomBoxLayout->addMultiCellWidget(d->addDateTimeBox, 2, 2, 1, 2); + TQWhatsThis::add( d->addDateTimeBox, i18n("<p>Set this option to add the camera provided date and time.")); + + TQWidget *dateTimeWidget = new TQWidget(d->renameCustomBox); + d->dateTimeLabel = new TQLabel(i18n("Date format:"), dateTimeWidget); + d->dateTimeFormat = new TQComboBox(dateTimeWidget); + d->dateTimeFormat->insertItem(i18n("Standard"), RenameCustomizerPriv::DigikamStandard); + d->dateTimeFormat->insertItem(i18n("ISO"), RenameCustomizerPriv::IsoDateFormat); + d->dateTimeFormat->insertItem(i18n("Full Text"), RenameCustomizerPriv::TextDateFormat); + d->dateTimeFormat->insertItem(i18n("Local Settings"), RenameCustomizerPriv::LocalDateFormat); + d->dateTimeFormat->insertItem(i18n("Advanced..."), RenameCustomizerPriv::Advanced); + TQWhatsThis::add( d->dateTimeFormat, i18n("<p>Select your preferred date format for " + "creating new albums. The options available are:</p>" + "<p><b>Standard</b>: the date format that has been used as a standard by digiKam. " + "E.g.: <i>20060824T142618</i></p>" + "<p/><b>ISO</b>: the date format according to ISO 8601 " + "(YYYY-MM-DD). E.g.: <i>2006-08-24T14:26:18</i></p>" + "<p><b>Full Text</b>: the date format is a user-readable string. " + "E.g.: <i>Thu Aug 24 14:26:18 2006</i></p>" + "<p><b>Local Settings</b>: the date format depending on TDE control panel settings.</p>" + "<p><b>Advanced:</b> allows the user to specify a custom date format.</p>")); + d->dateTimeButton = new TQPushButton(SmallIcon("configure"), TQString(), dateTimeWidget); + TQSizePolicy policy = d->dateTimeButton->sizePolicy(); + policy.setHorData(TQSizePolicy::Maximum); + d->dateTimeButton->setSizePolicy(policy); + TQHBoxLayout *boxLayout2 = new TQHBoxLayout(dateTimeWidget); + boxLayout2->addWidget(d->dateTimeLabel); + boxLayout2->addWidget(d->dateTimeFormat); + boxLayout2->addWidget(d->dateTimeButton); + renameCustomBoxLayout->addMultiCellWidget(dateTimeWidget, 3, 3, 1, 2); + + d->addCameraNameBox = new TQCheckBox( i18n("Add Camera Name"), d->renameCustomBox ); + renameCustomBoxLayout->addMultiCellWidget(d->addCameraNameBox, 4, 4, 1, 2); + TQWhatsThis::add( d->addCameraNameBox, i18n("<p>Set this option to add the camera name.")); + + d->addSeqNumberBox = new TQCheckBox( i18n("Add Sequence Number"), d->renameCustomBox ); + renameCustomBoxLayout->addMultiCellWidget(d->addSeqNumberBox, 5, 5, 1, 2); + TQWhatsThis::add( d->addSeqNumberBox, i18n("<p>Set this option to add a sequence number " + "starting with the index set below.")); + + d->startIndexLabel = new TQLabel( i18n("Start Index:"), d->renameCustomBox ); + d->startIndexInput = new KIntNumInput(1, d->renameCustomBox); + d->startIndexInput->setRange(1, 900000, 1, false); + TQWhatsThis::add( d->startIndexInput, i18n("<p>Set the starting index value used to rename " + "files with a sequence number.")); + + renameCustomBoxLayout->addMultiCellWidget(d->startIndexLabel, 6, 6, 1, 1); + renameCustomBoxLayout->addMultiCellWidget(d->startIndexInput, 6, 6, 2, 2); + + mainLayout->addMultiCellWidget(d->renameCustomBox, 3, 3, 0, 1); + mainLayout->setRowStretch(4, 10); + + // -- setup connections ------------------------------------------------- + + connect(this, TQ_SIGNAL(clicked(int)), + this, TQ_SLOT(slotRadioButtonClicked(int))); + + connect(d->renameCustomPrefix, TQ_SIGNAL(textChanged(const TQString&)), + this, TQ_SLOT(slotRenameOptionsChanged())); + + connect(d->renameCustomSuffix, TQ_SIGNAL(textChanged(const TQString&)), + this, TQ_SLOT(slotRenameOptionsChanged())); + + connect(d->addDateTimeBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotRenameOptionsChanged())); + + connect(d->addCameraNameBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotRenameOptionsChanged())); + + connect(d->addSeqNumberBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotRenameOptionsChanged())); + + connect(d->renameDefaultCaseType, TQ_SIGNAL(activated(const TQString&)), + this, TQ_SLOT(slotRenameOptionsChanged())); + + connect(d->startIndexInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotRenameOptionsChanged())); + + connect(d->changedTimer, TQ_SIGNAL(timeout()), + this, TQ_SIGNAL(signalChanged())); + + connect(d->dateTimeButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotDateTimeButtonClicked())); + + connect(d->dateTimeFormat, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotDateTimeFormatChanged(int))); + + connect(d->addDateTimeBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotDateTimeBoxToggled(bool))); + + // -- initial values --------------------------------------------------- + + readSettings(); + + // signal to this not yet connected when readSettings is called? Don't know + slotDateTimeBoxToggled(d->addDateTimeBox->isChecked()); +} + +RenameCustomizer::~RenameCustomizer() +{ + delete d->changedTimer; + saveSettings(); + delete d; +} + +bool RenameCustomizer::useDefault() const +{ + return d->renameDefault->isChecked(); +} + +int RenameCustomizer::startIndex() const +{ + return d->startIndexInput->value(); +} + +TQString RenameCustomizer::newName(const TQDateTime &dateTime, int index, const TQString &extension) const +{ + if (d->renameDefault->isChecked()) + return TQString(); + else + { + TQString name(d->renameCustomPrefix->text()); + + // use the "T" as a delimiter between date and time + TQString date; + switch (d->dateTimeFormat->currentItem()) + { + case RenameCustomizerPriv::DigikamStandard: + date = dateTime.toString("yyyyMMddThhmmss"); + break; + case RenameCustomizerPriv::TextDateFormat: + date = dateTime.toString(TQt::TextDate); + break; + case RenameCustomizerPriv::LocalDateFormat: + date = dateTime.toString(TQt::LocalDate); + break; + case RenameCustomizerPriv::IsoDateFormat: + date = dateTime.toString(TQt::ISODate); + break; + case RenameCustomizerPriv::Advanced: + date = dateTime.toString(d->dateTimeFormatString); + break; + } + + // it seems that TQString::number does not support padding with zeros + TQString seq; + seq.sprintf("-%06d", index); + + if (d->addDateTimeBox->isChecked()) + name += date; + + if (d->addSeqNumberBox->isChecked()) + name += seq; + + if (d->addCameraNameBox->isChecked()) + name += TQString("-%1").arg(d->cameraTitle.simplifyWhiteSpace().replace(" ", "")); + + name += d->renameCustomSuffix->text(); + name += extension; + + return name; + } +} + +RenameCustomizer::Case RenameCustomizer::changeCase() const +{ + RenameCustomizer::Case type = NONE; + + if (d->renameDefaultCaseType->currentItem() == 1) + type=UPPER; + if (d->renameDefaultCaseType->currentItem() == 2) + type=LOWER; + + return type; +} + +void RenameCustomizer::slotRadioButtonClicked(int) +{ + TQRadioButton* btn = dynamic_cast<TQRadioButton*>(selected()); + if (!btn) + return; + + d->renameCustomBox->setEnabled( btn != d->renameDefault ); + d->renameDefaultBox->setEnabled( btn == d->renameDefault ); + slotRenameOptionsChanged(); +} + +void RenameCustomizer::slotRenameOptionsChanged() +{ + d->focusedWidget = focusWidget(); + + if (d->addSeqNumberBox->isChecked()) + { + d->startIndexInput->setEnabled(true); + d->startIndexLabel->setEnabled(true); + } + else + { + d->startIndexInput->setEnabled(false); + d->startIndexLabel->setEnabled(false); + } + + d->changedTimer->start(500, true); +} + +void RenameCustomizer::slotDateTimeBoxToggled(bool on) +{ + d->dateTimeLabel->setEnabled(on); + d->dateTimeFormat->setEnabled(on); + d->dateTimeButton->setEnabled(on + && d->dateTimeFormat->currentItem() == RenameCustomizerPriv::Advanced); + slotRenameOptionsChanged(); +} + +void RenameCustomizer::slotDateTimeFormatChanged(int index) +{ + if (index == RenameCustomizerPriv::Advanced) + { + d->dateTimeButton->setEnabled(true); + //d->dateTimeButton->show(); + //slotDateTimeButtonClicked(); + } + else + { + d->dateTimeButton->setEnabled(false); + //d->dateTimeButton->hide(); + } + slotRenameOptionsChanged(); +} + +void RenameCustomizer::slotDateTimeButtonClicked() +{ + bool ok; + TQString message = i18n("<qt><p>Enter the format for date and time.</p>" + "<p>Use <i>dd</i> for the day, " + "<i>MM</i> for the month, " + "<i>yyyy</i> for the year, " + "<i>hh</i> for the hour, " + "<i>mm</i> for the minute, " + "<i>ss</i> for the second.</p>" + "<p>Examples: <i>yyyyMMddThhmmss</i> " + "for 20060824T142418,<br>" + "<i>yyyy-MM-dd hh:mm:ss</i> " + "for 2006-08-24 14:24:18.</p></qt>"); + +#if KDE_IS_VERSION(3,2,0) + TQString newFormat = KInputDialog::getText(i18n("Change Date and Time Format"), + message, + d->dateTimeFormatString, &ok, this); +#else + TQString newFormat = KLineEditDlg::getText(i18n("Change Date and Time Format"), + message, + d->dateTimeFormatString, &ok, this); +#endif + + if (!ok) + return; + + d->dateTimeFormatString = newFormat; + slotRenameOptionsChanged(); +} + +void RenameCustomizer::readSettings() +{ + TDEConfig* config = kapp->config(); + + config->setGroup("Camera Settings"); + bool def = config->readBoolEntry("Rename Use Default", true); + bool addSeqNumb = config->readBoolEntry("Add Sequence Number", true); + bool adddateTime = config->readBoolEntry("Add Date Time", false); + bool addCamName = config->readBoolEntry("Add Camera Name", false); + int chcaseT = config->readNumEntry("Case Type", NONE); + TQString prefix = config->readEntry("Rename Prefix", i18n("photo")); + TQString suffix = config->readEntry("Rename Postfix", TQString()); + int startIndex = config->readNumEntry("Rename Start Index", 1); + int dateTime = config->readNumEntry("Date Time Format", RenameCustomizerPriv::IsoDateFormat); + TQString format = config->readEntry("Date Time Format String", "yyyyMMddThhmmss"); + + if (def) + { + d->renameDefault->setChecked(true); + d->renameCustom->setChecked(false); + d->renameCustomBox->setEnabled(false); + d->renameDefaultBox->setEnabled(true); + } + else + { + d->renameDefault->setChecked(false); + d->renameCustom->setChecked(true); + d->renameCustomBox->setEnabled(true); + d->renameDefaultBox->setEnabled(false); + } + + d->addDateTimeBox->setChecked(adddateTime); + d->addCameraNameBox->setChecked(addCamName); + d->addSeqNumberBox->setChecked(addSeqNumb); + d->renameDefaultCaseType->setCurrentItem(chcaseT); + d->renameCustomPrefix->setText(prefix); + d->renameCustomSuffix->setText(suffix); + d->startIndexInput->setValue(startIndex); + d->dateTimeFormat->setCurrentItem(dateTime); + d->dateTimeFormatString = format; + slotRenameOptionsChanged(); +} + +void RenameCustomizer::saveSettings() +{ + TDEConfig* config = kapp->config(); + + config->setGroup("Camera Settings"); + config->writeEntry("Rename Use Default", d->renameDefault->isChecked()); + config->writeEntry("Add Camera Name", d->addCameraNameBox->isChecked()); + config->writeEntry("Add Date Time", d->addDateTimeBox->isChecked()); + config->writeEntry("Add Sequence Number", d->addSeqNumberBox->isChecked()); + config->writeEntry("Case Type", d->renameDefaultCaseType->currentItem()); + config->writeEntry("Rename Prefix", d->renameCustomPrefix->text()); + config->writeEntry("Rename Suffix", d->renameCustomSuffix->text()); + config->writeEntry("Rename Start Index", d->startIndexInput->value()); + config->writeEntry("Date Time Format", d->dateTimeFormat->currentItem()); + config->writeEntry("Date Time Format String", d->dateTimeFormatString); + config->sync(); +} + +void RenameCustomizer::restoreFocus() +{ + d->focusedWidget->setFocus(); +} + +} // namespace Digikam + diff --git a/src/utilities/cameragui/renamecustomizer.h b/src/utilities/cameragui/renamecustomizer.h new file mode 100644 index 00000000..47ad925b --- /dev/null +++ b/src/utilities/cameragui/renamecustomizer.h @@ -0,0 +1,91 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-19 + * Description : a options group to set renaming files + * operations during camera downloading + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef RENAMECUSTOMIZER_H +#define RENAMECUSTOMIZER_H + +// TQt includes. + +#include <tqbuttongroup.h> + +class TQDateTime; + +namespace Digikam +{ + +class RenameCustomizerPriv; + +class RenameCustomizer : public TQButtonGroup +{ + TQ_OBJECT + + +public: + + enum Case + { + NONE = 0, + UPPER, + LOWER + }; + + RenameCustomizer(TQWidget* parent, const TQString& cameraTitle); + ~RenameCustomizer(); + + void setUseDefault(bool val); + bool useDefault() const; + TQString newName(const TQDateTime &date, int index, const TQString &extension) const; + Case changeCase() const; + int startIndex() const; + +signals: + + void signalChanged(); + +public slots: + + void restoreFocus(); + +private: + + void readSettings(); + void saveSettings(); + +private slots: + + void slotRadioButtonClicked(int); + void slotRenameOptionsChanged(); + void slotDateTimeBoxToggled(bool); + void slotDateTimeFormatChanged(int); + void slotDateTimeButtonClicked(); + +private: + + RenameCustomizerPriv *d; +}; + +} // namespace Digikam + +#endif /* RENAMECUSTOMIZER_H */ diff --git a/src/utilities/cameragui/umscamera.cpp b/src/utilities/cameragui/umscamera.cpp new file mode 100644 index 00000000..537c29ba --- /dev/null +++ b/src/utilities/cameragui/umscamera.cpp @@ -0,0 +1,519 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-21 + * Description : USB Mass Storage camera interface + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +// C Ansi includes. + +extern "C" +{ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <utime.h> +} + +// TQt includes. + +#include <tqdir.h> +#include <tqfileinfo.h> +#include <tqfile.h> +#include <tqstringlist.h> +#include <tqdeepcopy.h> +#include <tqwmatrix.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdefilemetainfo.h> + +// LibKDcraw includes. + +#include <libkdcraw/kdcraw.h> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dmetadata.h" +#include "umscamera.h" + +namespace Digikam +{ + +UMSCamera::UMSCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path) + : DKCamera(title, model, port, path) +{ + m_cancel = false; +} + +UMSCamera::~UMSCamera() +{ +} + +bool UMSCamera::doConnect() +{ + return true; +} + +void UMSCamera::cancel() +{ + // set the cancel flag + m_cancel = true; +} + +void UMSCamera::getAllFolders(const TQString& folder, TQStringList& subFolderList) +{ + m_cancel = false; + subFolderList.clear(); + subFolderList.append(folder); + listFolders(folder, subFolderList); +} + +bool UMSCamera::getItemsInfoList(const TQString& folder, GPItemInfoList& infoList, bool getImageDimensions) +{ + m_cancel = false; + infoList.clear(); + + TQDir dir(folder); + dir.setFilter(TQDir::Files); + + const TQFileInfoList *list = dir.entryInfoList(); + if (!list) + return false; + + TQFileInfoListIterator it(*list); + TQFileInfo *fi; + TQFileInfo thmlo, thmup; + DMetadata meta; + + while ((fi = it.current()) != 0 && !m_cancel) + { + ++it; + + TQString mime = mimeType(fi->extension(false).lower()); + + if (!mime.isEmpty()) + { + TQSize dims; + TQDateTime dt; + GPItemInfo info; + thmlo.setFile(folder + TQString("/") + fi->baseName() + TQString(".thm")); + thmup.setFile(folder + TQString("/") + fi->baseName() + TQString(".THM")); + + if (thmlo.exists()) + { + // Try thumbnail sidecar files with lowercase extension. + meta.load(thmlo.filePath()); + dt = meta.getImageDateTime(); + dims = meta.getImageDimensions(); + } + else if (thmup.exists()) + { + // Try thumbnail sidecar files with uppercase extension. + meta.load(thmup.filePath()); + dt = meta.getImageDateTime(); + dims = meta.getImageDimensions(); + } + else if (mime == TQString("image/x-raw")) + { + // If no thumbnail sidecar file available , try to load image metadata with Raw files. + meta.load(fi->filePath()); + dt = meta.getImageDateTime(); + dims = meta.getImageDimensions(); + } + else + { + meta.load(fi->filePath()); + dt = meta.getImageDateTime(); + dims = meta.getImageDimensions(); + + if (dims.isNull()) + { + // In all others case, try KFileMetaInfo. + KFileMetaInfo kmeta(fi->filePath()); + if (kmeta.isValid()) + { + if (kmeta.containsGroup("Jpeg EXIF Data")) + dims = kmeta.group("Jpeg EXIF Data").item("Dimensions").value().toSize(); + else if (kmeta.containsGroup("General")) + dims = kmeta.group("General").item("Dimensions").value().toSize(); + else if (kmeta.containsGroup("Technical")) + dims = kmeta.group("Technical").item("Dimensions").value().toSize(); + } + } + } + + if (dt.isNull()) + { + // If date is not found in metadata, use file time stamp + dt = fi->created(); + } + + info.name = fi->fileName(); + info.folder = !folder.endsWith("/") ? folder + TQString("/") : folder; + info.mime = mime; + info.mtime = dt.toTime_t(); + info.size = fi->size(); + info.width = getImageDimensions ? dims.width() : -1; + info.height = getImageDimensions ? dims.height() : -1; + info.downloaded = GPItemInfo::DownloadUnknow; + info.readPermissions = fi->isReadable(); + info.writePermissions = fi->isWritable(); + + infoList.append(info); + } + } + + return true; +} + +bool UMSCamera::getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail) +{ + m_cancel = false; + + // JPEG files: try to get thumbnail from Exif data. + + DMetadata metadata(TQFile::encodeName(folder + TQString("/") + itemName)); + thumbnail = metadata.getExifThumbnail(true); + if (!thumbnail.isNull()) + return true; + + // RAW files : try to extract embedded thumbnail using dcraw + + KDcrawIface::KDcraw::loadDcrawPreview(thumbnail, TQString(folder + TQString("/") + itemName)); + if (!thumbnail.isNull()) + return true; + + // THM files: try to get thumbnail from '.thm' files if we didn't manage to get + // thumbnail from Exif. Any cameras provides *.thm files like JPEG files with RAW/video files. + // Using this way speed up thumbnailization and limit data transfered between camera and computer. + // NOTE: the thumbnail extracted with this method can provide a poor quality preview. + + TQFileInfo fi(folder + TQString("/") + itemName); + + if (thumbnail.load(folder + TQString("/") + fi.baseName() + TQString(".thm"))) // Lowercase + { + if (!thumbnail.isNull()) + return true; + } + else if (thumbnail.load(folder + TQString("/") + fi.baseName() + TQString(".THM"))) // Uppercase + { + if (!thumbnail.isNull()) + return true; + } + + // Finaly, we trying to get thumbnail using DImg API (slow). + + DImg dimgThumb(TQCString(TQFile::encodeName(folder + TQString("/") + itemName))); + + if (!dimgThumb.isNull()) + { + thumbnail = dimgThumb.copyTQImage(); + return true; + } + + return false; +} + +bool UMSCamera::getExif(const TQString&, const TQString&, char **, int&) +{ + // not necessary to implement this. read it directly from the file + // (done in camera controller) + DWarning() << "exif implemented yet in camera controller" << endl; + return false; +} + +bool UMSCamera::downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile) +{ + m_cancel = false; + TQString src = folder + TQString("/") + itemName; + TQString dest = saveFile; + + TQFile sFile(src); + TQFile dFile(dest); + + if ( !sFile.open(IO_ReadOnly) ) + { + DWarning() << "Failed to open source file for reading: " + << src << endl; + return false; + } + + if ( !dFile.open(IO_WriteOnly) ) + { + sFile.close(); + DWarning() << "Failed to open dest file for writing: " + << dest << endl; + return false; + } + + const int MAX_IPC_SIZE = (1024*32); + char buffer[MAX_IPC_SIZE]; + + TQ_LONG len; + while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel) + { + if (len == -1 || dFile.writeBlock(buffer, (TQ_ULONG)len) != len) + { + sFile.close(); + dFile.close(); + return false; + } + } + + sFile.close(); + dFile.close(); + + // set the file modification time of the downloaded file to that + // of the original file + struct stat st; + ::stat(TQFile::encodeName(src), &st); + + struct utimbuf ut; + ut.modtime = st.st_mtime; + ut.actime = st.st_atime; + + ::utime(TQFile::encodeName(dest), &ut); + + return true; +} + +bool UMSCamera::setLockItem(const TQString& folder, const TQString& itemName, bool lock) +{ + TQString src = folder + TQString("/") + itemName; + + if (lock) + { + // Lock the file to set read only flag + if (::chmod(TQFile::encodeName(src), S_IREAD) == -1) + return false; + } + else + { + // Unlock the file to set read/write flag + if (::chmod(TQFile::encodeName(src), S_IREAD | S_IWRITE) == -1) + return false; + } + + return true; +} + +bool UMSCamera::deleteItem(const TQString& folder, const TQString& itemName) +{ + m_cancel = false; + + // Any camera provide THM (thumbnail) file with real image. We need to remove it also. + + TQFileInfo fi(folder + TQString("/") + itemName); + + TQFileInfo thmLo(folder + TQString("/") + fi.baseName() + ".thm"); // Lowercase + + if (thmLo.exists()) + ::unlink(TQFile::encodeName(thmLo.filePath())); + + TQFileInfo thmUp(folder + TQString("/") + fi.baseName() + ".THM"); // Uppercase + + if (thmUp.exists()) + ::unlink(TQFile::encodeName(thmUp.filePath())); + + // Remove the real image. + return (::unlink(TQFile::encodeName(folder + TQString("/") + itemName)) == 0); +} + +bool UMSCamera::uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile, + GPItemInfo& info, bool getImageDimensions) +{ + m_cancel = false; + TQString dest = folder + TQString("/") + itemName; + TQString src = localFile; + + TQFile sFile(src); + TQFile dFile(dest); + + if ( !sFile.open(IO_ReadOnly) ) + { + DWarning() << "Failed to open source file for reading: " + << src << endl; + return false; + } + + if ( !dFile.open(IO_WriteOnly) ) + { + sFile.close(); + DWarning() << "Failed to open dest file for writing: " + << dest << endl; + return false; + } + + const int MAX_IPC_SIZE = (1024*32); + char buffer[MAX_IPC_SIZE]; + + TQ_LONG len; + while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel) + { + if (len == -1 || dFile.writeBlock(buffer, (TQ_ULONG)len) == -1) + { + sFile.close(); + dFile.close(); + return false; + } + } + + sFile.close(); + dFile.close(); + + // set the file modification time of the uploaded file to that + // of the original file + struct stat st; + ::stat(TQFile::encodeName(src), &st); + + struct utimbuf ut; + ut.modtime = st.st_mtime; + ut.actime = st.st_atime; + + ::utime(TQFile::encodeName(dest), &ut); + + // Get new camera item information. + + DMetadata meta; + TQFileInfo fi(dest); + TQString mime = mimeType(fi.extension(false).lower()); + + if (!mime.isEmpty()) + { + TQSize dims; + TQDateTime dt; + + if (mime == TQString("image/x-raw")) + { + // Try to load image metadata with Raw files. + meta.load(fi.filePath()); + dt = meta.getImageDateTime(); + dims = meta.getImageDimensions(); + } + else + { + meta.load(fi.filePath()); + dt = meta.getImageDateTime(); + dims = meta.getImageDimensions(); + + if (dims.isNull()) + { + // In all others case, try KFileMetaInfo. + KFileMetaInfo kmeta(fi.filePath()); + if (kmeta.isValid()) + { + if (kmeta.containsGroup("Jpeg EXIF Data")) + dims = kmeta.group("Jpeg EXIF Data").item("Dimensions").value().toSize(); + else if (kmeta.containsGroup("General")) + dims = kmeta.group("General").item("Dimensions").value().toSize(); + else if (kmeta.containsGroup("Technical")) + dims = kmeta.group("Technical").item("Dimensions").value().toSize(); + } + } + } + + if (dt.isNull()) + { + // If date is not found in metadata, use file time stamp + dt = fi.created(); + } + + info.name = fi.fileName(); + info.folder = !folder.endsWith("/") ? folder + TQString("/") : folder; + info.mime = mime; + info.mtime = dt.toTime_t(); + info.size = fi.size(); + info.width = getImageDimensions ? dims.width() : -1; + info.height = getImageDimensions ? dims.height() : -1; + info.downloaded = GPItemInfo::DownloadUnknow; + info.readPermissions = fi.isReadable(); + info.writePermissions = fi.isWritable(); + } + + return true; +} + +void UMSCamera::listFolders(const TQString& folder, TQStringList& subFolderList) +{ + if (m_cancel) + return; + + TQDir dir(folder); + dir.setFilter(TQDir::Dirs|TQDir::Executable); + + const TQFileInfoList *list = dir.entryInfoList(); + if (!list) + return; + + TQFileInfoListIterator it( *list ); + TQFileInfo *fi; + + while ((fi = it.current()) != 0 && !m_cancel) + { + ++it; + + if (fi->fileName() == "." || fi->fileName() == "..") + continue; + + TQString subfolder = folder + TQString(folder.endsWith("/") ? "" : "/") + fi->fileName(); + subFolderList.append(subfolder); + listFolders(subfolder, subFolderList); + } +} + +bool UMSCamera::cameraSummary(TQString& summary) +{ + summary = TQString(i18n("<b>Mounted Camera</b> driver for USB/IEEE1394 mass storage cameras and " + "Flash disk card readers.<br><br>")); + + summary.append(i18n("Title: %1<br>" + "Model: %2<br>" + "Port: %3<br>" + "Path: %4<br>") + .arg(title()) + .arg(model()) + .arg(port()) + .arg(path())); + return true; +} + +bool UMSCamera::cameraManual(TQString& manual) +{ + manual = TQString(i18n("For more information about the <b>Mounted Camera</b> driver, " + "please read <b>Supported Digital Still " + "Cameras</b> section in the digiKam manual.")); + return true; +} + +bool UMSCamera::cameraAbout(TQString& about) +{ + about = TQString(i18n("The <b>Mounted Camera</b> driver is a simple interface to a camera disk " + "mounted locally on your system.<br><br>" + "It doesn't use libgphoto2 drivers.<br><br>" + "To report any problems with this driver, please contact the digiKam team at:<br><br>" + "http://www.digikam.org/?q=contact")); + return true; +} + +} // namespace Digikam diff --git a/src/utilities/cameragui/umscamera.h b/src/utilities/cameragui/umscamera.h new file mode 100644 index 00000000..697ef615 --- /dev/null +++ b/src/utilities/cameragui/umscamera.h @@ -0,0 +1,78 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-21 + * Description : USB Mass Storage camera interface + * + * Copyright (C) 2004-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef UMSCAMERA_H +#define UMSCAMERA_H + +// TQt includes. + +#include <tqstringlist.h> + +// Local includes. + +#include "dkcamera.h" + +namespace Digikam +{ + +class UMSCameraPriv; + +class UMSCamera : public DKCamera +{ +public: + + UMSCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path); + ~UMSCamera(); + + bool doConnect(); + void cancel(); + + void getAllFolders(const TQString& folder, TQStringList& subFolderList); + bool getItemsInfoList(const TQString& folder, GPItemInfoList& infoList, bool getImageDimensions=true); + bool getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail); + bool getExif(const TQString& folder, const TQString& itemName, char **edata, int& esize); + + bool setLockItem(const TQString& folder, const TQString& itemName, bool lock); + + bool downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile); + bool deleteItem(const TQString& folder, const TQString& itemName); + bool uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile, + GPItemInfo& info, bool getImageDimensions=true); + + bool cameraSummary(TQString& summary); + bool cameraManual(TQString& manual); + bool cameraAbout(TQString& about); + +private: + + void listFolders(const TQString& folder, TQStringList& subFolderList); + +private: + + bool m_cancel; +}; + +} // namespace Digikam + +#endif /* UMSCAMERA_H */ |