File indexing completed on 2025-01-05 03:56:43

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2004-11-17
0007  * Description : item properties side bar (without support of digiKam database).
0008  *
0009  * SPDX-FileCopyrightText: 2004-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "itempropertiessidebar.h"
0016 
0017 // Qt includes
0018 
0019 #include <QSplitter>
0020 #include <QFileInfo>
0021 #include <QApplication>
0022 #include <QIcon>
0023 #include <QLocale>
0024 #include <QMimeDatabase>
0025 #include <QMimeType>
0026 
0027 // KDE includes
0028 
0029 #include <klocalizedstring.h>
0030 #include <kconfiggroup.h>
0031 
0032 // Local includes
0033 
0034 #include "drawdecoder.h"
0035 #include "digikam_debug.h"
0036 #include "dimg.h"
0037 #include "dmetadata.h"
0038 #include "itempropertiestab.h"
0039 #include "itemselectionpropertiestab.h"
0040 #include "itempropertiesmetadatatab.h"
0041 #include "itempropertiescolorstab.h"
0042 #include "itempropertiesversionstab.h"
0043 
0044 #ifdef HAVE_GEOLOCATION
0045 #   include "itempropertiesgpstab.h"
0046 #endif // HAVE_GEOLOCATION
0047 
0048 namespace Digikam
0049 {
0050 
0051 ItemPropertiesSideBar::ItemPropertiesSideBar(QWidget* const parent,
0052                                              SidebarSplitter* const splitter,
0053                                              Qt::Edge side,
0054                                              bool mimimizedDefault)
0055     : Sidebar             (parent, splitter, side, mimimizedDefault),
0056       m_dirtyPropertiesTab(false),
0057       m_dirtyMetadataTab  (false),
0058       m_dirtyColorTab     (false),
0059       m_dirtyGpsTab       (false),
0060       m_dirtyHistoryTab   (false),
0061       m_currentRect       (QRect()),
0062       m_image             (nullptr)
0063 {
0064     m_propertiesStackedView  = new QStackedWidget(parent);
0065     m_propertiesTab          = new ItemPropertiesTab(parent);
0066     m_selectionPropertiesTab = new ItemSelectionPropertiesTab(parent);
0067     m_metadataTab            = new ItemPropertiesMetadataTab(parent);
0068     m_colorTab               = new ItemPropertiesColorsTab(parent);
0069 
0070     m_propertiesStackedView->addWidget(m_propertiesTab);
0071     m_propertiesStackedView->addWidget(m_selectionPropertiesTab);
0072 
0073     // NOTE: Special case with Showfoto which will only be able to load image, not video.
0074 
0075     if (QApplication::applicationName() != QLatin1String("digikam"))
0076     {
0077         m_propertiesTab->setVideoInfoDisable(true);
0078     }
0079 
0080     appendTab(m_propertiesStackedView, QIcon::fromTheme(QLatin1String("configure")),        i18nc("@title: item properties", "Properties"));
0081     appendTab(m_metadataTab,           QIcon::fromTheme(QLatin1String("format-text-code")), i18nc("@title: item properties", "Metadata")); // krazy:exclude=iconnames
0082     appendTab(m_colorTab,              QIcon::fromTheme(QLatin1String("fill-color")),       i18nc("@title: item properties", "Colors"));
0083 
0084 #ifdef HAVE_GEOLOCATION
0085 
0086     m_gpsTab = new ItemPropertiesGPSTab(parent);
0087     appendTab(m_gpsTab,                QIcon::fromTheme(QLatin1String("globe")),            i18nc("@title: item properties", "Map"));
0088 
0089 #endif // HAVE_GEOLOCATION
0090 
0091     connect(m_metadataTab, SIGNAL(signalSetupMetadataFilters(int)),
0092             this, SIGNAL(signalSetupMetadataFilters(int)));
0093 
0094     connect(m_metadataTab, SIGNAL(signalSetupExifTool()),
0095             this, SIGNAL(signalSetupExifTool()));
0096 
0097     // --- NOTE: use dynamic binding as slotChangedTab() is a virtual method which can be re-implemented in derived classes.
0098 
0099     connect(this, &ItemPropertiesSideBar::signalChangedTab,
0100             this, &ItemPropertiesSideBar::slotChangedTab);
0101 }
0102 
0103 ItemPropertiesSideBar::~ItemPropertiesSideBar()
0104 {
0105 }
0106 
0107 void ItemPropertiesSideBar::itemChanged(const QUrl& url, const QRect& rect, DImg* const img)
0108 {
0109     if (!url.isValid())
0110     {
0111         return;
0112     }
0113 
0114     m_currentURL         = url;
0115     m_currentRect        = rect;
0116     m_image              = img;
0117     m_dirtyPropertiesTab = false;
0118     m_dirtyMetadataTab   = false;
0119     m_dirtyColorTab      = false;
0120     m_dirtyGpsTab        = false;
0121     m_dirtyHistoryTab    = false;
0122 
0123     slotChangedTab(getActiveTab());
0124 }
0125 
0126 void ItemPropertiesSideBar::slotNoCurrentItem()
0127 {
0128     m_currentURL = QUrl();
0129 
0130     m_selectionPropertiesTab->setCurrentURL();
0131     m_propertiesTab->setCurrentURL();
0132     m_metadataTab->setCurrentURL();
0133     m_colorTab->setData();
0134 
0135 #ifdef HAVE_GEOLOCATION
0136 
0137     m_gpsTab->setCurrentURL();
0138 
0139 #endif // HAVE_GEOLOCATION
0140 
0141     m_dirtyPropertiesTab = false;
0142     m_dirtyMetadataTab   = false;
0143     m_dirtyColorTab      = false;
0144     m_dirtyGpsTab        = false;
0145     m_dirtyHistoryTab    = false;
0146 }
0147 
0148 void ItemPropertiesSideBar::slotImageSelectionChanged(const QRect& rect)
0149 {
0150     m_currentRect = rect;
0151 
0152     if (m_dirtyColorTab)
0153     {
0154         m_colorTab->setSelection(rect);
0155     }
0156     else
0157     {
0158         slotChangedTab(m_colorTab);
0159     }
0160 }
0161 
0162 void ItemPropertiesSideBar::slotChangedTab(QWidget* tab)
0163 {
0164     if (!m_currentURL.isValid())
0165     {
0166 
0167 #ifdef HAVE_GEOLOCATION
0168 
0169         m_gpsTab->setActive(tab == m_gpsTab);
0170 
0171 #endif // HAVE_GEOLOCATION
0172 
0173         return;
0174     }
0175 
0176     setCursor(Qt::WaitCursor);
0177 
0178     if      ((tab == m_propertiesStackedView) && !m_dirtyPropertiesTab)
0179     {
0180         m_propertiesTab->setCurrentURL(m_currentURL);
0181         setImagePropertiesInformation(m_currentURL);
0182         m_dirtyPropertiesTab = true;
0183     }
0184     else if ((tab == m_metadataTab) && !m_dirtyMetadataTab)
0185     {
0186         m_metadataTab->setCurrentURL(m_currentURL);
0187         m_dirtyMetadataTab = true;
0188     }
0189     else if ((tab == m_colorTab) && !m_dirtyColorTab)
0190     {
0191         m_colorTab->setData(m_currentURL, m_currentRect, m_image);
0192         m_dirtyColorTab = true;
0193     }
0194 
0195 #ifdef HAVE_GEOLOCATION
0196 
0197     else if ((tab == m_gpsTab) && !m_dirtyGpsTab)
0198     {
0199         m_gpsTab->setCurrentURL(m_currentURL);
0200         m_dirtyGpsTab = true;
0201     }
0202 
0203     m_gpsTab->setActive(tab == m_gpsTab);
0204 
0205 #endif // HAVE_GEOLOCATION
0206 
0207     unsetCursor();
0208 }
0209 
0210 void ItemPropertiesSideBar::setImagePropertiesInformation(const QUrl& url)
0211 {
0212     if (!url.isValid())
0213     {
0214         return;
0215     }
0216 
0217     QString str;
0218     QString unavailable(QString::fromUtf8("<i>%1</i>").arg(i18nc("@info: item properties", "unavailable")));
0219     QFileInfo fileInfo(url.toLocalFile());
0220     QScopedPointer<DMetadata> metaData(new DMetadata(url.toLocalFile()));
0221 
0222     // -- File system information -----------------------------------------
0223 
0224     QDateTime modifiedDate = fileInfo.lastModified();
0225     str = QLocale().toString(modifiedDate, QLocale::ShortFormat);
0226     m_propertiesTab->setFileModifiedDate(str);
0227 
0228     str = QString::fromUtf8("%1 (%2)").arg(ItemPropertiesTab::humanReadableBytesCount(fileInfo.size()))
0229                                       .arg(QLocale().toString(fileInfo.size()));
0230     m_propertiesTab->setFileSize(str);
0231     m_propertiesTab->setFileOwner(QString::fromUtf8("%1 - %2").arg(fileInfo.owner()).arg(fileInfo.group()));
0232     m_propertiesTab->setFilePermissions(ItemPropertiesTab::permissionsString(fileInfo));
0233 
0234     // -- Image Properties --------------------------------------------------
0235 
0236     QSize   dims;
0237     QString bitDepth, colorMode;
0238     QString rawFilesExt = DRawDecoder::rawFiles();
0239     QString ext         = fileInfo.suffix().toUpper();
0240 
0241     if (!ext.isEmpty() && rawFilesExt.toUpper().contains(ext))
0242     {
0243         m_propertiesTab->setImageMime(i18nc("@info: item properties", "RAW Image"));
0244         bitDepth    = QLatin1String("48");
0245         dims        = metaData->getItemDimensions();
0246         colorMode   = i18nc("@info: item properties", "Uncalibrated");
0247     }
0248     else
0249     {
0250         m_propertiesTab->setImageMime(QMimeDatabase().mimeTypeForFile(fileInfo).comment());
0251 
0252         dims      = metaData->getPixelSize();
0253 
0254         DImg img;
0255         img.loadItemInfo(url.toLocalFile(), false, false, false, false);
0256         bitDepth.setNum(img.originalBitDepth());
0257         colorMode = DImg::colorModelToString(img.originalColorModel());
0258     }
0259 
0260     QString mpixels = QLocale().toString(dims.width()*dims.height()/1000000.0, 'f', 1);
0261     str = (!dims.isValid()) ? i18nc("@info: item properties", "Unknown")
0262                             : i18nc("@info: item properties", "%1x%2 (%3Mpx)",
0263             dims.width(), dims.height(), mpixels);
0264     m_propertiesTab->setItemDimensions(str);
0265 
0266     if (!dims.isValid())
0267     {
0268         str = i18nc("@info: item properties", "Unknown");
0269     }
0270     else
0271     {
0272         m_propertiesTab->aspectRatioToString(dims.width(), dims.height(), str);
0273     }
0274 
0275     m_propertiesTab->setImageRatio(str);
0276     m_propertiesTab->setImageColorMode(colorMode.isEmpty() ? unavailable : colorMode);
0277     m_propertiesTab->setImageBitDepth(bitDepth.isEmpty()   ? unavailable : i18nc("@info: item properties", "%1 bpp", bitDepth));
0278     m_propertiesTab->setHasSidecar(DMetadata::hasSidecar(url.toLocalFile()) ? i18nc("@info: item properties", "Yes")
0279                                                                             : i18nc("@info: item properties", "No"));
0280     double alt, lat, lng;
0281     m_propertiesTab->setHasGPSInfo(metaData->getGPSInfo(alt, lat, lng) ? i18nc("@info: item properties", "Yes")
0282                                                                        : i18nc("@info: item properties", "No"));
0283 
0284     // -- Photograph information ------------------------------------------
0285 
0286     PhotoInfoContainer photoInfo = metaData->getPhotographInformation();
0287 
0288     m_propertiesTab->setPhotoInfoDisable(photoInfo.isEmpty());
0289     ItemPropertiesTab::shortenedMakeInfo(photoInfo.make);
0290     ItemPropertiesTab::shortenedModelInfo(photoInfo.model);
0291     m_propertiesTab->setPhotoMake(photoInfo.make.isEmpty()   ? unavailable : photoInfo.make);
0292     m_propertiesTab->setPhotoModel(photoInfo.model.isEmpty() ? unavailable : photoInfo.model);
0293 
0294     if (photoInfo.dateTime.isValid())
0295     {
0296         str = QLocale().toString(photoInfo.dateTime, QLocale::ShortFormat);
0297         m_propertiesTab->setPhotoDateTime(str);
0298     }
0299     else
0300     {
0301         m_propertiesTab->setPhotoDateTime(unavailable);
0302     }
0303 
0304     m_propertiesTab->setPhotoLens(photoInfo.lens.isEmpty()         ? unavailable : photoInfo.lens);
0305     m_propertiesTab->setPhotoAperture(photoInfo.aperture.isEmpty() ? unavailable : photoInfo.aperture);
0306 
0307     if (photoInfo.focalLength35mm.isEmpty())
0308     {
0309         m_propertiesTab->setPhotoFocalLength(photoInfo.focalLength.isEmpty() ? unavailable : photoInfo.focalLength);
0310     }
0311     else
0312     {
0313         str = i18nc("@info: item properties", "%1 (%2)", photoInfo.focalLength, photoInfo.focalLength35mm);
0314         m_propertiesTab->setPhotoFocalLength(str);
0315     }
0316 
0317     m_propertiesTab->setPhotoExposureTime(photoInfo.exposureTime.isEmpty() ? unavailable : photoInfo.exposureTime);
0318     m_propertiesTab->setPhotoSensitivity(photoInfo.sensitivity.isEmpty()   ? unavailable : i18nc("@info: item properties", "%1 ISO", photoInfo.sensitivity));
0319 
0320     if      (photoInfo.exposureMode.isEmpty() && photoInfo.exposureProgram.isEmpty())
0321     {
0322         m_propertiesTab->setPhotoExposureMode(unavailable);
0323     }
0324     else if (!photoInfo.exposureMode.isEmpty() && photoInfo.exposureProgram.isEmpty())
0325     {
0326         m_propertiesTab->setPhotoExposureMode(photoInfo.exposureMode);
0327     }
0328     else if (photoInfo.exposureMode.isEmpty() && !photoInfo.exposureProgram.isEmpty())
0329     {
0330         m_propertiesTab->setPhotoExposureMode(photoInfo.exposureProgram);
0331     }
0332     else
0333     {
0334         str = QString::fromUtf8("%1 / %2").arg(photoInfo.exposureMode).arg(photoInfo.exposureProgram);
0335         m_propertiesTab->setPhotoExposureMode(str);
0336     }
0337 
0338     m_propertiesTab->setPhotoFlash(photoInfo.flash.isEmpty()               ? unavailable : photoInfo.flash);
0339     m_propertiesTab->setPhotoWhiteBalance(photoInfo.whiteBalance.isEmpty() ? unavailable : photoInfo.whiteBalance);
0340 
0341     // -- Audio/Video information ------------------------------------------
0342 
0343     VideoInfoContainer videoInfo = metaData->getVideoInformation();
0344 
0345     m_propertiesTab->setVideoInfoDisable(videoInfo.isEmpty());
0346 
0347     m_propertiesTab->setVideoAspectRatio(videoInfo.aspectRatio.isEmpty()           ? unavailable : videoInfo.aspectRatio);
0348     m_propertiesTab->setVideoDuration(videoInfo.duration.isEmpty()                 ? unavailable : videoInfo.duration);
0349     m_propertiesTab->setVideoFrameRate(videoInfo.frameRate.isEmpty()               ? unavailable : videoInfo.frameRate);
0350     m_propertiesTab->setVideoVideoCodec(videoInfo.videoCodec.isEmpty()             ? unavailable : videoInfo.videoCodec);
0351     m_propertiesTab->setVideoAudioBitRate(videoInfo.audioBitRate.isEmpty()         ? unavailable : videoInfo.audioBitRate);
0352     m_propertiesTab->setVideoAudioChannelType(videoInfo.audioChannelType.isEmpty() ? unavailable : videoInfo.audioChannelType);
0353     m_propertiesTab->setVideoAudioCodec(videoInfo.audioCodec.isEmpty()             ? unavailable : videoInfo.audioCodec);
0354 
0355     // -- Title, caption, ratings, tag information ---------------------
0356 
0357     CaptionsMap titles = metaData->getItemTitles();
0358     QString title;
0359 
0360     if      (titles.contains(QLatin1String("x-default")))
0361     {
0362         title = titles.value(QLatin1String("x-default")).caption;
0363     }
0364     else if (!titles.isEmpty())
0365     {
0366         title = titles.begin().value().caption;
0367     }
0368 
0369     m_propertiesTab->setTitle(title);
0370 
0371     CaptionsMap captions = metaData->getItemComments();
0372     QString caption;
0373 
0374     if      (captions.contains(QLatin1String("x-default")))
0375     {
0376         caption = captions.value(QLatin1String("x-default")).caption;
0377     }
0378     else if (!captions.isEmpty())
0379     {
0380         caption = captions.begin().value().caption;
0381     }
0382 
0383     m_propertiesTab->setCaption(caption);
0384 
0385     m_propertiesTab->setRating(metaData->getItemRating());
0386 
0387     QStringList tagPaths;
0388     metaData->getItemTagsPath(tagPaths);
0389     m_propertiesTab->setTags(tagPaths);
0390 
0391     // Not supported
0392     m_propertiesTab->setVersionnedInfo(QString());
0393     m_propertiesTab->setGroupedInfo(QString());
0394 
0395     m_propertiesTab->showOrHideCachedProperties();
0396 }
0397 
0398 void ItemPropertiesSideBar::doLoadState()
0399 {
0400     Sidebar::doLoadState();
0401 
0402     /// @todo m_propertiesTab should load its settings from our group
0403 
0404     m_propertiesTab->setObjectName(QLatin1String("Image Properties SideBar Expander"));
0405 
0406     KConfigGroup group = getConfigGroup();
0407 
0408     m_propertiesTab->readSettings(group);
0409 
0410 #ifdef HAVE_GEOLOCATION
0411 
0412     const KConfigGroup groupGPSTab      = KConfigGroup(&group, entryName(QLatin1String("GPS Properties Tab")));
0413     m_gpsTab->readSettings(groupGPSTab);
0414 
0415 #endif // HAVE_GEOLOCATION
0416 
0417     const KConfigGroup groupColorTab    = KConfigGroup(&group, entryName(QLatin1String("Color Properties Tab")));
0418     m_colorTab->readSettings(groupColorTab);
0419 
0420     const KConfigGroup groupMetadataTab = KConfigGroup(&group, entryName(QLatin1String("Metadata Properties Tab")));
0421     m_metadataTab->readSettings(groupMetadataTab);
0422 }
0423 
0424 void ItemPropertiesSideBar::doSaveState()
0425 {
0426     Sidebar::doSaveState();
0427 
0428     KConfigGroup group = getConfigGroup();
0429 
0430     m_propertiesTab->writeSettings(group);
0431 
0432 #ifdef HAVE_GEOLOCATION
0433 
0434     KConfigGroup groupGPSTab      = KConfigGroup(&group, entryName(QLatin1String("GPS Properties Tab")));
0435     m_gpsTab->writeSettings(groupGPSTab);
0436 
0437 #endif // HAVE_GEOLOCATION
0438 
0439     KConfigGroup groupColorTab    = KConfigGroup(&group, entryName(QLatin1String("Color Properties Tab")));
0440     m_colorTab->writeSettings(groupColorTab);
0441 
0442     KConfigGroup groupMetadataTab = KConfigGroup(&group, entryName(QLatin1String("Metadata Properties Tab")));
0443     m_metadataTab->writeSettings(groupMetadataTab);
0444 }
0445 
0446 void ItemPropertiesSideBar::slotLoadMetadataFilters()
0447 {
0448     m_metadataTab->loadFilters();
0449 }
0450 
0451 } // namespace Digikam
0452 
0453 #include "moc_itempropertiessidebar.cpp"