diff options
Diffstat (limited to 'src/utilities/lighttable')
-rw-r--r-- | src/utilities/lighttable/Makefile.am | 28 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablebar.cpp | 881 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablebar.h | 153 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablepreview.cpp | 777 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablepreview.h | 125 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttableview.cpp | 446 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttableview.h | 137 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablewindow.cpp | 1676 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablewindow.h | 162 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablewindowprivate.h | 158 | ||||
-rw-r--r-- | src/utilities/lighttable/lighttablewindowui.rc | 83 |
11 files changed, 4626 insertions, 0 deletions
diff --git a/src/utilities/lighttable/Makefile.am b/src/utilities/lighttable/Makefile.am new file mode 100644 index 00000000..df38b5f9 --- /dev/null +++ b/src/utilities/lighttable/Makefile.am @@ -0,0 +1,28 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/thumbbar \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/themeengine \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/libs/imageproperties \ + -I$(top_srcdir)/src/libs/threadimageio \ + -I$(top_srcdir)/src/utilities/setup \ + -I$(top_srcdir)/src/utilities/slideshow \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_builddir)/src/libs/dialogs \ + $(LIBKEXIV2_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes) + +noinst_LTLIBRARIES = liblighttable.la + +liblighttable_la_SOURCES = lighttablebar.cpp lighttablewindow.cpp lighttablepreview.cpp \ + lighttableview.cpp + +liblighttable_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +rcdir = $(kde_datadir)/digikam +rc_DATA = lighttablewindowui.rc diff --git a/src/utilities/lighttable/lighttablebar.cpp b/src/utilities/lighttable/lighttablebar.cpp new file mode 100644 index 00000000..cfb935ab --- /dev/null +++ b/src/utilities/lighttable/lighttablebar.cpp @@ -0,0 +1,881 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-04-11 + * Description : light table thumbs bar + * + * Copyright (C) 2007-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 <tqpixmap.h> +#include <tqpainter.h> +#include <tqimage.h> +#include <tqcursor.h> + +// KDE includes. + +#include <tdeglobal.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "ddebug.h" +#include "album.h" +#include "albumdb.h" +#include "albummanager.h" +#include "albumsettings.h" +#include "dragobjects.h" +#include "imageattributeswatch.h" +#include "metadatahub.h" +#include "ratingpopupmenu.h" +#include "themeengine.h" +#include "lighttablebar.h" +#include "lighttablebar.moc" + +namespace Digikam +{ + +class LightTableBarPriv +{ + +public: + + LightTableBarPriv() + { + navigateByPair = false; + toolTip = 0; + } + + bool navigateByPair; + + TQPixmap ratingPixmap; + + LightTableBarToolTip *toolTip; +}; + +class LightTableBarItemPriv +{ + +public: + + LightTableBarItemPriv() + { + onLeftPanel = false; + onRightPanel = false; + info = 0; + } + + bool onLeftPanel; + bool onRightPanel; + + ImageInfo *info; +}; + +LightTableBar::LightTableBar(TQWidget* parent, int orientation, bool exifRotate) + : ThumbBarView(parent, orientation, exifRotate) +{ + d = new LightTableBarPriv; + setMouseTracking(true); + readToolTipSettings(); + d->toolTip = new LightTableBarToolTip(this); + + // -- Load rating Pixmap ------------------------------------------ + + TDEGlobal::dirs()->addResourceType("digikam_rating", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + TQString ratingPixPath = TDEGlobal::dirs()->findResourceDir("digikam_rating", "rating.png"); + ratingPixPath += "/rating.png"; + d->ratingPixmap = TQPixmap(ratingPixPath); + + TQPainter painter(&d->ratingPixmap); + painter.fillRect(0, 0, d->ratingPixmap.width(), d->ratingPixmap.height(), + ThemeEngine::instance()->textSpecialRegColor()); + painter.end(); + + if (orientation ==TQt::Vertical) + setMinimumWidth(d->ratingPixmap.width()*5 + 6 + 2*getMargin()); + else + setMinimumHeight(d->ratingPixmap.width()*5 + 6 + 2*getMargin()); + + // ---------------------------------------------------------------- + + ImageAttributesWatch *watch = ImageAttributesWatch::instance(); + + connect(watch, TQ_SIGNAL(signalImageRatingChanged(TQ_LLONG)), + this, TQ_SLOT(slotImageRatingChanged(TQ_LLONG))); + + connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), + this, TQ_SLOT(slotThemeChanged())); + + connect(this, TQ_SIGNAL(signalItemSelected(ThumbBarItem*)), + this, TQ_SLOT(slotItemSelected(ThumbBarItem*))); +} + +LightTableBar::~LightTableBar() +{ + delete d->toolTip; + delete d; +} + +void LightTableBar::setNavigateByPair(bool b) +{ + d->navigateByPair = b; +} + +void LightTableBar::slotImageRatingChanged(TQ_LLONG imageId) +{ + for (ThumbBarItem *item = firstItem(); item; item = item->next()) + { + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + if (ltItem->info()->id() == imageId) + { + triggerUpdate(); + return; + } + } +} + +void LightTableBar::contentsMouseReleaseEvent(TQMouseEvent *e) +{ + if (!e) return; + + ThumbBarView::contentsMouseReleaseEvent(e); + + TQPoint pos = TQCursor::pos(); + LightTableBarItem *item = findItemByPos(e->pos()); + + RatingPopupMenu *ratingMenu = 0; + + if (e->button() == TQt::RightButton) + { + TDEPopupMenu popmenu(this); + + if (item) + { + popmenu.insertItem(SmallIcon("go-previous"), i18n("Show on left panel"), 10); + popmenu.insertItem(SmallIcon("go-next"), i18n("Show on right panel"), 11); + popmenu.insertItem(SmallIcon("editimage"), i18n("Edit"), 12); + + if (d->navigateByPair) + { + popmenu.setItemEnabled(10, false); + popmenu.setItemEnabled(11, false); + } + + popmenu.insertSeparator(); + popmenu.insertItem(SmallIcon("window-close"), i18n("Remove item"), 13); + } + + int totalItems = itemsURLs().count(); + popmenu.insertItem(SmallIcon("editshred"), i18n("Clear all"), 14); + popmenu.setItemEnabled(14, totalItems ? true : false); + + if (item) + { + popmenu.insertSeparator(); + + // Assign Star Rating ------------------------------------------- + + ratingMenu = new RatingPopupMenu(); + + connect(ratingMenu, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotAssignRating(int))); + + popmenu.insertItem(i18n("Assign Rating"), ratingMenu); + } + + switch(popmenu.exec(pos)) + { + case 10: // Left panel + { + emit signalSetItemOnLeftPanel(item->info()); + break; + } + case 11: // Right panel + { + emit signalSetItemOnRightPanel(item->info()); + break; + } + case 12: // Edit + { + emit signalEditItem(item->info()); + break; + } + case 13: // Remove + { + emit signalRemoveItem(item->info()); + break; + } + case 14: // Clear All + { + emit signalClearAll(); + break; + } + default: + break; + } + } + + delete ratingMenu; +} + +void LightTableBar::slotAssignRating(int rating) +{ + rating = TQMIN(5, TQMAX(0, rating)); + ImageInfo *info = currentItemImageInfo(); + if (info) + { + MetadataHub hub; + hub.load(info); + hub.setRating(rating); + hub.write(info, MetadataHub::PartialWrite); + hub.write(info->filePath(), MetadataHub::FullWriteIfChanged); + } +} + +void LightTableBar::slotAssignRatingNoStar() +{ + slotAssignRating(0); +} + +void LightTableBar::slotAssignRatingOneStar() +{ + slotAssignRating(1); +} + +void LightTableBar::slotAssignRatingTwoStar() +{ + slotAssignRating(2); +} + +void LightTableBar::slotAssignRatingThreeStar() +{ + slotAssignRating(3); +} + +void LightTableBar::slotAssignRatingFourStar() +{ + slotAssignRating(4); +} + +void LightTableBar::slotAssignRatingFiveStar() +{ + slotAssignRating(5); +} + +void LightTableBar::setOnLeftPanel(const ImageInfo* info) +{ + for (ThumbBarItem *item = firstItem(); item; item = item->next()) + { + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + if (ltItem) + { + if (info) + { + if (ltItem->info()->id() == info->id()) + { + ltItem->setOnLeftPanel(true); + repaintItem(item); + } + else if (ltItem->isOnLeftPanel() == true) + { + ltItem->setOnLeftPanel(false); + repaintItem(item); + } + } + else if (ltItem->isOnLeftPanel() == true) + { + ltItem->setOnLeftPanel(false); + repaintItem(item); + } + } + } +} + +void LightTableBar::setOnRightPanel(const ImageInfo* info) +{ + for (ThumbBarItem *item = firstItem(); item; item = item->next()) + { + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + if (ltItem) + { + if (info) + { + if (ltItem->info()->id() == info->id()) + { + ltItem->setOnRightPanel(true); + repaintItem(item); + } + else if (ltItem->isOnRightPanel() == true) + { + ltItem->setOnRightPanel(false); + repaintItem(item); + } + } + else if (ltItem->isOnRightPanel() == true) + { + ltItem->setOnRightPanel(false); + repaintItem(item); + } + } + } +} + +void LightTableBar::slotItemSelected(ThumbBarItem* item) +{ + if (item) + { + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + if (ltItem) + { + emit signalLightTableBarItemSelected(ltItem->info()); + return; + } + } + + emit signalLightTableBarItemSelected(0); +} + +ImageInfo* LightTableBar::currentItemImageInfo() const +{ + if (currentItem()) + { + LightTableBarItem *item = dynamic_cast<LightTableBarItem*>(currentItem()); + return item->info(); + } + + return 0; +} + +ImageInfoList LightTableBar::itemsImageInfoList() +{ + ImageInfoList list; + + for (ThumbBarItem *item = firstItem(); item; item = item->next()) + { + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + if (ltItem) + { + ImageInfo *info = new ImageInfo(*(ltItem->info())); + list.append(info); + } + } + + return list; +} + +void LightTableBar::setSelectedItem(LightTableBarItem* ltItem) +{ + ThumbBarItem *item = static_cast<ThumbBarItem*>(ltItem); + if (item) ThumbBarView::setSelected(item); +} + +void LightTableBar::removeItem(const ImageInfo* info) +{ + if (!info) return; + + LightTableBarItem* ltItem = findItemByInfo(info); + ThumbBarItem *item = static_cast<ThumbBarItem*>(ltItem); + if (item) ThumbBarView::removeItem(item); +} + +LightTableBarItem* LightTableBar::findItemByInfo(const ImageInfo* info) const +{ + if (info) + { + for (ThumbBarItem *item = firstItem(); item; item = item->next()) + { + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + if (ltItem) + { + if (ltItem->info()->id() == info->id()) + return ltItem; + } + } + } + return 0; +} + +LightTableBarItem* LightTableBar::findItemByPos(const TQPoint& pos) const +{ + ThumbBarItem *item = findItem(pos); + if (item) + { + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + return ltItem; + } + + return 0; +} + +void LightTableBar::readToolTipSettings() +{ + AlbumSettings* albumSettings = AlbumSettings::instance(); + if (!albumSettings) return; + + Digikam::ThumbBarToolTipSettings settings; + settings.showToolTips = albumSettings->getShowToolTips(); + settings.showFileName = albumSettings->getToolTipsShowFileName(); + settings.showFileDate = albumSettings->getToolTipsShowFileDate(); + settings.showFileSize = albumSettings->getToolTipsShowFileSize(); + settings.showImageType = albumSettings->getToolTipsShowImageType(); + settings.showImageDim = albumSettings->getToolTipsShowImageDim(); + settings.showPhotoMake = albumSettings->getToolTipsShowPhotoMake(); + settings.showPhotoDate = albumSettings->getToolTipsShowPhotoDate(); + settings.showPhotoFocal = albumSettings->getToolTipsShowPhotoFocal(); + settings.showPhotoExpo = albumSettings->getToolTipsShowPhotoExpo(); + settings.showPhotoMode = albumSettings->getToolTipsShowPhotoMode(); + settings.showPhotoFlash = albumSettings->getToolTipsShowPhotoFlash(); + settings.showPhotoWB = albumSettings->getToolTipsShowPhotoWB(); + setToolTipSettings(settings); +} + +void LightTableBar::viewportPaintEvent(TQPaintEvent* e) +{ + ThemeEngine* te = ThemeEngine::instance(); + TQRect er(e->rect()); + TQPixmap bgPix; + + if (countItems() > 0) + { + int cy, cx, ts, y1, y2, x1, x2; + TQPixmap tile; + + if (getOrientation() ==TQt::Vertical) + { + cy = viewportToContents(er.topLeft()).y(); + + bgPix.resize(contentsRect().width(), er.height()); + + ts = getTileSize() + 2*getMargin(); + tile.resize(visibleWidth(), ts); + + y1 = (cy/ts)*ts; + y2 = ((y1 + er.height())/ts +1)*ts; + } + else + { + cx = viewportToContents(er.topLeft()).x(); + + bgPix.resize(er.width(), contentsRect().height()); + + ts = getTileSize() + 2*getMargin(); + tile.resize(ts, visibleHeight()); + + x1 = (cx/ts)*ts; + x2 = ((x1 + er.width())/ts +1)*ts; + } + + bgPix.fill(te->baseColor()); + + for (ThumbBarItem *item = firstItem(); item; item = item->next()) + { + if (getOrientation() ==TQt::Vertical) + { + if (y1 <= item->position() && item->position() <= y2) + { + if (item == currentItem()) + tile = te->thumbSelPixmap(tile.width(), tile.height()); + else + tile = te->thumbRegPixmap(tile.width(), tile.height()); + + TQPainter p(&tile); + if (item == currentItem()) + { + p.setPen(TQPen(te->textSelColor(), 3)); + p.drawRect(2, 2, tile.width()-2, tile.height()-2); + } + else + { + p.setPen(TQPen(te->textRegColor(), 1)); + p.drawRect(0, 0, tile.width(), tile.height()); + } + p.end(); + + if (item->pixmap()) + { + TQPixmap pix; + pix.convertFromImage(TQImage(item->pixmap()->convertToImage()). + smoothScale(getTileSize(), getTileSize(), TQImage::ScaleMin)); + int x = (tile.width() - pix.width())/2; + int y = (tile.height() - pix.height())/2; + bitBlt(&tile, x, y, &pix); + + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + + if (ltItem->isOnLeftPanel()) + { + TQPixmap lPix = SmallIcon("go-previous"); + bitBlt(&tile, getMargin(), getMargin(), &lPix); + } + if (ltItem->isOnRightPanel()) + { + TQPixmap rPix = SmallIcon("go-next"); + bitBlt(&tile, tile.width() - getMargin() - rPix.width(), getMargin(), &rPix); + } + + TQRect r(0, tile.height()-getMargin()-d->ratingPixmap.height(), + tile.width(), d->ratingPixmap.height()); + int rating = ltItem->info()->rating(); + int xr = (r.width() - rating * d->ratingPixmap.width())/2; + int wr = rating * d->ratingPixmap.width(); + TQPainter p(&tile); + p.drawTiledPixmap(xr, r.y(), wr, r.height(), d->ratingPixmap); + } + + bitBlt(&bgPix, 0, item->position() - cy, &tile); + } + } + else + { + if (x1 <= item->position() && item->position() <= x2) + { + if (item == currentItem()) + tile = te->thumbSelPixmap(tile.width(), tile.height()); + else + tile = te->thumbRegPixmap(tile.width(), tile.height()); + + TQPainter p(&tile); + if (item == currentItem()) + { + p.setPen(TQPen(te->textSelColor(), 2)); + p.drawRect(1, 1, tile.width()-1, tile.height()-1); + } + else + { + p.setPen(TQPen(te->textRegColor(), 1)); + p.drawRect(0, 0, tile.width(), tile.height()); + } + p.end(); + + if (item->pixmap()) + { + TQPixmap pix; + pix.convertFromImage(TQImage(item->pixmap()->convertToImage()). + smoothScale(getTileSize(), getTileSize(), TQImage::ScaleMin)); + int x = (tile.width() - pix.width())/2; + int y = (tile.height()- pix.height())/2; + bitBlt(&tile, x, y, &pix); + + LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item); + + if (ltItem->isOnLeftPanel()) + { + TQPixmap lPix = SmallIcon("go-previous"); + bitBlt(&tile, getMargin(), getMargin(), &lPix); + } + if (ltItem->isOnRightPanel()) + { + TQPixmap rPix = SmallIcon("go-next"); + bitBlt(&tile, tile.width() - getMargin() - rPix.width(), getMargin(), &rPix); + } + + TQRect r(0, tile.height()-getMargin()-d->ratingPixmap.height(), + tile.width(), d->ratingPixmap.height()); + int rating = ltItem->info()->rating(); + int xr = (r.width() - rating * d->ratingPixmap.width())/2; + int wr = rating * d->ratingPixmap.width(); + TQPainter p(&tile); + p.drawTiledPixmap(xr, r.y(), wr, r.height(), d->ratingPixmap); + } + + bitBlt(&bgPix, item->position() - cx, 0, &tile); + } + } + } + + if (getOrientation() ==TQt::Vertical) + bitBlt(viewport(), 0, er.y(), &bgPix); + else + bitBlt(viewport(), er.x(), 0, &bgPix); + } + else + { + bgPix.resize(contentsRect().width(), contentsRect().height()); + bgPix.fill(te->baseColor()); + TQPainter p(&bgPix); + p.setPen(TQPen(te->textRegColor())); + p.drawText(0, 0, bgPix.width(), bgPix.height(), + TQt::AlignCenter|TQt::WordBreak, + i18n("Drag and drop images here")); + p.end(); + bitBlt(viewport(), 0, 0, &bgPix); + } +} + +void LightTableBar::startDrag() +{ + if (!currentItem()) return; + + KURL::List urls; + KURL::List kioURLs; + TQValueList<int> albumIDs; + TQValueList<int> imageIDs; + + LightTableBarItem *item = dynamic_cast<LightTableBarItem*>(currentItem()); + + urls.append(item->info()->kurl()); + kioURLs.append(item->info()->kurlForKIO()); + imageIDs.append(item->info()->id()); + albumIDs.append(item->info()->albumID()); + + TQPixmap icon(DesktopIcon("image-x-generic", 48)); + int w = icon.width(); + int h = icon.height(); + + TQPixmap pix(w+4,h+4); + 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); + p.end(); + + TQDragObject* drag = 0; + + drag = new ItemDrag(urls, kioURLs, albumIDs, imageIDs, this); + if (drag) + { + drag->setPixmap(pix); + drag->drag(); + } +} + +void LightTableBar::contentsDragMoveEvent(TQDragMoveEvent *e) +{ + int albumID; + TQValueList<int> albumIDs; + TQValueList<int> imageIDs; + KURL::List urls; + KURL::List kioURLs; + + if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs) || + AlbumDrag::decode(e, urls, albumID) || + TagDrag::canDecode(e)) + { + e->accept(); + return; + } + + e->ignore(); +} + +void LightTableBar::contentsDropEvent(TQDropEvent *e) +{ + int albumID; + TQValueList<int> albumIDs; + TQValueList<int> imageIDs; + KURL::List urls; + KURL::List kioURLs; + + if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs)) + { + ImageInfoList imageInfoList; + + for (TQValueList<int>::const_iterator it = imageIDs.begin(); + it != imageIDs.end(); ++it) + { + ImageInfo *info = new ImageInfo(*it); + if (!findItemByInfo(info)) + { + imageInfoList.append(info); + } + else + { + delete info; + } + } + + emit signalDroppedItems(imageInfoList); + e->accept(); + } + else if (AlbumDrag::decode(e, urls, albumID)) + { + TQValueList<TQ_LLONG> itemIDs = AlbumManager::instance()->albumDB()->getItemIDsInAlbum(albumID); + ImageInfoList imageInfoList; + + for (TQValueList<TQ_LLONG>::const_iterator it = itemIDs.begin(); + it != itemIDs.end(); ++it) + { + ImageInfo *info = new ImageInfo(*it); + if (!findItemByInfo(info)) + { + imageInfoList.append(info); + } + else + { + delete info; + } + } + + emit signalDroppedItems(imageInfoList); + e->accept(); + } + else if(TagDrag::canDecode(e)) + { + TQByteArray ba = e->encodedData("digikam/tag-id"); + TQDataStream ds(ba, IO_ReadOnly); + int tagID; + ds >> tagID; + + AlbumManager* man = AlbumManager::instance(); + TQValueList<TQ_LLONG> itemIDs = man->albumDB()->getItemIDsInTag(tagID, true); + ImageInfoList imageInfoList; + + for (TQValueList<TQ_LLONG>::const_iterator it = itemIDs.begin(); + it != itemIDs.end(); ++it) + { + ImageInfo *info = new ImageInfo(*it); + if (!findItemByInfo(info)) + { + imageInfoList.append(info); + } + else + { + delete info; + } + } + + emit signalDroppedItems(imageInfoList); + e->accept(); + } + else + { + e->ignore(); + } +} + +void LightTableBar::slotThemeChanged() +{ + TDEGlobal::dirs()->addResourceType("digikam_rating", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + TQString ratingPixPath = TDEGlobal::dirs()->findResourceDir("digikam_rating", "rating.png"); + ratingPixPath += "/rating.png"; + d->ratingPixmap = TQPixmap(ratingPixPath); + + TQPainter painter(&d->ratingPixmap); + painter.fillRect(0, 0, d->ratingPixmap.width(), d->ratingPixmap.height(), + ThemeEngine::instance()->textSpecialRegColor()); + painter.end(); + + slotUpdate(); +} + +// ------------------------------------------------------------------------- + +LightTableBarItem::LightTableBarItem(LightTableBar *view, ImageInfo *info) + : ThumbBarItem(view, info->kurl()) +{ + d = new LightTableBarItemPriv; + d->info = info; +} + +LightTableBarItem::~LightTableBarItem() +{ + delete d; +} + +ImageInfo* LightTableBarItem::info() const +{ + return d->info; +} + +void LightTableBarItem::setOnLeftPanel(bool on) +{ + d->onLeftPanel = on; +} + +void LightTableBarItem::setOnRightPanel(bool on) +{ + d->onRightPanel = on; +} + +bool LightTableBarItem::isOnLeftPanel() const +{ + return d->onLeftPanel; +} + +bool LightTableBarItem::isOnRightPanel() const +{ + return d->onRightPanel; +} + +// ------------------------------------------------------------------------- + +LightTableBarToolTip::LightTableBarToolTip(ThumbBarView *parent) + : ThumbBarToolTip(parent) +{ +} + +TQString LightTableBarToolTip::tipContentExtraData(ThumbBarItem *item) +{ + TQString tip, str; + AlbumSettings* settings = AlbumSettings::instance(); + ImageInfo* info = static_cast<LightTableBarItem *>(item)->info(); + + if (settings) + { + if (settings->getToolTipsShowAlbumName() || + settings->getToolTipsShowComments() || + settings->getToolTipsShowTags() || + settings->getToolTipsShowRating()) + { + tip += m_headBeg + i18n("digiKam Properties") + m_headEnd; + + if (settings->getToolTipsShowAlbumName()) + { + PAlbum* album = info->album(); + if (album) + tip += m_cellSpecBeg + i18n("Album:") + m_cellSpecMid + + album->url().remove(0, 1) + m_cellSpecEnd; + } + + if (settings->getToolTipsShowComments()) + { + str = info->caption(); + if (str.isEmpty()) str = TQString("---"); + tip += m_cellSpecBeg + i18n("Caption:") + m_cellSpecMid + breakString(str) + m_cellSpecEnd; + } + + if (settings->getToolTipsShowTags()) + { + TQStringList tagPaths = info->tagPaths(false); + + str = tagPaths.join(", "); + if (str.isEmpty()) str = TQString("---"); + if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "..."; + tip += m_cellSpecBeg + i18n("Tags:") + m_cellSpecMid + str + m_cellSpecEnd; + } + + if (settings->getToolTipsShowRating()) + { + str.fill( '*', info->rating() ); + if (str.isEmpty()) str = TQString("---"); + tip += m_cellSpecBeg + i18n("Rating:") + m_cellSpecMid + str + m_cellSpecEnd; + } + } + } + + return tip; +} + +} // NameSpace Digikam diff --git a/src/utilities/lighttable/lighttablebar.h b/src/utilities/lighttable/lighttablebar.h new file mode 100644 index 00000000..b64e93a6 --- /dev/null +++ b/src/utilities/lighttable/lighttablebar.h @@ -0,0 +1,153 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-04-11 + * Description : light table thumbs bar + * + * Copyright (C) 2007-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 LIGHTTABLEBAR_H +#define LIGHTTABLEBAR_H + +// Local includes. + +#include "thumbbar.h" +#include "imageinfo.h" +#include "digikam_export.h" + +class TQDragMoveEvent; +class TQDropEvent; +class TQMouseEvent; +class TQPaintEvent; + +class KURL; + +namespace Digikam +{ + +class LightTableBarItem; +class LightTableBarItemPriv; +class LightTableBarPriv; + +class DIGIKAM_EXPORT LightTableBar : public ThumbBarView +{ + TQ_OBJECT + + +public: + + LightTableBar(TQWidget* parent, int orientation=Vertical, bool exifRotate=true); + ~LightTableBar(); + + ImageInfo* currentItemImageInfo() const; + ImageInfoList itemsImageInfoList(); + + void setSelectedItem(LightTableBarItem* ltItem); + + LightTableBarItem* findItemByInfo(const ImageInfo* info) const; + LightTableBarItem* findItemByPos(const TQPoint& pos) const; + + /** Read tool tip settings from Album Settings instance */ + void readToolTipSettings(); + + void setOnLeftPanel(const ImageInfo* info); + void setOnRightPanel(const ImageInfo* info); + + void removeItem(const ImageInfo* info); + + void setNavigateByPair(bool b); + +signals: + + void signalLightTableBarItemSelected(ImageInfo*); + void signalSetItemOnLeftPanel(ImageInfo*); + void signalSetItemOnRightPanel(ImageInfo*); + void signalEditItem(ImageInfo*); + void signalRemoveItem(ImageInfo*); + void signalClearAll(); + void signalDroppedItems(const ImageInfoList&); + +private: + + void viewportPaintEvent(TQPaintEvent*); + void contentsMouseReleaseEvent(TQMouseEvent*); + void startDrag(); + void contentsDragMoveEvent(TQDragMoveEvent*); + void contentsDropEvent(TQDropEvent*); + +private slots: + + void slotImageRatingChanged(TQ_LLONG); + void slotItemSelected(ThumbBarItem*); + + void slotAssignRatingNoStar(); + void slotAssignRatingOneStar(); + void slotAssignRatingTwoStar(); + void slotAssignRatingThreeStar(); + void slotAssignRatingFourStar(); + void slotAssignRatingFiveStar(); + void slotAssignRating(int); + + void slotThemeChanged(); + +private: + + LightTableBarPriv *d; + + friend class LightTableBarItem; +}; + +// ------------------------------------------------------------------------- + +class DIGIKAM_EXPORT LightTableBarItem : public ThumbBarItem +{ +public: + + LightTableBarItem(LightTableBar *view, ImageInfo *info); + ~LightTableBarItem(); + + ImageInfo* info() const; + + void setOnLeftPanel(bool on); + void setOnRightPanel(bool on); + bool isOnLeftPanel() const; + bool isOnRightPanel() const; + +private: + + LightTableBarItemPriv *d; + + friend class LightTableBar; +}; + +// ------------------------------------------------------------------------- + +class DIGIKAM_EXPORT LightTableBarToolTip : public ThumbBarToolTip +{ +public: + + LightTableBarToolTip(ThumbBarView *parent); + +private: + + TQString tipContentExtraData(ThumbBarItem *item); +}; + +} // NameSpace Digikam + +#endif /* LIGHTTABLEBAR_H */ diff --git a/src/utilities/lighttable/lighttablepreview.cpp b/src/utilities/lighttable/lighttablepreview.cpp new file mode 100644 index 00000000..100427ec --- /dev/null +++ b/src/utilities/lighttable/lighttablepreview.cpp @@ -0,0 +1,777 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-21-12 + * Description : digiKam light table preview item. + * + * 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 <tqpainter.h> +#include <tqcursor.h> +#include <tqstring.h> +#include <tqvaluevector.h> +#include <tqfileinfo.h> +#include <tqtoolbutton.h> +#include <tqtooltip.h> +#include <tqpixmap.h> +#include <tqdrawutil.h> + +// KDE includes. + +#include <kdialogbase.h> +#include <tdelocale.h> +#include <kservice.h> +#include <krun.h> +#include <ktrader.h> +#include <kmimetype.h> +#include <kcursor.h> +#include <kdatetbl.h> +#include <kiconloader.h> +#include <kprocess.h> +#include <tdeapplication.h> + +// Local includes. + +#include "dimg.h" +#include "ddebug.h" +#include "albumdb.h" +#include "constants.h" +#include "albummanager.h" +#include "albumsettings.h" +#include "dragobjects.h" +#include "dmetadata.h" +#include "dpopupmenu.h" +#include "metadatahub.h" +#include "paniconwidget.h" +#include "previewloadthread.h" +#include "loadingdescription.h" +#include "tagspopupmenu.h" +#include "ratingpopupmenu.h" +#include "themeengine.h" +#include "lighttablepreview.h" +#include "lighttablepreview.moc" + +namespace Digikam +{ + +class LightTablePreviewPriv +{ +public: + + LightTablePreviewPriv() + { + panIconPopup = 0; + panIconWidget = 0; + cornerButton = 0; + previewThread = 0; + previewPreloadThread = 0; + imageInfo = 0; + hasPrev = false; + hasNext = false; + selected = false; + dragAndDropEnabled = true; + loadFullImageSize = false; + currentFitWindowZoom = 0; + previewSize = 1024; + } + + bool hasPrev; + bool hasNext; + bool selected; + bool dragAndDropEnabled; + bool loadFullImageSize; + + int previewSize; + + double currentFitWindowZoom; + + TQString path; + TQString nextPath; + TQString previousPath; + + TQToolButton *cornerButton; + + TDEPopupFrame *panIconPopup; + + PanIconWidget *panIconWidget; + + DImg preview; + + ImageInfo *imageInfo; + + PreviewLoadThread *previewThread; + PreviewLoadThread *previewPreloadThread; +}; + +LightTablePreview::LightTablePreview(TQWidget *parent) + : PreviewWidget(parent) +{ + d = new LightTablePreviewPriv; + + // get preview size from screen size, but limit from VGA to WTQXGA + d->previewSize = TQMAX(TDEApplication::desktop()->height(), + TDEApplication::desktop()->width()); + if (d->previewSize < 640) + d->previewSize = 640; + if (d->previewSize > 2560) + d->previewSize = 2560; + + viewport()->setAcceptDrops(true); + setAcceptDrops(true); + + slotThemeChanged(); + setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); + + d->cornerButton = new TQToolButton(this); + d->cornerButton->setIconSet(SmallIcon("move")); + d->cornerButton->hide(); + TQToolTip::add(d->cornerButton, i18n("Pan the image")); + setCornerWidget(d->cornerButton); + + setLineWidth(5); + setSelected(false); + + // ------------------------------------------------------------ + + connect(d->cornerButton, TQ_SIGNAL(pressed()), + this, TQ_SLOT(slotCornerButtonPressed())); + + connect(this, TQ_SIGNAL(signalRightButtonClicked()), + this, TQ_SLOT(slotContextMenu())); + + connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), + this, TQ_SLOT(slotThemeChanged())); + + // ------------------------------------------------------------ + + slotReset(); +} + +LightTablePreview::~LightTablePreview() +{ + delete d->previewThread; + delete d->previewPreloadThread; + delete d; +} + +void LightTablePreview::setLoadFullImageSize(bool b) +{ + d->loadFullImageSize = b; + reload(); +} + +void LightTablePreview::setDragAndDropEnabled(bool b) +{ + d->dragAndDropEnabled = b; +} + +void LightTablePreview::setDragAndDropMessage() +{ + if (d->dragAndDropEnabled) + { + TQPixmap pix(visibleWidth(), visibleHeight()); + pix.fill(ThemeEngine::instance()->baseColor()); + TQPainter p(&pix); + p.setPen(TQPen(ThemeEngine::instance()->textRegColor())); + p.drawText(0, 0, pix.width(), pix.height(), + TQt::AlignCenter|TQt::WordBreak, + i18n("Drag and drop an image here")); + p.end(); + setImage(pix.convertToImage()); + } +} + +void LightTablePreview::setImage(const DImg& image) +{ + d->preview = image; + + updateZoomAndSize(true); + + viewport()->setUpdatesEnabled(true); + viewport()->update(); +} + +DImg& LightTablePreview::getImage() const +{ + return d->preview; +} + +TQSize LightTablePreview::getImageSize() +{ + return d->preview.size(); +} + +void LightTablePreview::reload() +{ + // cache is cleaned from AlbumIconView::refreshItems + setImagePath(d->path); +} + +void LightTablePreview::setPreviousNextPaths(const TQString& previous, const TQString &next) +{ + d->nextPath = next; + d->previousPath = previous; +} + +void LightTablePreview::setImagePath(const TQString& path) +{ + setCursor( KCursor::waitCursor() ); + + d->path = path; + d->nextPath = TQString(); + d->previousPath = TQString(); + + if (d->path.isEmpty()) + { + slotReset(); + unsetCursor(); + return; + } + + if (!d->previewThread) + { + d->previewThread = new PreviewLoadThread(); + connect(d->previewThread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)), + this, TQ_SLOT(slotGotImagePreview(const LoadingDescription &, const DImg&))); + } + if (!d->previewPreloadThread) + { + d->previewPreloadThread = new PreviewLoadThread(); + connect(d->previewPreloadThread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)), + this, TQ_SLOT(slotNextPreload())); + } + + if (d->loadFullImageSize) + d->previewThread->loadHighQuality(LoadingDescription(path, 0, AlbumSettings::instance()->getExifRotate())); + else + d->previewThread->load(LoadingDescription(path, d->previewSize, AlbumSettings::instance()->getExifRotate())); +} + +void LightTablePreview::slotGotImagePreview(const LoadingDescription &description, const DImg& preview) +{ + if (description.filePath != d->path) + return; + + if (preview.isNull()) + { + TQPixmap pix(visibleWidth(), visibleHeight()); + pix.fill(ThemeEngine::instance()->baseColor()); + TQPainter p(&pix); + TQFileInfo info(d->path); + p.setPen(TQPen(ThemeEngine::instance()->textRegColor())); + p.drawText(0, 0, pix.width(), pix.height(), + TQt::AlignCenter|TQt::WordBreak, + i18n("Unable to display preview for\n\"%1\"") + .arg(info.fileName())); + p.end(); + setImage(DImg(pix.convertToImage())); + + emit signalPreviewLoaded(false); + } + else + { + DImg img(preview); + if (AlbumSettings::instance()->getExifRotate()) + d->previewThread->exifRotate(img, description.filePath); + setImage(img); + emit signalPreviewLoaded(true); + } + + unsetCursor(); + slotNextPreload(); +} + +void LightTablePreview::slotNextPreload() +{ + TQString loadPath; + if (!d->nextPath.isNull()) + { + loadPath = d->nextPath; + d->nextPath = TQString(); + } + else if (!d->previousPath.isNull()) + { + loadPath = d->previousPath; + d->previousPath = TQString(); + } + else + return; + + d->previewPreloadThread->load(LoadingDescription(loadPath, d->previewSize, + AlbumSettings::instance()->getExifRotate())); +} + +void LightTablePreview::setImageInfo(ImageInfo* info, ImageInfo *previous, ImageInfo *next) +{ + d->imageInfo = info; + d->hasPrev = previous; + d->hasNext = next; + + if (d->imageInfo) + setImagePath(info->filePath()); + else + { + setImagePath(); + setSelected(false); + } + + setPreviousNextPaths(previous ? previous->filePath() : TQString(), + next ? next->filePath() : TQString()); +} + +ImageInfo* LightTablePreview::getImageInfo() const +{ + return d->imageInfo; +} + +void LightTablePreview::slotContextMenu() +{ + RatingPopupMenu *ratingMenu = 0; + TagsPopupMenu *assignTagsMenu = 0; + TagsPopupMenu *removeTagsMenu = 0; + + if (!d->imageInfo) + return; + + //-- Open With Actions ------------------------------------ + + KURL url(d->imageInfo->kurl().path()); + KMimeType::Ptr mimePtr = KMimeType::findByURL(url, 0, true, true); + + TQValueVector<KService::Ptr> serviceVector; + TDETrader::OfferList offers = TDETrader::self()->query(mimePtr->name(), "Type == 'Application'"); + + TQPopupMenu openWithMenu; + + TDETrader::OfferList::Iterator iter; + KService::Ptr ptr; + int index = 100; + + for( iter = offers.begin(); iter != offers.end(); ++iter ) + { + ptr = *iter; + openWithMenu.insertItem( ptr->pixmap(TDEIcon::Small), ptr->name(), index++); + serviceVector.push_back(ptr); + } + + DPopupMenu popmenu(this); + + //-- Zoom actions ----------------------------------------------- + + popmenu.insertItem(SmallIcon("viewmag"), i18n("Zoom in"), 17); + popmenu.insertItem(SmallIcon("zoom-out"), i18n("Zoom out"), 18); + popmenu.insertItem(SmallIcon("view_fit_window"), i18n("Fit to &Window"), 19); + + //-- Edit actions ----------------------------------------------- + + popmenu.insertSeparator(); + popmenu.insertItem(SmallIcon("slideshow"), i18n("SlideShow"), 16); + popmenu.insertItem(SmallIcon("editimage"), i18n("Edit..."), 12); + popmenu.insertItem(i18n("Open With"), &openWithMenu, 13); + + //-- Trash action ------------------------------------------- + + popmenu.insertSeparator(); + popmenu.insertItem(SmallIcon("edittrash"), i18n("Move to Trash"), 14); + + // Bulk assignment/removal of tags -------------------------- + + TQ_LLONG id = d->imageInfo->id(); + TQValueList<TQ_LLONG> idList; + idList.append(id); + + assignTagsMenu = new TagsPopupMenu(idList, 1000, TagsPopupMenu::ASSIGN); + removeTagsMenu = new TagsPopupMenu(idList, 2000, TagsPopupMenu::REMOVE); + + popmenu.insertSeparator(); + + popmenu.insertItem(i18n("Assign Tag"), assignTagsMenu); + int i = popmenu.insertItem(i18n("Remove Tag"), removeTagsMenu); + + connect(assignTagsMenu, TQ_SIGNAL(signalTagActivated(int)), + this, TQ_SLOT(slotAssignTag(int))); + + connect(removeTagsMenu, TQ_SIGNAL(signalTagActivated(int)), + this, TQ_SLOT(slotRemoveTag(int))); + + AlbumDB* db = AlbumManager::instance()->albumDB(); + if (!db->hasTags( idList )) + popmenu.setItemEnabled(i, false); + + popmenu.insertSeparator(); + + // Assign Star Rating ------------------------------------------- + + ratingMenu = new RatingPopupMenu(); + + connect(ratingMenu, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotAssignRating(int))); + + popmenu.insertItem(i18n("Assign Rating"), ratingMenu); + + // -------------------------------------------------------- + + int idm = popmenu.exec(TQCursor::pos()); + + switch(idm) + { + case 12: // Edit... + { + emit signalEditItem(d->imageInfo); + break; + } + + case 14: // Move to trash + { + emit signalDeleteItem(d->imageInfo); + break; + } + + case 16: // SlideShow + { + emit signalSlideShow(); + break; + } + + case 17: // Zoom in + { + slotIncreaseZoom(); + break; + } + + case 18: // Zoom out + { + slotDecreaseZoom(); + break; + } + + case 19: // Fit to window + { + fitToWindow(); + break; + } + + default: + break; + } + + // Open With... + if (idm >= 100 && idm < 1000) + { + KService::Ptr imageServicePtr = serviceVector[idm-100]; + KRun::run(*imageServicePtr, url); + } + + serviceVector.clear(); + delete assignTagsMenu; + delete removeTagsMenu; + delete ratingMenu; +} + +void LightTablePreview::slotAssignTag(int tagID) +{ + if (d->imageInfo) + { + MetadataHub hub; + hub.load(d->imageInfo); + hub.setTag(tagID, true); + hub.write(d->imageInfo, MetadataHub::PartialWrite); + hub.write(d->imageInfo->filePath(), MetadataHub::FullWriteIfChanged); + } +} + +void LightTablePreview::slotRemoveTag(int tagID) +{ + if (d->imageInfo) + { + MetadataHub hub; + hub.load(d->imageInfo); + hub.setTag(tagID, false); + hub.write(d->imageInfo, MetadataHub::PartialWrite); + hub.write(d->imageInfo->filePath(), MetadataHub::FullWriteIfChanged); + } +} + +void LightTablePreview::slotAssignRating(int rating) +{ + rating = TQMIN(RatingMax, TQMAX(RatingMin, rating)); + if (d->imageInfo) + { + MetadataHub hub; + hub.load(d->imageInfo); + hub.setRating(rating); + hub.write(d->imageInfo, MetadataHub::PartialWrite); + hub.write(d->imageInfo->filePath(), MetadataHub::FullWriteIfChanged); + } +} + +void LightTablePreview::slotThemeChanged() +{ + setBackgroundColor(ThemeEngine::instance()->baseColor()); + frameChanged(); +} + +void LightTablePreview::slotCornerButtonPressed() +{ + if (d->panIconPopup) + { + d->panIconPopup->hide(); + delete d->panIconPopup; + d->panIconPopup = 0; + } + + d->panIconPopup = new TDEPopupFrame(this); + PanIconWidget *pan = new PanIconWidget(d->panIconPopup); + pan->setImage(180, 120, getImage()); + d->panIconPopup->setMainWidget(pan); + + TQRect r((int)(contentsX() / zoomFactor()), (int)(contentsY() / zoomFactor()), + (int)(visibleWidth() / zoomFactor()), (int)(visibleHeight() / zoomFactor())); + pan->setRegionSelection(r); + pan->setMouseFocus(); + + connect(pan, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)), + this, TQ_SLOT(slotPanIconSelectionMoved(const TQRect&, bool))); + + connect(pan, TQ_SIGNAL(signalHiden()), + this, TQ_SLOT(slotPanIconHiden())); + + TQPoint g = mapToGlobal(viewport()->pos()); + g.setX(g.x()+ viewport()->size().width()); + g.setY(g.y()+ viewport()->size().height()); + d->panIconPopup->popup(TQPoint(g.x() - d->panIconPopup->width(), + g.y() - d->panIconPopup->height())); + + pan->setCursorToLocalRegionSelectionCenter(); +} + +void LightTablePreview::slotPanIconHiden() +{ + d->cornerButton->blockSignals(true); + d->cornerButton->animateClick(); + d->cornerButton->blockSignals(false); +} + +void LightTablePreview::slotPanIconSelectionMoved(const TQRect& r, bool b) +{ + setContentsPos((int)(r.x()*zoomFactor()), (int)(r.y()*zoomFactor())); + + if (b) + { + d->panIconPopup->hide(); + delete d->panIconPopup; + d->panIconPopup = 0; + slotPanIconHiden(); + } +} + +void LightTablePreview::zoomFactorChanged(double zoom) +{ + updateScrollBars(); + + if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible()) + d->cornerButton->show(); + else + d->cornerButton->hide(); + + PreviewWidget::zoomFactorChanged(zoom); +} + +void LightTablePreview::resizeEvent(TQResizeEvent* e) +{ + if (!e) return; + + TQScrollView::resizeEvent(e); + + if (!d->imageInfo) + { + d->cornerButton->hide(); + setDragAndDropMessage(); + } + + updateZoomAndSize(false); +} + +void LightTablePreview::updateZoomAndSize(bool alwaysFitToWindow) +{ + // Set zoom for fit-in-window as minimum, but dont scale up images + // that are smaller than the available space, only scale down. + double zoom = calcAutoZoomFactor(ZoomInOnly); + setZoomMin(zoom); + setZoomMax(zoom*12.0); + + // Is currently the zoom factor set to fit to window? Then set it again to fit the new size. + if (zoomFactor() < zoom || alwaysFitToWindow || zoomFactor() == d->currentFitWindowZoom) + { + setZoomFactor(zoom); + } + + // store which zoom factor means it is fit to window + d->currentFitWindowZoom = zoom; + + updateContentsSize(); +} + +int LightTablePreview::previewWidth() +{ + return d->preview.width(); +} + +int LightTablePreview::previewHeight() +{ + return d->preview.height(); +} + +bool LightTablePreview::previewIsNull() +{ + return d->preview.isNull(); +} + +void LightTablePreview::resetPreview() +{ + d->preview = DImg(); + d->path = TQString(); + d->imageInfo = 0; + + setDragAndDropMessage(); + updateZoomAndSize(true); + viewport()->setUpdatesEnabled(true); + viewport()->update(); + emit signalPreviewLoaded(false); +} + +void LightTablePreview::paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh) +{ + DImg img = d->preview.smoothScaleSection(sx, sy, sw, sh, tileSize(), tileSize()); + TQPixmap pix2 = img.convertToPixmap(); + bitBlt(pix, 0, 0, &pix2, 0, 0); +} + +void LightTablePreview::contentsDragMoveEvent(TQDragMoveEvent *e) +{ + if (d->dragAndDropEnabled) + { + int albumID; + TQValueList<int> albumIDs; + TQValueList<int> imageIDs; + KURL::List urls; + KURL::List kioURLs; + + if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs) || + AlbumDrag::decode(e, urls, albumID) || + TagDrag::canDecode(e)) + { + e->accept(); + return; + } + } + + e->ignore(); +} + +void LightTablePreview::contentsDropEvent(TQDropEvent *e) +{ + if (d->dragAndDropEnabled) + { + int albumID; + TQValueList<int> albumIDs; + TQValueList<int> imageIDs; + KURL::List urls; + KURL::List kioURLs; + ImageInfoList list; + + if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs)) + { + for (TQValueList<int>::const_iterator it = imageIDs.begin(); + it != imageIDs.end(); ++it) + { + list.append(new ImageInfo(*it)); + } + + emit signalDroppedItems(list); + e->accept(); + return; + } + else if (AlbumDrag::decode(e, urls, albumID)) + { + TQValueList<TQ_LLONG> itemIDs = AlbumManager::instance()->albumDB()->getItemIDsInAlbum(albumID); + + for (TQValueList<TQ_LLONG>::const_iterator it = itemIDs.begin(); + it != itemIDs.end(); ++it) + { + list.append(new ImageInfo(*it)); + } + + emit signalDroppedItems(list); + e->accept(); + return; + } + else if(TagDrag::canDecode(e)) + { + TQByteArray ba = e->encodedData("digikam/tag-id"); + TQDataStream ds(ba, IO_ReadOnly); + int tagID; + ds >> tagID; + + AlbumManager* man = AlbumManager::instance(); + TQValueList<TQ_LLONG> itemIDs = man->albumDB()->getItemIDsInTag(tagID, true); + ImageInfoList imageInfoList; + + for (TQValueList<TQ_LLONG>::const_iterator it = itemIDs.begin(); + it != itemIDs.end(); ++it) + { + list.append(new ImageInfo(*it)); + } + + emit signalDroppedItems(list); + e->accept(); + return; + } + } + + e->ignore(); +} + +void LightTablePreview::setSelected(bool sel) +{ + if (d->selected != sel) + { + d->selected = sel; + frameChanged(); + } +} + +bool LightTablePreview::isSelected() +{ + return d->selected; +} + +void LightTablePreview::drawFrame(TQPainter *p) +{ + if (d->selected) + { + qDrawPlainRect(p, frameRect(), ThemeEngine::instance()->thumbSelColor(), lineWidth()); + qDrawPlainRect(p, frameRect(), ThemeEngine::instance()->textSelColor(), 2); + } + else + qDrawPlainRect(p, frameRect(), ThemeEngine::instance()->baseColor(), lineWidth()); +} + +} // NameSpace Digikam diff --git a/src/utilities/lighttable/lighttablepreview.h b/src/utilities/lighttable/lighttablepreview.h new file mode 100644 index 00000000..3549fa1c --- /dev/null +++ b/src/utilities/lighttable/lighttablepreview.h @@ -0,0 +1,125 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-21-12 + * Description : digiKam light table preview item. + * + * Copyright (C) 2006-2008 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 LIGHTTABLEPREVIEW_H +#define LIGHTTABLEPREVIEW_H + +// TQt includes. + +#include <tqstring.h> +#include <tqimage.h> +#include <tqsize.h> + +// Local includes. + +#include "imageinfo.h" +#include "previewwidget.h" +#include "digikam_export.h" + +class TQPixmap; + +namespace Digikam +{ + +class DImg; +class LoadingDescription; +class LightTablePreviewPriv; + +class DIGIKAM_EXPORT LightTablePreview : public PreviewWidget +{ + +TQ_OBJECT + + +public: + + LightTablePreview(TQWidget *parent=0); + ~LightTablePreview(); + + void setLoadFullImageSize(bool b); + + void setImage(const DImg& image); + DImg& getImage() const; + + TQSize getImageSize(); + + void setImageInfo(ImageInfo* info=0, ImageInfo *previous=0, ImageInfo *next=0); + ImageInfo* getImageInfo() const; + + void reload(); + void setImagePath(const TQString& path=TQString()); + void setPreviousNextPaths(const TQString& previous, const TQString &next); + + void setSelected(bool sel); + bool isSelected(); + + void setDragAndDropEnabled(bool b); + void setDragAndDropMessage(); + +signals: + + void signalDroppedItems(const ImageInfoList&); + void signalDeleteItem(ImageInfo*); + void signalEditItem(ImageInfo*); + void signalPreviewLoaded(bool success); + void signalSlideShow(); + +protected: + + void resizeEvent(TQResizeEvent* e); + void drawFrame(TQPainter *p); + +private slots: + + void slotGotImagePreview(const LoadingDescription &loadingDescription, const DImg &image); + void slotNextPreload(); + void slotContextMenu(); + void slotAssignTag(int tagID); + void slotRemoveTag(int tagID); + void slotAssignRating(int rating); + void slotThemeChanged(); + void slotCornerButtonPressed(); + void slotPanIconSelectionMoved(const TQRect&, bool); + void slotPanIconHiden(); + +private: + + int previewWidth(); + int previewHeight(); + bool previewIsNull(); + void resetPreview(); + void zoomFactorChanged(double zoom); + void updateZoomAndSize(bool alwaysFitToWindow); + inline void paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh); + + void contentsDragMoveEvent(TQDragMoveEvent*); + void contentsDropEvent(TQDropEvent*); + +private: + + LightTablePreviewPriv* d; +}; + +} // NameSpace Digikam + +#endif /* LIGHTTABLEPREVIEW_H */ diff --git a/src/utilities/lighttable/lighttableview.cpp b/src/utilities/lighttable/lighttableview.cpp new file mode 100644 index 00000000..51f45ab5 --- /dev/null +++ b/src/utilities/lighttable/lighttableview.cpp @@ -0,0 +1,446 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-03-05 + * Description : a widget to display 2 preview image on + * lightable to compare pictures. + * + * Copyright (C) 2007-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 <tqlayout.h> + +// KDE includes. + +#include <kdialogbase.h> + +// Local includes. + +#include "ddebug.h" +#include "thumbnailsize.h" +#include "lighttablepreview.h" +#include "lighttableview.h" +#include "lighttableview.moc" + +namespace Digikam +{ + +class LightTableViewPriv +{ +public: + + LightTableViewPriv() + { + syncPreview = false; + leftLoading = false; + rightLoading = false; + leftPreview = 0; + rightPreview = 0; + grid = 0; + } + + bool syncPreview; + bool leftLoading; // To not sync right panel during left loading. + bool rightLoading; // To not sync left panel during right loading. + + TQGridLayout *grid; + + LightTablePreview *leftPreview; + LightTablePreview *rightPreview; +}; + +LightTableView::LightTableView(TQWidget *parent) + : TQFrame(parent, 0, TQt::WDestructiveClose) +{ + d = new LightTableViewPriv; + + setFrameStyle(TQFrame::NoFrame); + setMargin(0); + setLineWidth(0); + + d->grid = new TQGridLayout(this, 1, 1, 0, 1); + d->leftPreview = new LightTablePreview(this); + d->rightPreview = new LightTablePreview(this); + + d->grid->addMultiCellWidget(d->leftPreview, 0, 0, 0, 0); + d->grid->addMultiCellWidget(d->rightPreview, 0, 0, 1, 1); + + d->grid->setColStretch(0, 10), + d->grid->setColStretch(1, 10), + d->grid->setRowStretch(0, 10), + + // Left panel connections ------------------------------------------------ + + connect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_SIGNAL(signalLeftZoomFactorChanged(double))); + + connect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)), + this, TQ_SLOT(slotLeftContentsMoved(int, int))); + + connect(d->leftPreview, TQ_SIGNAL(signalSlideShow()), + this, TQ_SIGNAL(signalSlideShow())); + + connect(d->leftPreview, TQ_SIGNAL(signalDeleteItem(ImageInfo*)), + this, TQ_SIGNAL(signalDeleteItem(ImageInfo*))); + + connect(d->leftPreview, TQ_SIGNAL(signalEditItem(ImageInfo*)), + this, TQ_SIGNAL(signalEditItem(ImageInfo*))); + + connect(d->leftPreview, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)), + this, TQ_SIGNAL(signalLeftDroppedItems(const ImageInfoList&))); + + connect(d->leftPreview, TQ_SIGNAL(signalPreviewLoaded(bool)), + this, TQ_SLOT(slotLeftPreviewLoaded(bool))); + + connect(d->leftPreview, TQ_SIGNAL(signalLeftButtonClicked()), + this, TQ_SIGNAL(signalLeftPanelLeftButtonClicked())); + + // Right panel connections ------------------------------------------------ + + connect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_SIGNAL(signalRightZoomFactorChanged(double))); + + connect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)), + this, TQ_SLOT(slotRightContentsMoved(int, int))); + + connect(d->rightPreview, TQ_SIGNAL(signalDeleteItem(ImageInfo*)), + this, TQ_SIGNAL(signalDeleteItem(ImageInfo*))); + + connect(d->rightPreview, TQ_SIGNAL(signalEditItem(ImageInfo*)), + this, TQ_SIGNAL(signalEditItem(ImageInfo*))); + + connect(d->rightPreview, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)), + this, TQ_SIGNAL(signalRightDroppedItems(const ImageInfoList&))); + + connect(d->rightPreview, TQ_SIGNAL(signalSlideShow()), + this, TQ_SIGNAL(signalSlideShow())); + + connect(d->rightPreview, TQ_SIGNAL(signalPreviewLoaded(bool)), + this, TQ_SLOT(slotRightPreviewLoaded(bool))); + + connect(d->rightPreview, TQ_SIGNAL(signalLeftButtonClicked()), + this, TQ_SIGNAL(signalRightPanelLeftButtonClicked())); +} + +LightTableView::~LightTableView() +{ + delete d; +} + +void LightTableView::setLoadFullImageSize(bool b) +{ + d->leftPreview->setLoadFullImageSize(b); + d->rightPreview->setLoadFullImageSize(b); +} + +void LightTableView::setSyncPreview(bool sync) +{ + d->syncPreview = sync; + + // Left panel like a reference to resync preview. + if (d->syncPreview) + slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY()); +} + +void LightTableView::setNavigateByPair(bool b) +{ + d->leftPreview->setDragAndDropEnabled(!b); + d->rightPreview->setDragAndDropEnabled(!b); +} + +void LightTableView::slotDecreaseZoom() +{ + if (d->syncPreview) + { + slotDecreaseLeftZoom(); + return; + } + + if (d->leftPreview->isSelected()) + slotDecreaseLeftZoom(); + else if (d->rightPreview->isSelected()) + slotDecreaseRightZoom(); +} + +void LightTableView::slotIncreaseZoom() +{ + if (d->syncPreview) + { + slotIncreaseLeftZoom(); + return; + } + + if (d->leftPreview->isSelected()) + slotIncreaseLeftZoom(); + else if (d->rightPreview->isSelected()) + slotIncreaseRightZoom(); +} + +void LightTableView::slotDecreaseLeftZoom() +{ + d->leftPreview->slotDecreaseZoom(); +} + +void LightTableView::slotIncreaseLeftZoom() +{ + d->leftPreview->slotIncreaseZoom(); +} + +void LightTableView::slotDecreaseRightZoom() +{ + d->rightPreview->slotDecreaseZoom(); +} + +void LightTableView::slotIncreaseRightZoom() +{ + d->rightPreview->slotIncreaseZoom(); +} + +void LightTableView::setLeftZoomFactor(double z) +{ + d->leftPreview->setZoomFactor(z); +} + +void LightTableView::setRightZoomFactor(double z) +{ + d->rightPreview->setZoomFactor(z); +} + +void LightTableView::fitToWindow() +{ + d->leftPreview->fitToWindow(); + d->rightPreview->fitToWindow(); +} + +void LightTableView::toggleFitToWindowOr100() +{ + // If we are currently precisely at 100%, then fit to window, + // otherwise zoom to a centered 100% view. + if ((d->leftPreview->zoomFactor()==1.0) && + (d->rightPreview->zoomFactor()==1.0)) + { + fitToWindow(); + } + else + { + d->leftPreview->setZoomFactor(1.0, true); + d->rightPreview->setZoomFactor(1.0, true); + } +} + +double LightTableView::leftZoomMax() +{ + return d->leftPreview->zoomMax(); +} + +double LightTableView::leftZoomMin() +{ + return d->leftPreview->zoomMin(); +} + +bool LightTableView::leftMaxZoom() +{ + return d->leftPreview->maxZoom(); +} + +bool LightTableView::leftMinZoom() +{ + return d->leftPreview->minZoom(); +} + +double LightTableView::rightZoomMax() +{ + return d->rightPreview->zoomMax(); +} + +double LightTableView::rightZoomMin() +{ + return d->rightPreview->zoomMin(); +} + +bool LightTableView::rightMaxZoom() +{ + return d->rightPreview->maxZoom(); +} + +bool LightTableView::rightMinZoom() +{ + return d->rightPreview->minZoom(); +} + +void LightTableView::slotLeftZoomSliderChanged(int size) +{ + double h = (double)ThumbnailSize::Huge; + double s = (double)ThumbnailSize::Small; + double zmin = d->leftPreview->zoomMin(); + double zmax = d->leftPreview->zoomMax(); + double b = (zmin-(zmax*s/h))/(1-s/h); + double a = (zmax-b)/h; + double z = a*size+b; + + d->leftPreview->setZoomFactorSnapped(z); +} + +void LightTableView::slotRightZoomSliderChanged(int size) +{ + double h = (double)ThumbnailSize::Huge; + double s = (double)ThumbnailSize::Small; + double zmin = d->rightPreview->zoomMin(); + double zmax = d->rightPreview->zoomMax(); + double b = (zmin-(zmax*s/h))/(1-s/h); + double a = (zmax-b)/h; + double z = a*size+b; + + d->rightPreview->setZoomFactorSnapped(z); +} + +void LightTableView::leftReload() +{ + d->leftPreview->reload(); +} + +void LightTableView::rightReload() +{ + d->rightPreview->reload(); +} + +void LightTableView::slotLeftContentsMoved(int x, int y) +{ + if (d->syncPreview && !d->leftLoading) + { + disconnect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_SIGNAL(signalRightZoomFactorChanged(double))); + + disconnect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)), + this, TQ_SLOT(slotRightContentsMoved(int, int))); + + setRightZoomFactor(d->leftPreview->zoomFactor()); + emit signalRightZoomFactorChanged(d->leftPreview->zoomFactor()); + d->rightPreview->setContentsPos(x, y); + + connect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_SIGNAL(signalRightZoomFactorChanged(double))); + + connect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)), + this, TQ_SLOT(slotRightContentsMoved(int, int))); + } +} + +void LightTableView::slotRightContentsMoved(int x, int y) +{ + if (d->syncPreview && !d->rightLoading) + { + disconnect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_SIGNAL(signalLeftZoomFactorChanged(double))); + + disconnect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)), + this, TQ_SLOT(slotLeftContentsMoved(int, int))); + + + setLeftZoomFactor(d->rightPreview->zoomFactor()); + emit signalLeftZoomFactorChanged(d->rightPreview->zoomFactor()); + d->leftPreview->setContentsPos(x, y); + + connect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_SIGNAL(signalLeftZoomFactorChanged(double))); + + connect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)), + this, TQ_SLOT(slotLeftContentsMoved(int, int))); + } +} + +ImageInfo* LightTableView::leftImageInfo() const +{ + return d->leftPreview->getImageInfo(); +} + +ImageInfo* LightTableView::rightImageInfo() const +{ + return d->rightPreview->getImageInfo(); +} + +void LightTableView::setLeftImageInfo(ImageInfo* info) +{ + d->leftLoading = true; + d->leftPreview->setImageInfo(info); +} + +void LightTableView::setRightImageInfo(ImageInfo* info) +{ + d->rightLoading = true; + d->rightPreview->setImageInfo(info); +} + +void LightTableView::slotLeftPreviewLoaded(bool success) +{ + checkForSyncPreview(); + d->leftLoading = false; + slotRightContentsMoved(d->rightPreview->contentsX(), + d->rightPreview->contentsY()); + + emit signalLeftPreviewLoaded(success); +} + +void LightTableView::slotRightPreviewLoaded(bool success) +{ + checkForSyncPreview(); + d->rightLoading = false; + slotLeftContentsMoved(d->leftPreview->contentsX(), + d->leftPreview->contentsY()); + + emit signalRightPreviewLoaded(success); +} + +void LightTableView::checkForSyncPreview() +{ + if (d->leftPreview->getImageInfo() && d->rightPreview->getImageInfo() && + d->leftPreview->getImageSize() == d->rightPreview->getImageSize()) + { + d->syncPreview = true; + } + else + { + d->syncPreview = false; + } + + emit signalToggleOnSyncPreview(d->syncPreview); +} + +void LightTableView::checkForSelection(ImageInfo* info) +{ + if (!info) + { + d->leftPreview->setSelected(false); + d->rightPreview->setSelected(false); + return; + } + + if (d->leftPreview->getImageInfo()) + { + d->leftPreview->setSelected(d->leftPreview->getImageInfo()->id() == info->id()); + } + + if (d->rightPreview->getImageInfo()) + { + d->rightPreview->setSelected(d->rightPreview->getImageInfo()->id() == info->id()); + } +} + +} // namespace Digikam + diff --git a/src/utilities/lighttable/lighttableview.h b/src/utilities/lighttable/lighttableview.h new file mode 100644 index 00000000..273b7072 --- /dev/null +++ b/src/utilities/lighttable/lighttableview.h @@ -0,0 +1,137 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-03-05 + * Description : a widget to display 2 preview image on + * lightable to compare pictures. + * + * Copyright (C) 2007-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 LIGHTTABLEVIEW_H +#define LIGHTTABLEVIEW_H + +// TQt includes. + +#include <tqframe.h> +#include <tqstring.h> + +// Local includes. + +#include "imageinfo.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class LightTableViewPriv; + +class DIGIKAM_EXPORT LightTableView : public TQFrame +{ + +TQ_OBJECT + + +public: + + LightTableView(TQWidget *parent=0); + ~LightTableView(); + + void setSyncPreview(bool sync); + void setNavigateByPair(bool b); + + void setLeftImageInfo(ImageInfo* info=0); + void setRightImageInfo(ImageInfo* info=0); + + ImageInfo* leftImageInfo() const; + ImageInfo* rightImageInfo() const; + + void setLoadFullImageSize(bool b); + + void setLeftZoomFactor(double z); + void setRightZoomFactor(double z); + + void checkForSelection(ImageInfo* info); + + double leftZoomMax(); + double leftZoomMin(); + + double rightZoomMax(); + double rightZoomMin(); + + bool leftMaxZoom(); + bool leftMinZoom(); + + bool rightMaxZoom(); + bool rightMinZoom(); + + void leftReload(); + void rightReload(); + + void fitToWindow(); + void toggleFitToWindowOr100(); + +signals: + + void signalLeftPreviewLoaded(bool); + void signalRightPreviewLoaded(bool); + + void signalLeftZoomFactorChanged(double); + void signalRightZoomFactorChanged(double); + + void signalLeftDroppedItems(const ImageInfoList&); + void signalRightDroppedItems(const ImageInfoList&); + + void signalLeftPanelLeftButtonClicked(); + void signalRightPanelLeftButtonClicked(); + + void signalSlideShow(); + void signalDeleteItem(ImageInfo*); + void signalEditItem(ImageInfo*); + void signalToggleOnSyncPreview(bool); + +public slots: + + void slotDecreaseZoom(); + void slotIncreaseZoom(); + void slotDecreaseLeftZoom(); + void slotIncreaseLeftZoom(); + void slotLeftZoomSliderChanged(int); + + void slotDecreaseRightZoom(); + void slotIncreaseRightZoom(); + void slotRightZoomSliderChanged(int); + +private slots: + + void slotLeftContentsMoved(int, int); + void slotRightContentsMoved(int, int); + void slotLeftPreviewLoaded(bool); + void slotRightPreviewLoaded(bool); + +private : + + void checkForSyncPreview(); + +private : + + LightTableViewPriv* d; +}; + +} // namespace Digikam + +#endif /* LIGHTTABLEVIEW_H */ diff --git a/src/utilities/lighttable/lighttablewindow.cpp b/src/utilities/lighttable/lighttablewindow.cpp new file mode 100644 index 00000000..58409aef --- /dev/null +++ b/src/utilities/lighttable/lighttablewindow.cpp @@ -0,0 +1,1676 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-03-05 + * Description : digiKam light table GUI + * + * Copyright (C) 2007-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 <tqdockarea.h> + +// KDE includes. + +#include <kkeydialog.h> +#include <kedittoolbar.h> +#include <tdeversion.h> +#include <tdelocale.h> +#include <twin.h> +#include <tdemessagebox.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kstatusbar.h> +#include <tdemenubar.h> + +// LibKDcraw includes. + +#include <libkdcraw/version.h> +#include <libkdcraw/kdcraw.h> + +#if KDCRAW_VERSION < 0x000106 +#include <libkdcraw/dcrawbinary.h> +#endif + +// Local includes. + +#include "ddebug.h" +#include "dlogoaction.h" +#include "themeengine.h" +#include "dimg.h" +#include "dmetadata.h" +#include "albumsettings.h" +#include "albummanager.h" +#include "deletedialog.h" +#include "imagewindow.h" +#include "slideshow.h" +#include "setup.h" +#include "syncjob.h" +#include "thumbnailsize.h" +#include "rawcameradlg.h" +#include "lighttablepreview.h" +#include "lighttablewindowprivate.h" +#include "lighttablewindow.h" +#include "lighttablewindow.moc" + +namespace Digikam +{ + +LightTableWindow* LightTableWindow::m_instance = 0; + +LightTableWindow* LightTableWindow::lightTableWindow() +{ + if (!m_instance) + new LightTableWindow(); + + return m_instance; +} + +bool LightTableWindow::lightTableWindowCreated() +{ + return m_instance; +} + +LightTableWindow::LightTableWindow() + : TDEMainWindow(0, "lighttable", WType_TopLevel) +{ + d = new LightTableWindowPriv; + m_instance = this; + + setCaption(i18n("Light Table")); + + // -- Build the GUI ------------------------------- + + setupUserArea(); + setupStatusBar(); + setupActions(); + setupAccelerators(); + + // Make signals/slots connections + + setupConnections(); + + //------------------------------------------------------------- + + d->leftSidebar->loadViewState(); + d->rightSidebar->loadViewState(); + d->leftSidebar->populateTags(); + d->rightSidebar->populateTags(); + + readSettings(); + applySettings(); + setAutoSaveSettings("LightTable Settings"); +} + +LightTableWindow::~LightTableWindow() +{ + m_instance = 0; + + delete d->barView; + delete d->rightSidebar; + delete d->leftSidebar; + delete d; +} + +void LightTableWindow::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("LightTable Settings"); + + if(config->hasKey("Vertical Splitter Sizes")) + d->vSplitter->setSizes(config->readIntListEntry("Vertical Splitter Sizes")); + + if(config->hasKey("Horizontal Splitter Sizes")) + d->hSplitter->setSizes(config->readIntListEntry("Horizontal Splitter Sizes")); + + d->navigateByPairAction->setChecked(config->readBoolEntry("Navigate By Pair", false)); + slotToggleNavigateByPair(); +} + +void LightTableWindow::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("LightTable Settings"); + config->writeEntry("Vertical Splitter Sizes", d->vSplitter->sizes()); + config->writeEntry("Horizontal Splitter Sizes", d->hSplitter->sizes()); + config->writeEntry("Navigate By Pair", d->navigateByPairAction->isChecked()); + config->sync(); +} + +void LightTableWindow::applySettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("LightTable Settings"); + + d->autoLoadOnRightPanel = config->readBoolEntry("Auto Load Right Panel", true); + d->autoSyncPreview = config->readBoolEntry("Auto Sync Preview", true); + d->fullScreenHideToolBar = config->readBoolEntry("FullScreen Hide ToolBar", false); + d->previewView->setLoadFullImageSize(config->readBoolEntry("Load Full Image size", false)); + refreshView(); +} + +void LightTableWindow::refreshView() +{ + d->leftSidebar->refreshTagsView(); + d->rightSidebar->refreshTagsView(); +} + +void LightTableWindow::closeEvent(TQCloseEvent* e) +{ + if (!e) return; + + writeSettings(); + + e->accept(); +} + +void LightTableWindow::setupUserArea() +{ + TQWidget* mainW = new TQWidget(this); + d->hSplitter = new TQSplitter(TQt::Horizontal, mainW); + TQHBoxLayout *hlay = new TQHBoxLayout(mainW); + d->leftSidebar = new ImagePropertiesSideBarDB(mainW, + "LightTable Left Sidebar", d->hSplitter, + Sidebar::Left, true); + + TQWidget* centralW = new TQWidget(d->hSplitter); + TQVBoxLayout *vlay = new TQVBoxLayout(centralW); + d->vSplitter = new TQSplitter(TQt::Vertical, centralW); + d->barView = new LightTableBar(d->vSplitter, ThumbBarView::Horizontal, + AlbumSettings::instance()->getExifRotate()); + d->previewView = new LightTableView(d->vSplitter); + vlay->addWidget(d->vSplitter); + + d->rightSidebar = new ImagePropertiesSideBarDB(mainW, + "LightTable Right Sidebar", d->hSplitter, + Sidebar::Right, true); + + hlay->addWidget(d->leftSidebar); + hlay->addWidget(d->hSplitter); + hlay->addWidget(d->rightSidebar); + + d->hSplitter->setFrameStyle( TQFrame::NoFrame ); + d->hSplitter->setFrameShadow( TQFrame::Plain ); + d->hSplitter->setFrameShape( TQFrame::NoFrame ); + d->hSplitter->setOpaqueResize(false); + d->vSplitter->setFrameStyle( TQFrame::NoFrame ); + d->vSplitter->setFrameShadow( TQFrame::Plain ); + d->vSplitter->setFrameShape( TQFrame::NoFrame ); + d->vSplitter->setOpaqueResize(false); + + setCentralWidget(mainW); +} + +void LightTableWindow::setupStatusBar() +{ + d->leftZoomBar = new StatusZoomBar(statusBar()); + d->leftZoomBar->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(d->leftZoomBar, 1); + d->leftZoomBar->setEnabled(false); + + d->statusProgressBar = new StatusProgressBar(statusBar()); + d->statusProgressBar->setAlignment(TQt::AlignCenter); + d->statusProgressBar->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(d->statusProgressBar, 100); + + d->rightZoomBar = new StatusZoomBar(statusBar()); + d->rightZoomBar->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(d->rightZoomBar, 1); + d->rightZoomBar->setEnabled(false); +} + +void LightTableWindow::setupConnections() +{ + connect(d->statusProgressBar, TQ_SIGNAL(signalCancelButtonPressed()), + this, TQ_SLOT(slotProgressBarCancelButtonPressed())); + + connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), + this, TQ_SLOT(slotThemeChanged())); + + // Thumbs bar connections --------------------------------------- + + connect(d->barView, TQ_SIGNAL(signalSetItemOnLeftPanel(ImageInfo*)), + this, TQ_SLOT(slotSetItemOnLeftPanel(ImageInfo*))); + + connect(d->barView, TQ_SIGNAL(signalSetItemOnRightPanel(ImageInfo*)), + this, TQ_SLOT(slotSetItemOnRightPanel(ImageInfo*))); + + connect(d->barView, TQ_SIGNAL(signalRemoveItem(ImageInfo*)), + this, TQ_SLOT(slotRemoveItem(ImageInfo*))); + + connect(d->barView, TQ_SIGNAL(signalEditItem(ImageInfo*)), + this, TQ_SLOT(slotEditItem(ImageInfo*))); + + connect(d->barView, TQ_SIGNAL(signalClearAll()), + this, TQ_SLOT(slotClearItemsList())); + + connect(d->barView, TQ_SIGNAL(signalLightTableBarItemSelected(ImageInfo*)), + this, TQ_SLOT(slotItemSelected(ImageInfo*))); + + connect(d->barView, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)), + this, TQ_SLOT(slotThumbbarDroppedItems(const ImageInfoList&))); + + // Zoom bars connections ----------------------------------------- + + connect(d->leftZoomBar, TQ_SIGNAL(signalZoomMinusClicked()), + d->previewView, TQ_SLOT(slotDecreaseLeftZoom())); + + connect(d->leftZoomBar, TQ_SIGNAL(signalZoomPlusClicked()), + d->previewView, TQ_SLOT(slotIncreaseLeftZoom())); + + connect(d->leftZoomBar, TQ_SIGNAL(signalZoomSliderChanged(int)), + d->previewView, TQ_SLOT(slotLeftZoomSliderChanged(int))); + + connect(d->rightZoomBar, TQ_SIGNAL(signalZoomMinusClicked()), + d->previewView, TQ_SLOT(slotDecreaseRightZoom())); + + connect(d->rightZoomBar, TQ_SIGNAL(signalZoomPlusClicked()), + d->previewView, TQ_SLOT(slotIncreaseRightZoom())); + + connect(d->rightZoomBar, TQ_SIGNAL(signalZoomSliderChanged(int)), + d->previewView, TQ_SLOT(slotRightZoomSliderChanged(int))); + + // View connections --------------------------------------------- + + connect(d->previewView, TQ_SIGNAL(signalLeftZoomFactorChanged(double)), + this, TQ_SLOT(slotLeftZoomFactorChanged(double))); + + connect(d->previewView, TQ_SIGNAL(signalRightZoomFactorChanged(double)), + this, TQ_SLOT(slotRightZoomFactorChanged(double))); + + connect(d->previewView, TQ_SIGNAL(signalEditItem(ImageInfo*)), + this, TQ_SLOT(slotEditItem(ImageInfo*))); + + connect(d->previewView, TQ_SIGNAL(signalDeleteItem(ImageInfo*)), + this, TQ_SLOT(slotDeleteItem(ImageInfo*))); + + connect(d->previewView, TQ_SIGNAL(signalSlideShow()), + this, TQ_SLOT(slotToggleSlideShow())); + + connect(d->previewView, TQ_SIGNAL(signalLeftDroppedItems(const ImageInfoList&)), + this, TQ_SLOT(slotLeftDroppedItems(const ImageInfoList&))); + + connect(d->previewView, TQ_SIGNAL(signalRightDroppedItems(const ImageInfoList&)), + this, TQ_SLOT(slotRightDroppedItems(const ImageInfoList&))); + + connect(d->previewView, TQ_SIGNAL(signalToggleOnSyncPreview(bool)), + this, TQ_SLOT(slotToggleOnSyncPreview(bool))); + + connect(d->previewView, TQ_SIGNAL(signalLeftPreviewLoaded(bool)), + this, TQ_SLOT(slotLeftPreviewLoaded(bool))); + + connect(d->previewView, TQ_SIGNAL(signalRightPreviewLoaded(bool)), + this, TQ_SLOT(slotRightPreviewLoaded(bool))); + + connect(d->previewView, TQ_SIGNAL(signalLeftPanelLeftButtonClicked()), + this, TQ_SLOT(slotLeftPanelLeftButtonClicked())); + + connect(d->previewView, TQ_SIGNAL(signalRightPanelLeftButtonClicked()), + this, TQ_SLOT(slotRightPanelLeftButtonClicked())); +} + +void LightTableWindow::setupActions() +{ + // -- Standard 'File' menu actions --------------------------------------------- + + d->backwardAction = KStdAction::back(this, TQ_SLOT(slotBackward()), + actionCollection(), "lighttable_backward"); + d->backwardAction->setEnabled(false); + + d->forwardAction = KStdAction::forward(this, TQ_SLOT(slotForward()), + actionCollection(), "lighttable_forward"); + d->forwardAction->setEnabled(false); + + d->firstAction = new TDEAction(i18n("&First"), "go-first", + TDEStdAccel::shortcut( TDEStdAccel::Home), + this, TQ_SLOT(slotFirst()), + actionCollection(), "lighttable_first"); + d->firstAction->setEnabled(false); + + d->lastAction = new TDEAction(i18n("&Last"), "go-last", + TDEStdAccel::shortcut( TDEStdAccel::End), + this, TQ_SLOT(slotLast()), + actionCollection(), "lighttable_last"); + d->lastAction->setEnabled(false); + + d->setItemLeftAction = new TDEAction(i18n("On Left"), "go-previous", + CTRL+Key_L, this, TQ_SLOT(slotSetItemLeft()), + actionCollection(), "lighttable_setitemleft"); + d->setItemLeftAction->setEnabled(false); + d->setItemLeftAction->setWhatsThis(i18n("Show item on left panel")); + + d->setItemRightAction = new TDEAction(i18n("On Right"), "go-next", + CTRL+Key_R, this, TQ_SLOT(slotSetItemRight()), + actionCollection(), "lighttable_setitemright"); + d->setItemRightAction->setEnabled(false); + d->setItemRightAction->setWhatsThis(i18n("Show item on right panel")); + + d->editItemAction = new TDEAction(i18n("Edit"), "editimage", + Key_F4, this, TQ_SLOT(slotEditItem()), + actionCollection(), "lighttable_edititem"); + d->editItemAction->setEnabled(false); + + d->removeItemAction = new TDEAction(i18n("Remove item from LightTable"), "window-close", + CTRL+Key_K, this, TQ_SLOT(slotRemoveItem()), + actionCollection(), "lighttable_removeitem"); + d->removeItemAction->setEnabled(false); + + d->clearListAction = new TDEAction(i18n("Remove all items from LightTable"), "editshred", + CTRL+SHIFT+Key_K, this, TQ_SLOT(slotClearItemsList()), + actionCollection(), "lighttable_clearlist"); + d->clearListAction->setEnabled(false); + + d->fileDeleteAction = new TDEAction(i18n("Move to Trash"), "edittrash", + Key_Delete, + this, TQ_SLOT(slotDeleteItem()), + actionCollection(), "lighttable_filedelete"); + d->fileDeleteAction->setEnabled(false); + + KStdAction::close(this, TQ_SLOT(close()), actionCollection(), "lighttable_close"); + + // -- Standard 'View' menu actions --------------------------------------------- + + d->syncPreviewAction = new TDEToggleAction(i18n("Synchronize"), "goto", + CTRL+SHIFT+Key_Y, this, + TQ_SLOT(slotToggleSyncPreview()), + actionCollection(), "lighttable_syncpreview"); + d->syncPreviewAction->setEnabled(false); + d->syncPreviewAction->setWhatsThis(i18n("Synchronize preview from left and right panels")); + + d->navigateByPairAction = new TDEToggleAction(i18n("By Pair"), "preferences-system", + CTRL+SHIFT+Key_P, this, + TQ_SLOT(slotToggleNavigateByPair()), + actionCollection(), "lighttable_navigatebypair"); + d->navigateByPairAction->setEnabled(false); + d->navigateByPairAction->setWhatsThis(i18n("Navigate by pair with all items")); + + d->zoomPlusAction = KStdAction::zoomIn(d->previewView, TQ_SLOT(slotIncreaseZoom()), + actionCollection(), "lighttable_zoomplus"); + d->zoomPlusAction->setEnabled(false); + + d->zoomMinusAction = KStdAction::zoomOut(d->previewView, TQ_SLOT(slotDecreaseZoom()), + actionCollection(), "lighttable_zoomminus"); + d->zoomMinusAction->setEnabled(false); + + d->zoomTo100percents = new TDEAction(i18n("Zoom to 100%"), "zoom-original", + ALT+CTRL+Key_0, // NOTE: Photoshop 7 use ALT+CTRL+0. + this, TQ_SLOT(slotZoomTo100Percents()), + actionCollection(), "lighttable_zoomto100percents"); + + d->zoomFitToWindowAction = new TDEAction(i18n("Fit to &Window"), "view_fit_window", + CTRL+SHIFT+Key_E, this, TQ_SLOT(slotFitToWindow()), + actionCollection(), "lighttable_zoomfit2window"); + + // Do not use std KDE action for full screen because action text is too large for app. toolbar. + d->fullScreenAction = new TDEToggleAction(i18n("Full Screen"), "view-fullscreen", + CTRL+SHIFT+Key_F, this, + TQ_SLOT(slotToggleFullScreen()), + actionCollection(), "lighttable_fullscreen"); + d->fullScreenAction->setWhatsThis(i18n("Toggle the window to full screen mode")); + + d->slideShowAction = new TDEAction(i18n("Slideshow"), "slideshow", Key_F9, + this, TQ_SLOT(slotToggleSlideShow()), + actionCollection(),"lighttable_slideshow"); + + // -- Standard 'Configure' menu actions ---------------------------------------- + + d->showMenuBarAction = KStdAction::showMenubar(this, TQ_SLOT(slotShowMenuBar()), actionCollection()); + + KStdAction::keyBindings(this, TQ_SLOT(slotEditKeys()), actionCollection()); + KStdAction::configureToolbars(this, TQ_SLOT(slotConfToolbars()), actionCollection()); + KStdAction::preferences(this, TQ_SLOT(slotSetup()), actionCollection()); + + // ----------------------------------------------------------------------------------------- + + d->themeMenuAction = new TDESelectAction(i18n("&Themes"), 0, actionCollection(), "theme_menu"); + connect(d->themeMenuAction, TQ_SIGNAL(activated(const TQString&)), + this, TQ_SLOT(slotChangeTheme(const TQString&))); + + d->themeMenuAction->setItems(ThemeEngine::instance()->themeNames()); + slotThemeChanged(); + + // -- Standard 'Help' menu actions --------------------------------------------- + + + d->donateMoneyAction = new TDEAction(i18n("Donate..."), + 0, 0, + this, TQ_SLOT(slotDonateMoney()), + actionCollection(), + "lighttable_donatemoney"); + + d->contributeAction = new TDEAction(i18n("Contribute..."), + 0, 0, + this, TQ_SLOT(slotContribute()), + actionCollection(), + "lighttable_contribute"); + + d->rawCameraListAction = new TDEAction(i18n("Supported RAW Cameras"), + "kdcraw", + 0, + this, + TQ_SLOT(slotRawCameraList()), + actionCollection(), + "lighttable_rawcameralist"); + + + // Provides a menu entry that allows showing/hiding the toolbar(s) + setStandardToolBarMenuEnabled(true); + + // Provides a menu entry that allows showing/hiding the statusbar + createStandardStatusBarAction(); + + // -- Rating actions --------------------------------------------------------------- + + d->star0 = new TDEAction(i18n("Assign Rating \"No Stars\""), CTRL+Key_0, + d->barView, TQ_SLOT(slotAssignRatingNoStar()), + actionCollection(), "lighttable_ratenostar"); + d->star1 = new TDEAction(i18n("Assign Rating \"One Star\""), CTRL+Key_1, + d->barView, TQ_SLOT(slotAssignRatingOneStar()), + actionCollection(), "lighttable_rateonestar"); + d->star2 = new TDEAction(i18n("Assign Rating \"Two Stars\""), CTRL+Key_2, + d->barView, TQ_SLOT(slotAssignRatingTwoStar()), + actionCollection(), "lighttable_ratetwostar"); + d->star3 = new TDEAction(i18n("Assign Rating \"Three Stars\""), CTRL+Key_3, + d->barView, TQ_SLOT(slotAssignRatingThreeStar()), + actionCollection(), "lighttable_ratethreestar"); + d->star4 = new TDEAction(i18n("Assign Rating \"Four Stars\""), CTRL+Key_4, + d->barView, TQ_SLOT(slotAssignRatingFourStar()), + actionCollection(), "lighttable_ratefourstar"); + d->star5 = new TDEAction(i18n("Assign Rating \"Five Stars\""), CTRL+Key_5, + d->barView, TQ_SLOT(slotAssignRatingFiveStar()), + actionCollection(), "lighttable_ratefivestar"); + + // --------------------------------------------------------------------------------- + + new DLogoAction(actionCollection(), "logo_action"); + + createGUI("lighttablewindowui.rc", false); +} + +void LightTableWindow::setupAccelerators() +{ + d->accelerators = new TDEAccel(this); + + d->accelerators->insert("Exit fullscreen", i18n("Exit Fullscreen mode"), + i18n("Exit fullscreen viewing mode"), + Key_Escape, this, TQ_SLOT(slotEscapePressed()), + false, true); + + d->accelerators->insert("Next Image Key_Space", i18n("Next Image"), + i18n("Load Next Image"), + Key_Space, this, TQ_SLOT(slotForward()), + false, true); + + d->accelerators->insert("Previous Image SHIFT+Key_Space", i18n("Previous Image"), + i18n("Load Previous Image"), + SHIFT+Key_Space, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Previous Image Key_Backspace", i18n("Previous Image"), + i18n("Load Previous Image"), + Key_Backspace, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Next Image Key_Next", i18n("Next Image"), + i18n("Load Next Image"), + Key_Next, this, TQ_SLOT(slotForward()), + false, true); + + d->accelerators->insert("Previous Image Key_Prior", i18n("Previous Image"), + i18n("Load Previous Image"), + Key_Prior, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Zoom Plus Key_Plus", i18n("Zoom in"), + i18n("Zoom in on image"), + Key_Plus, d->previewView, TQ_SLOT(slotIncreaseZoom()), + false, true); + + d->accelerators->insert("Zoom Plus Key_Minus", i18n("Zoom out"), + i18n("Zoom out from image"), + Key_Minus, d->previewView, TQ_SLOT(slotDecreaseZoom()), + false, true); +} + +// Deal with items dropped onto the thumbbar (e.g. from the Album view) +void LightTableWindow::slotThumbbarDroppedItems(const ImageInfoList& list) +{ + // Setting the third parameter of loadImageInfos to true + // means that the images are added to the presently available images. + loadImageInfos(list, 0, true); +} + +// We get here either +// - via CTRL+L (from the albumview) +// a) digikamapp.cpp: CTRL+key_L leads to slotImageLightTable()) +// b) digikamview.cpp: void DigikamView::slotImageLightTable() +// calls d->iconView->insertToLightTable(list, info); +// c) albumiconview.cpp: AlbumIconView::insertToLightTable +// calls ltview->loadImageInfos(list, current); +// - via drag&drop, i.e. calls issued by the ...Dropped... routines +void LightTableWindow::loadImageInfos(const ImageInfoList &list, + ImageInfo *imageInfoCurrent, + bool addTo) +{ + // Clear all items before adding new images to the light table. + if (!addTo) + slotClearItemsList(); + + ImageInfoList l = list; + + if (!imageInfoCurrent) + imageInfoCurrent = l.first(); + + AlbumSettings *settings = AlbumSettings::instance(); + if (!settings) return; + + TQString imagefilter = settings->getImageFileFilter().lower() + + settings->getImageFileFilter().upper(); + +#if KDCRAW_VERSION < 0x000106 + if (KDcrawIface::DcrawBinary::instance()->versionIsRight()) + { + // add raw files only if dcraw is available + imagefilter += settings->getRawFileFilter().lower() + + settings->getRawFileFilter().upper(); + } +#else + imagefilter += settings->getRawFileFilter().lower() + + settings->getRawFileFilter().upper(); +#endif + + d->barView->blockSignals(true); + for (TQPtrList<ImageInfo>::const_iterator it = l.begin(); it != l.end(); ++it) + { + TQString fileExtension = (*it)->kurl().fileName().section( '.', -1 ); + + if ( imagefilter.find(fileExtension) != -1 && + !d->barView->findItemByInfo(*it) ) + { + new LightTableBarItem(d->barView, *it); + } + } + d->barView->blockSignals(false); + + // if window is iconified, show it + if (isMinimized()) + { + KWin::deIconifyWindow(winId()); + } + + refreshStatusBar(); +} + +void LightTableWindow::refreshStatusBar() +{ + switch (d->barView->countItems()) + { + case 0: + d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode, + i18n("No item on Light Table")); + break; + case 1: + d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode, + i18n("1 item on Light Table")); + break; + default: + d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode, + i18n("%1 items on Light Table") + .arg(d->barView->countItems())); + break; + } +} + +void LightTableWindow::slotItemsUpdated(const KURL::List& urls) +{ + d->barView->refreshThumbs(urls); + + for (KURL::List::const_iterator it = urls.begin() ; it != urls.end() ; ++it) + { + if (d->previewView->leftImageInfo()) + { + if (d->previewView->leftImageInfo()->kurl() == *it) + { + d->previewView->leftReload(); + d->leftSidebar->itemChanged(d->previewView->leftImageInfo()); + } + } + + if (d->previewView->rightImageInfo()) + { + if (d->previewView->rightImageInfo()->kurl() == *it) + { + d->previewView->rightReload(); + d->rightSidebar->itemChanged(d->previewView->rightImageInfo()); + } + } + } +} + +void LightTableWindow::slotLeftPanelLeftButtonClicked() +{ + if (d->navigateByPairAction->isChecked()) return; + + d->barView->setSelectedItem(d->barView->findItemByInfo(d->previewView->leftImageInfo())); +} + +void LightTableWindow::slotRightPanelLeftButtonClicked() +{ + // With navigate by pair option, only the left panel can be selected. + if (d->navigateByPairAction->isChecked()) return; + + d->barView->setSelectedItem(d->barView->findItemByInfo(d->previewView->rightImageInfo())); +} + +void LightTableWindow::slotLeftPreviewLoaded(bool b) +{ + d->leftZoomBar->setEnabled(b); + + if (b) + { + d->previewView->checkForSelection(d->barView->currentItemImageInfo()); + d->barView->setOnLeftPanel(d->previewView->leftImageInfo()); + + LightTableBarItem *item = d->barView->findItemByInfo(d->previewView->leftImageInfo()); + if (item) item->setOnLeftPanel(true); + + if (d->navigateByPairAction->isChecked() && item) + { + LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(item->next()); + if (next) + { + d->barView->setOnRightPanel(next->info()); + slotSetItemOnRightPanel(next->info()); + } + else + { + LightTableBarItem* first = dynamic_cast<LightTableBarItem*>(d->barView->firstItem()); + slotSetItemOnRightPanel(first ? first->info() : 0); + } + } + } +} + +void LightTableWindow::slotRightPreviewLoaded(bool b) +{ + d->rightZoomBar->setEnabled(b); + if (b) + { + d->previewView->checkForSelection(d->barView->currentItemImageInfo()); + d->barView->setOnRightPanel(d->previewView->rightImageInfo()); + + LightTableBarItem *item = d->barView->findItemByInfo(d->previewView->rightImageInfo()); + if (item) item->setOnRightPanel(true); + } +} + +void LightTableWindow::slotItemSelected(ImageInfo* info) +{ + if (info) + { + d->setItemLeftAction->setEnabled(true); + d->setItemRightAction->setEnabled(true); + d->editItemAction->setEnabled(true); + d->removeItemAction->setEnabled(true); + d->clearListAction->setEnabled(true); + d->fileDeleteAction->setEnabled(true); + d->backwardAction->setEnabled(true); + d->forwardAction->setEnabled(true); + d->firstAction->setEnabled(true); + d->lastAction->setEnabled(true); + d->syncPreviewAction->setEnabled(true); + d->zoomPlusAction->setEnabled(true); + d->zoomMinusAction->setEnabled(true); + d->navigateByPairAction->setEnabled(true); + d->slideShowAction->setEnabled(true); + + LightTableBarItem* curr = d->barView->findItemByInfo(info); + if (curr) + { + if (!curr->prev()) + { +// d->backwardAction->setEnabled(false); + d->firstAction->setEnabled(false); + } + + if (!curr->next()) + { +// d->forwardAction->setEnabled(false); + d->lastAction->setEnabled(false); + } + + if (d->navigateByPairAction->isChecked()) + { + d->setItemLeftAction->setEnabled(false); + d->setItemRightAction->setEnabled(false); + + d->barView->setOnLeftPanel(info); + slotSetItemOnLeftPanel(info); + } + else if (d->autoLoadOnRightPanel && !curr->isOnLeftPanel()) + { + d->barView->setOnRightPanel(info); + slotSetItemOnRightPanel(info); + } + } + } + else + { + d->setItemLeftAction->setEnabled(false); + d->setItemRightAction->setEnabled(false); + d->editItemAction->setEnabled(false); + d->removeItemAction->setEnabled(false); + d->clearListAction->setEnabled(false); + d->fileDeleteAction->setEnabled(false); + d->backwardAction->setEnabled(false); + d->forwardAction->setEnabled(false); + d->firstAction->setEnabled(false); + d->lastAction->setEnabled(false); + d->zoomPlusAction->setEnabled(false); + d->zoomMinusAction->setEnabled(false); + d->syncPreviewAction->setEnabled(false); + d->navigateByPairAction->setEnabled(false); + d->slideShowAction->setEnabled(false); + } + + d->previewView->checkForSelection(info); +} + +// Deal with one (or more) items dropped onto the left panel +void LightTableWindow::slotLeftDroppedItems(const ImageInfoList& list) +{ + ImageInfo *info = *(list.begin()); + // add the image to the existing images + loadImageInfos(list, info, true); + + // We will check if first item from list is already stored in thumbbar + // Note that the thumbbar stores all ImageInfo reference + // in memory for preview object. + LightTableBarItem *item = d->barView->findItemByInfo(info); + if (item) + { + slotSetItemOnLeftPanel(item->info()); + // One approach is to make this item the current one, via + // d->barView->setSelectedItem(item); + // However, this is not good, because this also sets + // the right thumb to the same image. + // Therefore we use setLeftRightItems if there is more than + // one item in the list of dropped images. + } +} + +// Deal with one (or more) items dropped onto the right panel +void LightTableWindow::slotRightDroppedItems(const ImageInfoList& list) +{ + ImageInfo *info = *(list.begin()); + // add the image to the existing images + loadImageInfos(list, info, true); + + // We will check if first item from list is already stored in thumbbar + // Note that the thumbbar stores all ImageInfo reference + // in memory for preview object. + LightTableBarItem *item = d->barView->findItemByInfo(info); + if (item) + { + slotSetItemOnRightPanel(item->info()); + // Make this item the current one. + d->barView->setSelectedItem(item); + } +} + +// Set the images for the left and right panel. +void LightTableWindow::setLeftRightItems(const ImageInfoList &list, bool addTo) +{ + ImageInfoList l = list; + + if (l.count() == 0) + return; + + ImageInfo *info = l.first(); + LightTableBarItem *ltItem = d->barView->findItemByInfo(info); + + if (l.count() == 1 && !addTo) + { + // Just one item; this is used for the left panel. + d->barView->setOnLeftPanel(info); + slotSetItemOnLeftPanel(info); + d->barView->setSelectedItem(ltItem); + d->barView->ensureItemVisible(ltItem); + return; + } + + if (ltItem) + { + // The first item is used for the left panel. + if (!addTo) + { + d->barView->setOnLeftPanel(info); + slotSetItemOnLeftPanel(info); + } + + // The subsequent item is used for the right panel. + LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(ltItem->next()); + if (next && !addTo) + { + d->barView->setOnRightPanel(next->info()); + slotSetItemOnRightPanel(next->info()); + if (!d->navigateByPairAction->isChecked()) + { + d->barView->setSelectedItem(next); + // ensure that the selected item is visible + // FIXME: this does not work: + d->barView->ensureItemVisible(next); + } + } + + // If navigate by pairs is active, the left panel item is selected. + // (Fixes parts of bug #150296) + if (d->navigateByPairAction->isChecked()) + { + d->barView->setSelectedItem(ltItem); + d->barView->ensureItemVisible(ltItem); + } + } +} + +void LightTableWindow::slotSetItemLeft() +{ + if (d->barView->currentItemImageInfo()) + { + slotSetItemOnLeftPanel(d->barView->currentItemImageInfo()); + } +} + +void LightTableWindow::slotSetItemRight() +{ + if (d->barView->currentItemImageInfo()) + { + slotSetItemOnRightPanel(d->barView->currentItemImageInfo()); + } +} + +void LightTableWindow::slotSetItemOnLeftPanel(ImageInfo* info) +{ + d->previewView->setLeftImageInfo(info); + if (info) + d->leftSidebar->itemChanged(info); + else + d->leftSidebar->slotNoCurrentItem(); +} + +void LightTableWindow::slotSetItemOnRightPanel(ImageInfo* info) +{ + d->previewView->setRightImageInfo(info); + if (info) + d->rightSidebar->itemChanged(info); + else + d->rightSidebar->slotNoCurrentItem(); +} + +void LightTableWindow::slotClearItemsList() +{ + if (d->previewView->leftImageInfo()) + { + d->previewView->setLeftImageInfo(); + d->leftSidebar->slotNoCurrentItem(); + } + + if (d->previewView->rightImageInfo()) + { + d->previewView->setRightImageInfo(); + d->rightSidebar->slotNoCurrentItem(); + } + + d->barView->clear(); + refreshStatusBar(); +} + +void LightTableWindow::slotDeleteItem() +{ + if (d->barView->currentItemImageInfo()) + slotDeleteItem(d->barView->currentItemImageInfo()); +} + +void LightTableWindow::slotDeleteItem(ImageInfo* info) +{ + bool ask = true; + bool permanently = false; + + KURL u = info->kurl(); + PAlbum *palbum = AlbumManager::instance()->findPAlbum(u.directory()); + if (!palbum) + return; + + // Provide a digikamalbums:// URL to TDEIO + KURL kioURL = info->kurlForKIO(); + KURL fileURL = u; + + bool useTrash; + + if (ask) + { + bool preselectDeletePermanently = permanently; + + DeleteDialog dialog(this); + + KURL::List urlList; + urlList.append(u); + if (!dialog.confirmDeleteList(urlList, + DeleteDialogMode::Files, + preselectDeletePermanently ? + DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) + return; + + useTrash = !dialog.shouldDelete(); + } + else + { + useTrash = !permanently; + } + + // trash does not like non-local URLs, put is not implemented + if (useTrash) + kioURL = fileURL; + + if (!SyncJob::del(kioURL, useTrash)) + { + TQString errMsg(SyncJob::lastErrorMsg()); + KMessageBox::error(this, errMsg, errMsg); + return; + } + + emit signalFileDeleted(u); + + slotRemoveItem(info); +} + +void LightTableWindow::slotRemoveItem() +{ + if (d->barView->currentItemImageInfo()) + slotRemoveItem(d->barView->currentItemImageInfo()); +} + +void LightTableWindow::slotRemoveItem(ImageInfo* info) +{ + // When either the image from the left or right panel is removed, + // there are various situations to account for. + // To describe them, 4 images A B C D are used + // and the subscript _L and _ R mark the currently + // active item on the left and right panel + + bool leftPanelActive = false; + ImageInfo *curr_linfo = d->previewView->leftImageInfo(); + ImageInfo *curr_rinfo = d->previewView->rightImageInfo(); + ImageInfo *new_linfo = 0; + ImageInfo *new_rinfo = 0; + + TQ_LLONG infoId = info->id(); + + // First determine the next images to the current left and right image: + ImageInfo *next_linfo = 0; + ImageInfo *next_rinfo = 0; + + if (curr_linfo) + { + LightTableBarItem *ltItem = d->barView->findItemByInfo(curr_linfo); + if (ltItem) + { + LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(ltItem->next()); + if (next) + { + next_linfo = next->info(); + } + } + } + + if (curr_rinfo) + { + LightTableBarItem *ltItem = d->barView->findItemByInfo(curr_rinfo); + if (ltItem) + { + LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(ltItem->next()); + if (next) + { + next_rinfo = next->info(); + } + } + } + + d->barView->removeItem(info); + + // Make sure that next_linfo and next_rinfo are still available: + if (!d->barView->findItemByInfo(next_linfo)) + { + next_linfo = 0; + } + if (!d->barView->findItemByInfo(next_rinfo)) + { + next_rinfo = 0; + } + + // removal of the left panel item? + if (curr_linfo) + { + if ( curr_linfo->id() == infoId ) + { + leftPanelActive = true; + // Delete the item A_L of the left panel: + // 1) A_L B_R C D -> B_L C_R D + // 2) A_L B C_R D -> B C_L D_R + // 3) A_L B C D_R -> B_R C D_L + // 4) A_L B_R -> A_L + // some more corner cases: + // 5) A B_L C_R D -> A C_L D_R + // 6) A B_L C_R -> A_R C_L + // 7) A_LR B C D -> B_L C_R D (does not yet work) + // I.e. in 3) we wrap around circularly. + + // When removing the left panel image, + // put the right panel image into the left panel. + // Check if this one is not the same (i.e. also removed). + if (curr_rinfo) + { + if (curr_rinfo->id() != infoId) + { + new_linfo = curr_rinfo; + // Set the right panel to the next image: + new_rinfo = next_rinfo; + // set the right panel active + leftPanelActive = false; + } + } + } + } + + // removal of the right panel item? + if (curr_rinfo) + { + if (curr_rinfo->id() == infoId) + { + // Leave the left panel as the current one + new_linfo = curr_linfo; + // Set the right panel to the next image + new_rinfo = next_rinfo; + } + } + + // Now we deal with the corner cases, where no left or right item exists. + // If the right panel would be set, but not the left-one, then swap + if (!new_linfo && new_rinfo) + { + new_linfo = new_rinfo; + new_rinfo = 0; + leftPanelActive = true; + } + + if (!new_linfo) + { + if (d->barView->countItems() > 0) + { + LightTableBarItem* first = dynamic_cast<LightTableBarItem*>(d->barView->firstItem()); + new_linfo = first->info(); + } + } + + + // Make sure that new_linfo and new_rinfo exist. + // This addresses a crash occuring if the last image is removed + // in the navigate by pairs mode. + if (!d->barView->findItemByInfo(new_linfo)) + { + new_linfo = 0; + } + if (!d->barView->findItemByInfo(new_rinfo)) + { + new_rinfo = 0; + } + + // no right item defined? + if (!new_rinfo) + { + // If there are at least two items, we can find reasonable right image. + if (d->barView->countItems() > 1) + { + // See if there is an item next to the left one: + LightTableBarItem *ltItem = d->barView->findItemByInfo(new_linfo); + LightTableBarItem* next = 0; + // re-check if ltItem is really set + if (ltItem) + { + next = dynamic_cast<LightTableBarItem*>(ltItem->next()); + } + if (next) + { + new_rinfo = next->info(); + } + else + { + // If there is no item to the right of new_linfo + // then we can choose the first item for new_rinfo + // (as we made sure that there are at least two items) + LightTableBarItem* first = dynamic_cast<LightTableBarItem*>(d->barView->firstItem()); + new_rinfo = first->info(); + } + } + } + + // Check if left and right are set to the same + if (new_linfo && new_rinfo) + { + if (new_linfo->id() == new_rinfo->id()) + { + // Only keep the left one + new_rinfo = 0; + } + } + + // If the right panel would be set, but not the left-one, then swap + // (note that this has to be done here again!) + if (!new_linfo && new_rinfo) + { + new_linfo = new_rinfo; + new_rinfo = 0; + leftPanelActive = true; + } + + // set the image for the left panel + if (new_linfo) + { + d->barView->setOnLeftPanel(new_linfo); + slotSetItemOnLeftPanel(new_linfo); + + // make this the selected item if the left was active before + if ( leftPanelActive) + { + LightTableBarItem *ltItem = d->barView->findItemByInfo(new_linfo); + d->barView->setSelectedItem(ltItem); + } + } + else + { + d->previewView->setLeftImageInfo(); + d->leftSidebar->slotNoCurrentItem(); + } + + // set the image for the right panel + if (new_rinfo) + { + d->barView->setOnRightPanel(new_rinfo); + slotSetItemOnRightPanel(new_rinfo); + // make this the selected item if the left was active before + if (!leftPanelActive) + { + LightTableBarItem *ltItem = d->barView->findItemByInfo(new_rinfo); + d->barView->setSelectedItem(ltItem); + } + } + else + { + d->previewView->setRightImageInfo(); + d->rightSidebar->slotNoCurrentItem(); + } + + refreshStatusBar(); +} + +void LightTableWindow::slotEditItem() +{ + if (d->barView->currentItemImageInfo()) + slotEditItem(d->barView->currentItemImageInfo()); +} + +void LightTableWindow::slotEditItem(ImageInfo* info) +{ + ImageWindow *im = ImageWindow::imagewindow(); + ImageInfoList list = d->barView->itemsImageInfoList(); + + im->loadImageInfos(list, info, i18n("Light Table"), true); + + if (im->isHidden()) + im->show(); + else + im->raise(); + + im->setFocus(); +} + +void LightTableWindow::slotZoomTo100Percents() +{ + d->previewView->toggleFitToWindowOr100(); +} + +void LightTableWindow::slotFitToWindow() +{ + d->previewView->fitToWindow(); +} + +void LightTableWindow::slotToggleSlideShow() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + bool startWithCurrent = config->readBoolEntry("SlideShowStartCurrent", false); + + SlideShowSettings settings; + settings.exifRotate = AlbumSettings::instance()->getExifRotate(); + settings.delay = config->readNumEntry("SlideShowDelay", 5) * 1000; + settings.printName = config->readBoolEntry("SlideShowPrintName", true); + settings.printDate = config->readBoolEntry("SlideShowPrintDate", false); + settings.printApertureFocal = config->readBoolEntry("SlideShowPrintApertureFocal", false); + settings.printExpoSensitivity = config->readBoolEntry("SlideShowPrintExpoSensitivity", false); + settings.printMakeModel = config->readBoolEntry("SlideShowPrintMakeModel", false); + settings.printComment = config->readBoolEntry("SlideShowPrintComment", false); + settings.loop = config->readBoolEntry("SlideShowLoop", false); + slideShow(startWithCurrent, settings); +} + +void LightTableWindow::slideShow(bool startWithCurrent, SlideShowSettings& settings) +{ + if (!d->barView->countItems()) return; + + DMetadata meta; + int i = 0; + d->cancelSlideShow = false; + + d->statusProgressBar->progressBarMode(StatusProgressBar::CancelProgressBarMode, + i18n("Preparing slideshow. Please wait...")); + + ImageInfoList list = d->barView->itemsImageInfoList(); + + for (ImageInfo *info = list.first() ; !d->cancelSlideShow && info ; info = list.next()) + { + SlidePictureInfo pictInfo; + pictInfo.comment = info->caption(); + + // Perform optimizations: only read pictures metadata if necessary. + if (settings.printApertureFocal || settings.printExpoSensitivity || settings.printMakeModel) + { + meta.load(info->kurl().path()); + pictInfo.photoInfo = meta.getPhotographInformations(); + } + + // In case of dateTime extraction from metadata failed + pictInfo.photoInfo.dateTime = info->dateTime(); + settings.pictInfoMap.insert(info->kurl(), pictInfo); + settings.fileList.append(info->kurl()); + + d->statusProgressBar->setProgressValue((int)((i++/(float)list.count())*100.0)); + kapp->processEvents(); + } + + d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode, TQString()); + refreshStatusBar(); + + if (!d->cancelSlideShow) + { + settings.exifRotate = AlbumSettings::instance()->getExifRotate(); + + SlideShow *slide = new SlideShow(settings); + if (startWithCurrent) + slide->setCurrent(d->barView->currentItemImageInfo()->kurl()); + + slide->show(); + } +} + +void LightTableWindow::slotProgressBarCancelButtonPressed() +{ + d->cancelSlideShow = true; +} + +void LightTableWindow::slotToggleFullScreen() +{ + if (d->fullScreen) // out of fullscreen + { + + setWindowState( windowState() & ~WindowFullScreen ); + menuBar()->show(); + statusBar()->show(); + leftDock()->show(); + rightDock()->show(); + topDock()->show(); + bottomDock()->show(); + + TQObject* obj = child("ToolBar","TDEToolBar"); + + if (obj) + { + TDEToolBar* toolBar = static_cast<TDEToolBar*>(obj); + + if (d->fullScreenAction->isPlugged(toolBar) && d->removeFullScreenButton) + d->fullScreenAction->unplug(toolBar); + + if (toolBar->isHidden()) + showToolBars(); + } + + // -- remove the gui action accels ---- + + unplugActionAccel(d->zoomFitToWindowAction); + + if (d->fullScreen) + { + d->leftSidebar->restore(); + d->rightSidebar->restore(); + } + else + { + d->leftSidebar->backup(); + d->rightSidebar->backup(); + } + + d->fullScreen = false; + } + else // go to fullscreen + { + // hide the menubar and the statusbar + menuBar()->hide(); + statusBar()->hide(); + topDock()->hide(); + leftDock()->hide(); + rightDock()->hide(); + bottomDock()->hide(); + + TQObject* obj = child("ToolBar","TDEToolBar"); + + if (obj) + { + TDEToolBar* toolBar = static_cast<TDEToolBar*>(obj); + + if (d->fullScreenHideToolBar) + { + hideToolBars(); + } + else + { + showToolBars(); + + if ( !d->fullScreenAction->isPlugged(toolBar) ) + { + d->fullScreenAction->plug(toolBar); + d->removeFullScreenButton=true; + } + else + { + // If FullScreen button is enable in toolbar settings + // We don't remove it when we out of fullscreen mode. + d->removeFullScreenButton=false; + } + } + } + + // -- Insert all the gui actions into the accel -- + + plugActionAccel(d->zoomFitToWindowAction); + + if (d->fullScreen) + { + d->leftSidebar->restore(); + d->rightSidebar->restore(); + } + else + { + d->leftSidebar->backup(); + d->rightSidebar->backup(); + } + + showFullScreen(); + d->fullScreen = true; + } +} + +void LightTableWindow::slotEscapePressed() +{ + if (d->fullScreen) + d->fullScreenAction->activate(); +} + +void LightTableWindow::showToolBars() +{ + TQPtrListIterator<TDEToolBar> it = toolBarIterator(); + TDEToolBar* bar; + + for( ; it.current()!=0L ; ++it) + { + bar=it.current(); + + if (bar->area()) + bar->area()->show(); + else + bar->show(); + } +} + +void LightTableWindow::hideToolBars() +{ + TQPtrListIterator<TDEToolBar> it = toolBarIterator(); + TDEToolBar* bar; + + for( ; it.current()!=0L ; ++it) + { + bar=it.current(); + + if (bar->area()) + bar->area()->hide(); + else + bar->hide(); + } +} + +void LightTableWindow::plugActionAccel(TDEAction* action) +{ + if (!action) + return; + + d->accelerators->insert(action->text(), + action->text(), + action->whatsThis(), + action->shortcut(), + action, + TQ_SLOT(activate())); +} + +void LightTableWindow::unplugActionAccel(TDEAction* action) +{ + d->accelerators->remove(action->text()); +} + +void LightTableWindow::slotDonateMoney() +{ + TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=donation"); +} + +void LightTableWindow::slotContribute() +{ + TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=contrib"); +} + +void LightTableWindow::slotEditKeys() +{ + KKeyDialog dialog(true, this); + dialog.insert( actionCollection(), i18n( "General" ) ); + dialog.configure(); +} + +void LightTableWindow::slotConfToolbars() +{ + saveMainWindowSettings(TDEGlobal::config(), "LightTable Settings"); + KEditToolbar dlg(factory(), this); + + connect(&dlg, TQ_SIGNAL(newToolbarConfig()), + this, TQ_SLOT(slotNewToolbarConfig())); + + dlg.exec(); +} + +void LightTableWindow::slotNewToolbarConfig() +{ + applyMainWindowSettings(TDEGlobal::config(), "LightTable Settings"); +} + +void LightTableWindow::slotSetup() +{ + Setup setup(this, 0); + + if (setup.exec() != TQDialog::Accepted) + return; + + kapp->config()->sync(); + + applySettings(); +} + +void LightTableWindow::slotLeftZoomFactorChanged(double zoom) +{ + double h = (double)ThumbnailSize::Huge; + double s = (double)ThumbnailSize::Small; + double zmin = d->previewView->leftZoomMin(); + double zmax = d->previewView->leftZoomMax(); + double b = (zmin-(zmax*s/h))/(1-s/h); + double a = (zmax-b)/h; + int size = (int)((zoom - b) /a); + + d->leftZoomBar->setZoomSliderValue(size); + d->leftZoomBar->setZoomTrackerText(i18n("zoom: %1%").arg((int)(zoom*100.0))); + + d->leftZoomBar->setEnableZoomPlus(true); + d->leftZoomBar->setEnableZoomMinus(true); + + if (d->previewView->leftMaxZoom()) + d->leftZoomBar->setEnableZoomPlus(false); + + if (d->previewView->leftMinZoom()) + d->leftZoomBar->setEnableZoomMinus(false); +} + +void LightTableWindow::slotRightZoomFactorChanged(double zoom) +{ + double h = (double)ThumbnailSize::Huge; + double s = (double)ThumbnailSize::Small; + double zmin = d->previewView->rightZoomMin(); + double zmax = d->previewView->rightZoomMax(); + double b = (zmin-(zmax*s/h))/(1-s/h); + double a = (zmax-b)/h; + int size = (int)((zoom - b) /a); + + d->rightZoomBar->setZoomSliderValue(size); + d->rightZoomBar->setZoomTrackerText(i18n("zoom: %1%").arg((int)(zoom*100.0))); + + d->rightZoomBar->setEnableZoomPlus(true); + d->rightZoomBar->setEnableZoomMinus(true); + + if (d->previewView->rightMaxZoom()) + d->rightZoomBar->setEnableZoomPlus(false); + + if (d->previewView->rightMinZoom()) + d->rightZoomBar->setEnableZoomMinus(false); +} + +void LightTableWindow::slotToggleSyncPreview() +{ + d->previewView->setSyncPreview(d->syncPreviewAction->isChecked()); +} + +void LightTableWindow::slotToggleOnSyncPreview(bool t) +{ + d->syncPreviewAction->setEnabled(t); + + if (!t) + { + d->syncPreviewAction->setChecked(false); + } + else + { + if (d->autoSyncPreview) + d->syncPreviewAction->setChecked(true); + } +} + +void LightTableWindow::slotBackward() +{ + ThumbBarItem* curr = d->barView->currentItem(); + ThumbBarItem* last = d->barView->lastItem(); + if (curr) + { + if (curr->prev()) + d->barView->setSelected(curr->prev()); + else + d->barView->setSelected(last); + } +} + +void LightTableWindow::slotForward() +{ + ThumbBarItem* curr = d->barView->currentItem(); + ThumbBarItem* first = d->barView->firstItem(); + if (curr) + { + if (curr->next()) + d->barView->setSelected(curr->next()); + else + d->barView->setSelected(first); + } +} + +void LightTableWindow::slotFirst() +{ + d->barView->setSelected( d->barView->firstItem() ); +} + +void LightTableWindow::slotLast() +{ + d->barView->setSelected( d->barView->lastItem() ); +} + +void LightTableWindow::slotToggleNavigateByPair() +{ + d->barView->setNavigateByPair(d->navigateByPairAction->isChecked()); + d->previewView->setNavigateByPair(d->navigateByPairAction->isChecked()); + slotItemSelected(d->barView->currentItemImageInfo()); +} + +void LightTableWindow::slotRawCameraList() +{ + RawCameraDlg dlg(this); + dlg.exec(); +} + +void LightTableWindow::slotThemeChanged() +{ + TQStringList themes(ThemeEngine::instance()->themeNames()); + int index = themes.findIndex(AlbumSettings::instance()->getCurrentTheme()); + if (index == -1) + index = themes.findIndex(i18n("Default")); + + d->themeMenuAction->setCurrentItem(index); +} + +void LightTableWindow::slotChangeTheme(const TQString& theme) +{ + AlbumSettings::instance()->setCurrentTheme(theme); + ThemeEngine::instance()->slotChangeTheme(theme); +} + +void LightTableWindow::slotShowMenuBar() +{ + if (menuBar()->isVisible()) + menuBar()->hide(); + else + menuBar()->show(); +} + +} // namespace Digikam diff --git a/src/utilities/lighttable/lighttablewindow.h b/src/utilities/lighttable/lighttablewindow.h new file mode 100644 index 00000000..f080e2d1 --- /dev/null +++ b/src/utilities/lighttable/lighttablewindow.h @@ -0,0 +1,162 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-03-05 + * Description : digiKam light table GUI + * + * Copyright (C) 2007-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 LIGHTTABLEWINDOW_H +#define LIGHTTABLEWINDOW_H + +// TQt includes. + +#include <tqstring.h> + +// KDE includes. + +#include <kurl.h> +#include <tdemainwindow.h> + +// Local includes. + +#include "imageinfo.h" + +class TDEAction; + +namespace Digikam +{ + +class SlideShowSettings; +class ThumbBarItem; +class LightTableWindowPriv; + +class LightTableWindow : public TDEMainWindow +{ + TQ_OBJECT + + +public: + + ~LightTableWindow(); + + static LightTableWindow *lightTableWindow(); + static bool lightTableWindowCreated(); + + void loadImageInfos(const ImageInfoList &list, ImageInfo *imageInfoCurrent, bool addTo); + void setLeftRightItems(const ImageInfoList &list, bool addTo); + void applySettings(); + void refreshView(); + +signals: + + void signalFileDeleted(const KURL&); + +public slots: + + void slotItemsUpdated(const KURL::List&); + +private: + + void closeEvent(TQCloseEvent* e); + void setupActions(); + void setupConnections(); + void setupUserArea(); + void setupStatusBar(); + void setupAccelerators(); + void slideShow(bool startWithCurrent, SlideShowSettings& settings); + void showToolBars(); + void hideToolBars(); + void plugActionAccel(TDEAction* action); + void unplugActionAccel(TDEAction* action); + void readSettings(); + void writeSettings(); + void refreshStatusBar(); + + LightTableWindow(); + +private slots: + + void slotBackward(); + void slotForward(); + void slotFirst(); + void slotLast(); + + void slotSetItemLeft(); + void slotSetItemRight(); + void slotSetItemOnLeftPanel(ImageInfo*); + void slotSetItemOnRightPanel(ImageInfo*); + void slotLeftDroppedItems(const ImageInfoList&); + void slotRightDroppedItems(const ImageInfoList&); + + void slotLeftPanelLeftButtonClicked(); + void slotRightPanelLeftButtonClicked(); + + void slotLeftPreviewLoaded(bool); + void slotRightPreviewLoaded(bool); + + void slotLeftZoomFactorChanged(double); + void slotRightZoomFactorChanged(double); + + void slotToggleOnSyncPreview(bool); + void slotToggleSyncPreview(); + void slotToggleNavigateByPair(); + + void slotEditItem(); + void slotEditItem(ImageInfo*); + + void slotDeleteItem(); + void slotDeleteItem(ImageInfo*); + + void slotRemoveItem(); + void slotRemoveItem(ImageInfo*); + + void slotItemSelected(ImageInfo*); + void slotClearItemsList(); + + void slotThumbbarDroppedItems(const ImageInfoList&); + + void slotZoomTo100Percents(); + void slotFitToWindow(); + + void slotProgressBarCancelButtonPressed(); + void slotToggleSlideShow(); + void slotToggleFullScreen(); + void slotEscapePressed(); + void slotDonateMoney(); + void slotContribute(); + void slotRawCameraList(); + void slotEditKeys(); + void slotConfToolbars(); + void slotShowMenuBar(); + void slotNewToolbarConfig(); + void slotSetup(); + + void slotThemeChanged(); + void slotChangeTheme(const TQString& theme); + +private: + + LightTableWindowPriv *d; + + static LightTableWindow *m_instance; +}; + +} // namespace Digikam + +#endif /* LIGHTTABLEWINDOW_H */ diff --git a/src/utilities/lighttable/lighttablewindowprivate.h b/src/utilities/lighttable/lighttablewindowprivate.h new file mode 100644 index 00000000..a96e0b08 --- /dev/null +++ b/src/utilities/lighttable/lighttablewindowprivate.h @@ -0,0 +1,158 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-03-05 + * Description : digiKam light table GUI + * + * Copyright (C) 2007-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 <tqsplitter.h> + +// KDE includes. + +#include <tdeaction.h> +#include <tdeaccel.h> + +// Local includes. + +#include "imagepropertiessidebardb.h" +#include "statusprogressbar.h" +#include "statuszoombar.h" +#include "lighttableview.h" +#include "lighttablebar.h" + +namespace Digikam +{ + +class LightTableWindowPriv +{ + +public: + + LightTableWindowPriv() + { + autoLoadOnRightPanel = true; + autoSyncPreview = true; + fullScreenHideToolBar = false; + fullScreen = false; + removeFullScreenButton = false; + cancelSlideShow = false; + star0 = 0; + star1 = 0; + star2 = 0; + star3 = 0; + star4 = 0; + star5 = 0; + accelerators = 0; + leftSidebar = 0; + rightSidebar = 0; + previewView = 0; + barView = 0; + hSplitter = 0; + vSplitter = 0; + syncPreviewAction = 0; + clearListAction = 0; + setItemLeftAction = 0; + setItemRightAction = 0; + editItemAction = 0; + removeItemAction = 0; + fileDeleteAction = 0; + slideShowAction = 0; + fullScreenAction = 0; + donateMoneyAction = 0; + zoomFitToWindowAction = 0; + zoomTo100percents = 0; + zoomPlusAction = 0; + zoomMinusAction = 0; + statusProgressBar = 0; + leftZoomBar = 0; + rightZoomBar = 0; + forwardAction = 0; + backwardAction = 0; + firstAction = 0; + lastAction = 0; + navigateByPairAction = 0; + rawCameraListAction = 0; + themeMenuAction = 0; + contributeAction = 0; + showMenuBarAction = 0; + } + + bool autoLoadOnRightPanel; + bool autoSyncPreview; + bool fullScreenHideToolBar; + bool fullScreen; + bool removeFullScreenButton; + bool cancelSlideShow; + + TQSplitter *hSplitter; + TQSplitter *vSplitter; + + // Rating actions. + TDEAction *star0; + TDEAction *star1; + TDEAction *star2; + TDEAction *star3; + TDEAction *star4; + TDEAction *star5; + + TDEAction *forwardAction; + TDEAction *backwardAction; + TDEAction *firstAction; + TDEAction *lastAction; + + TDEAction *setItemLeftAction; + TDEAction *setItemRightAction; + TDEAction *clearListAction; + TDEAction *editItemAction; + TDEAction *removeItemAction; + TDEAction *fileDeleteAction; + TDEAction *slideShowAction; + TDEAction *donateMoneyAction; + TDEAction *contributeAction; + TDEAction *zoomPlusAction; + TDEAction *zoomMinusAction; + TDEAction *zoomTo100percents; + TDEAction *zoomFitToWindowAction; + TDEAction *rawCameraListAction; + + TDESelectAction *themeMenuAction; + + TDEToggleAction *fullScreenAction; + TDEToggleAction *syncPreviewAction; + TDEToggleAction *navigateByPairAction; + TDEToggleAction *showMenuBarAction; + + TDEAccel *accelerators; + + LightTableBar *barView; + + LightTableView *previewView; + + StatusZoomBar *leftZoomBar; + StatusZoomBar *rightZoomBar; + + StatusProgressBar *statusProgressBar; + + ImagePropertiesSideBarDB *leftSidebar; + ImagePropertiesSideBarDB *rightSidebar; +}; + +} // namespace Digikam diff --git a/src/utilities/lighttable/lighttablewindowui.rc b/src/utilities/lighttable/lighttablewindowui.rc new file mode 100644 index 00000000..ae7ce721 --- /dev/null +++ b/src/utilities/lighttable/lighttablewindowui.rc @@ -0,0 +1,83 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<gui version="24" name="lighttablewindow" > + +<MenuBar> + + <Menu name="File" ><text>&File</text> + <Action name="lighttable_first" /> + <Action name="lighttable_backward" /> + <Action name="lighttable_forward" /> + <Action name="lighttable_last" /> + <Separator/> + <Action name="lighttable_setitemleft" /> + <Action name="lighttable_setitemright" /> + <Action name="lighttable_edititem" /> + <Separator/> + <Action name="lighttable_removeitem" /> + <Action name="lighttable_clearlist" /> + <Separator/> + <Action name="lighttable_filedelete" /> + <Separator/> + <Action name="lighttable_close" /> + </Menu> + + <Menu name="View" ><text>&View</text> + <Action name="lighttable_fullscreen" /> + <Action name="lighttable_slideshow" /> + <Separator/> + <Action name="lighttable_syncpreview" /> + <Action name="lighttable_navigatebypair" /> + <Separator/> + <Action name="lighttable_zoomplus" /> + <Action name="lighttable_zoomminus" /> + <Action name="lighttable_zoomto100percents" /> + <Action name="lighttable_zoomfit2window" /> + </Menu> + + <Menu name="help" ><text>&Help</text> + <Action name="lighttable_rawcameralist"/> + <Action name="lighttable_donatemoney" /> + <Action name="lighttable_contribute" /> + </Menu> + + <Merge/> + + <Menu name="settings" noMerge="1"><Text>&Settings</Text> + <Merge name="StandardToolBarMenuHandler" /> + <Action name="options_show_menubar"/> + <Action name="options_show_statusbar"/> + <Action name="options_show_toolbar"/> + <Separator/> + <Action name="theme_menu" /> + <Action name="options_configure_keybinding"/> + <Action name="options_configure_toolbars"/> + <Action name="options_configure" /> + </Menu> + +</MenuBar> + +<ToolBar name="ToolBar" ><text>Main Toolbar</text> + <Action name="lighttable_first" /> + <Action name="lighttable_backward" /> + <Action name="lighttable_forward" /> + <Action name="lighttable_last" /> + <Separator/> + <Action name="lighttable_zoomplus" /> + <Action name="lighttable_zoomminus" /> + <Action name="lighttable_zoomfit2window" /> + <Separator/> + <Action name="lighttable_setitemleft" /> + <Action name="lighttable_setitemright" /> + <Action name="lighttable_syncpreview" /> + <Action name="lighttable_navigatebypair" /> + <Separator/> + <Action name="lighttable_fullscreen" /> + <Action name="lighttable_slideshow" /> + <Merge /> + <WeakSeparator/> + <Action name="logo_action" /> +</ToolBar> + +<ActionProperties/> + +</gui> |