diff options
| author | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-11-22 18:41:30 +0900 | 
|---|---|---|
| committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-11-22 20:55:03 +0900 | 
| commit | 5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90 (patch) | |
| tree | f89cc49efc9ca1d0e1579ecb079ee7e7088ff8c8 /src/utilities/lighttable | |
| parent | 0bfbf616d9c1fd7abb1bd02732389ab35e5f8771 (diff) | |
| download | digikam-5bed6e4a.tar.gz digikam-5bed6e4a.zip | |
Rename 'digikam' folder to 'src'
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
(cherry picked from commit ee0d99607c14cb63d3ebdb3a970b508949fa8219)
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> | 
