File indexing completed on 2025-04-27 03:58:26
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-08-11 0007 * Description : a combo box containing ICC profiles 0008 * 0009 * SPDX-FileCopyrightText: 2009-2010 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "iccprofilescombobox.h" 0016 0017 // Qt includes 0018 0019 #include <QFileInfo> 0020 #include <QSet> 0021 #include <QAction> 0022 0023 // KDE includes 0024 0025 #include <klocalizedstring.h> 0026 0027 // Local includes 0028 0029 #include "icctransform.h" 0030 0031 namespace Digikam 0032 { 0033 0034 IccProfilesComboBox::IccProfilesComboBox(QWidget* const parent) 0035 : SqueezedComboBox(parent) 0036 { 0037 } 0038 0039 IccProfilesComboBox::~IccProfilesComboBox() 0040 { 0041 } 0042 0043 bool iccProfileLessThan(IccProfile a, IccProfile b) 0044 { 0045 return (a.description() < b.description()); 0046 } 0047 0048 // if needed outside this class, make it a public static method in a namespace 0049 static QString profileUserString(const IccProfile& p) 0050 { 0051 IccProfile profile(p); 0052 QFileInfo info(profile.filePath()); 0053 QString fileName = info.fileName(); 0054 0055 QString description = profile.description(); 0056 0057 if (!description.isEmpty() && !fileName.isEmpty()) 0058 { 0059 return i18nc("<Profile Description> (<File Name>)", "%1 (%2)", description, fileName); 0060 } 0061 else if (!fileName.isEmpty()) 0062 { 0063 return fileName; 0064 } 0065 else 0066 { 0067 return QString(); 0068 } 0069 } 0070 0071 /** 0072 * NOTE: if needed outside this class, make it a public static method in a namespace 0073 */ 0074 static void formatProfiles(const QList<IccProfile>& givenProfiles, QList<IccProfile>* const returnedProfiles, QStringList* const userText) 0075 { 0076 QList<IccProfile> profiles; 0077 QSet<QString> filePaths; 0078 0079 Q_FOREACH (IccProfile profile, givenProfiles) // krazy:exclude=foreach 0080 { 0081 QString filePath = profile.filePath(); 0082 0083 if (!profile.description().isNull() && (filePath.isNull() || !filePaths.contains(filePath)) ) 0084 { 0085 profiles << profile; 0086 filePaths << filePath; 0087 } 0088 } 0089 0090 std::sort(profiles.begin(), profiles.end(), iccProfileLessThan); 0091 0092 Q_FOREACH (IccProfile profile, profiles) // krazy:exclude=foreach 0093 { 0094 QString description = profileUserString(profile); 0095 0096 if (description.isNull()) 0097 { 0098 continue; 0099 } 0100 0101 *returnedProfiles << profile; 0102 *userText << description; 0103 } 0104 } 0105 0106 void IccProfilesComboBox::addProfilesSqueezed(const QList<IccProfile>& givenProfiles) 0107 { 0108 QList<IccProfile> profiles; 0109 QStringList userDescription; 0110 formatProfiles(givenProfiles, &profiles, &userDescription); 0111 0112 for (int i = 0 ; i < profiles.size() ; ++i) 0113 { 0114 addSqueezedItem(userDescription.at(i), QVariant::fromValue(profiles.at(i))); 0115 } 0116 } 0117 0118 void IccProfilesComboBox::addProfileSqueezed(const IccProfile& profile, const QString& d) 0119 { 0120 QString description = d; 0121 0122 if (description.isNull()) 0123 { 0124 description = profileUserString(profile); 0125 } 0126 0127 addSqueezedItem(description, QVariant::fromValue(profile)); 0128 } 0129 0130 void IccProfilesComboBox::replaceProfilesSqueezed(const QList<IccProfile>& profiles) 0131 { 0132 IccProfile current = currentProfile(); 0133 clear(); 0134 addProfilesSqueezed(profiles); 0135 setCurrentProfile(current); 0136 } 0137 0138 void IccProfilesComboBox::setNoProfileIfEmpty(const QString& message) 0139 { 0140 if (count() == 0) 0141 { 0142 setEnabled(false); 0143 addSqueezedItem(message); 0144 setCurrentIndex(0); 0145 } 0146 } 0147 0148 IccProfile IccProfilesComboBox::currentProfile() const 0149 { 0150 return itemData(currentIndex()).value<IccProfile>(); 0151 } 0152 0153 void IccProfilesComboBox::setCurrentProfile(const IccProfile& profile) 0154 { 0155 if (profile.isNull()) 0156 { 0157 setCurrentIndex(-1); 0158 return; 0159 } 0160 0161 const int size = count(); 0162 0163 for (int i = 0 ; i < size ; ++i) 0164 { 0165 if (itemData(i).value<IccProfile>() == profile) 0166 { 0167 setCurrentIndex(i); 0168 return; 0169 } 0170 } 0171 0172 setCurrentIndex(-1); 0173 } 0174 0175 // ------------------------------------------------------------------------------------------ 0176 0177 IccProfilesMenuAction::IccProfilesMenuAction(const QIcon& icon, const QString& text, QObject* const parent) 0178 : QMenu (text), 0179 m_parent(parent) 0180 { 0181 setIcon(icon); 0182 } 0183 0184 IccProfilesMenuAction::IccProfilesMenuAction(const QString& text, QObject* const parent) 0185 : QMenu (text), 0186 m_parent(parent) 0187 { 0188 } 0189 0190 void IccProfilesMenuAction::replaceProfiles(const QList<IccProfile>& profiles) 0191 { 0192 clear(); 0193 addProfiles(profiles); 0194 } 0195 0196 void IccProfilesMenuAction::addProfiles(const QList<IccProfile>& givenProfiles) 0197 { 0198 QList<IccProfile> profiles; 0199 QStringList userDescription; 0200 formatProfiles(givenProfiles, &profiles, &userDescription); 0201 0202 for (int i = 0 ; i < profiles.size() ; ++i) 0203 { 0204 addProfile(profiles.at(i), userDescription.at(i)); 0205 } 0206 } 0207 0208 void IccProfilesMenuAction::addProfile(const IccProfile& profile, const QString& d) 0209 { 0210 QString description = d; 0211 0212 if (description.isNull()) 0213 { 0214 description = profileUserString(profile); 0215 } 0216 0217 QAction* const action = new QAction(d.left(50), m_parent); 0218 action->setData(QVariant::fromValue(profile)); 0219 addAction(action); 0220 0221 connect(action, &QAction::triggered, 0222 this, [this, action]() { slotTriggered(action); }); 0223 } 0224 0225 void IccProfilesMenuAction::disableIfEmpty() 0226 { 0227 if (isEmpty()) 0228 { 0229 setEnabled(false); 0230 } 0231 } 0232 0233 void IccProfilesMenuAction::slotTriggered(QObject* obj) 0234 { 0235 QAction* const action = static_cast<QAction*>(obj); 0236 IccProfile profile = action->data().value<IccProfile>(); 0237 0238 if (!profile.isNull()) 0239 { 0240 Q_EMIT triggered(profile); 0241 } 0242 } 0243 0244 QObject* IccProfilesMenuAction::parentObject() const 0245 { 0246 return m_parent; 0247 } 0248 0249 // ------------------------------------------------------------------------------------------ 0250 0251 IccRenderingIntentComboBox::IccRenderingIntentComboBox(QWidget* const parent) 0252 : QComboBox(parent) 0253 { 0254 addItem(i18n("Perceptual"), IccTransform::Perceptual); 0255 addItem(i18n("Relative Colorimetric"), IccTransform::RelativeColorimetric); 0256 addItem(i18n("Absolute Colorimetric"), IccTransform::AbsoluteColorimetric); 0257 addItem(i18n("Saturation"), IccTransform::Saturation); 0258 setWhatsThis(i18n("<ul><li><p><b>Perceptual intent</b> causes the full gamut of the image to be " 0259 "compressed or expanded to fill the gamut of the destination device, so that gray balance is " 0260 "preserved but colorimetric accuracy may not be preserved.</p>" 0261 "<p>In other words, if certain colors in an image fall outside of the range of colors that the output " 0262 "device can render, the image intent will cause all the colors in the image to be adjusted so that " 0263 "the every color in the image falls within the range that can be rendered and so that the relationship " 0264 "between colors is preserved as much as possible.</p>" 0265 "<p>This intent is most suitable for display of photographs and images, and is the default intent.</p></li>" 0266 "<li><p><b>Absolute Colorimetric intent</b> causes any colors that fall outside the range that the output device " 0267 "can render to be adjusted to the closest color that can be rendered, while all other colors are " 0268 "left unchanged.</p>" 0269 "<p>This intent preserves the white point and is most suitable for spot colors (Pantone, TruMatch, " 0270 "logo colors, ....)</p></li>" 0271 "<li><p><b>Relative Colorimetric intent</b> is defined such that any colors that fall outside the range that the " 0272 "output device can render are adjusted to the closest color that can be rendered, while all other colors " 0273 "are left unchanged. Proof intent does not preserve the white point.</p></li>" 0274 "<li><p><b>Saturation intent</b> preserves the saturation of colors in the image at the possible expense of " 0275 "hue and lightness.</p>" 0276 "<p>Implementation of this intent remains somewhat problematic, and the ICC is still working on methods to " 0277 "achieve the desired effects.</p>" 0278 "<p>This intent is most suitable for business graphics such as charts, where it is more important that the " 0279 "colors be vivid and contrast well with each other rather than a specific color.</p></li></ul>")); 0280 } 0281 0282 void IccRenderingIntentComboBox::setIntent(int intent) 0283 { 0284 const int size = count(); 0285 0286 for (int i = 0 ; i < size ; ++i) 0287 { 0288 if (itemData(i).toInt() == intent) 0289 { 0290 setCurrentIndex(i); 0291 return; 0292 } 0293 } 0294 0295 setCurrentIndex(-1); 0296 } 0297 0298 int IccRenderingIntentComboBox::intent() const 0299 { 0300 return itemData(currentIndex()).toInt(); 0301 } 0302 0303 } // namespace Digikam 0304 0305 #include "moc_iccprofilescombobox.cpp"