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"