File indexing completed on 2025-01-19 03:52:57
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-05-22 0007 * Description : Flickr file list view and items. 0008 * 0009 * SPDX-FileCopyrightText: 2009 by Pieter Edelman <pieter dot edelman at gmx dot net> 0010 * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "flickrlist.h" 0017 0018 // Qt includes 0019 0020 #include <QApplication> 0021 #include <QComboBox> 0022 #include <QPainter> 0023 0024 // KDE includes 0025 0026 #include <klocalizedstring.h> 0027 0028 // Local includes 0029 0030 #include "digikam_debug.h" 0031 #include "dtextedit.h" 0032 #include "wscomboboxdelegate.h" 0033 0034 namespace DigikamGenericFlickrPlugin 0035 { 0036 0037 class Q_DECL_HIDDEN FlickrList::Private 0038 { 0039 public: 0040 0041 explicit Private() 0042 : isPublic (Qt::Unchecked), 0043 isFamily (Qt::Unchecked), 0044 isFriends (Qt::Unchecked), 0045 safetyLevel (FlickrList::SAFE), 0046 contentType (FlickrList::PHOTO), 0047 userIsEditing (false) 0048 { 0049 } 0050 0051 Qt::CheckState isPublic; 0052 Qt::CheckState isFamily; 0053 Qt::CheckState isFriends; 0054 FlickrList::SafetyLevel safetyLevel; 0055 FlickrList::ContentType contentType; 0056 0057 /** 0058 * Used to separate the ImagesList::itemChanged signals that were caused 0059 * programmatically from those caused by the user. 0060 */ 0061 bool userIsEditing; 0062 }; 0063 0064 FlickrList::FlickrList(QWidget* const parent) 0065 : DItemsList(parent), 0066 d (new Private) 0067 { 0068 // Catch a click on the items. 0069 0070 connect(listView(), SIGNAL(itemClicked(QTreeWidgetItem*,int)), 0071 this, SLOT(slotItemClicked(QTreeWidgetItem*,int))); 0072 0073 // Catch it if the items change. 0074 0075 connect(listView(), SIGNAL(itemChanged(QTreeWidgetItem*,int)), 0076 this, SLOT(slotItemChanged(QTreeWidgetItem*,int))); 0077 } 0078 0079 FlickrList::~FlickrList() 0080 { 0081 delete d; 0082 } 0083 0084 void FlickrList::setPublic(Qt::CheckState isPublic) 0085 { 0086 /* Change the general public flag for photos in the list. */ 0087 0088 d->isPublic = isPublic; 0089 setPermissionState(PUBLIC, isPublic); 0090 } 0091 0092 void FlickrList::setFamily(Qt::CheckState isFamily) 0093 { 0094 /* Change the general family flag for photos in the list. */ 0095 0096 d->isFamily = isFamily; 0097 setPermissionState(FAMILY, d->isFamily); 0098 } 0099 0100 void FlickrList::setFriends(Qt::CheckState isFriends) 0101 { 0102 /* Change the general friends flag for photos in the list. */ 0103 0104 d->isFriends = isFriends; 0105 setPermissionState(FRIENDS, d->isFriends); 0106 } 0107 0108 void FlickrList::setSafetyLevels(SafetyLevel safetyLevel) 0109 { 0110 /* Change the general safety level for photos in the list. */ 0111 0112 d->safetyLevel = safetyLevel; 0113 0114 if (safetyLevel != MIXEDLEVELS) 0115 { 0116 for (int i = 0 ; i < listView()->topLevelItemCount() ; ++i) 0117 { 0118 FlickrListViewItem* const lvItem = dynamic_cast<FlickrListViewItem*>(listView()->topLevelItem(i)); 0119 0120 if (lvItem) 0121 { 0122 lvItem->setSafetyLevel(d->safetyLevel); 0123 } 0124 } 0125 } 0126 } 0127 0128 void FlickrList::setContentTypes(ContentType contentType) 0129 { 0130 /* Change the general content type for photos in the list. */ 0131 0132 d->contentType = contentType; 0133 0134 if (contentType != MIXEDTYPES) 0135 { 0136 for (int i = 0 ; i < listView()->topLevelItemCount() ; ++i) 0137 { 0138 FlickrListViewItem* const lvItem = dynamic_cast<FlickrListViewItem*>(listView()->topLevelItem(i)); 0139 0140 if (lvItem) 0141 { 0142 lvItem->setContentType(d->contentType); 0143 } 0144 } 0145 } 0146 } 0147 0148 void FlickrList::setPermissionState(FieldType type, Qt::CheckState state) 0149 { 0150 /* 0151 * When the state of one of the three permission levels changes, distribute 0152 * the global change to each individual photo. 0153 */ 0154 0155 if (state != Qt::PartiallyChecked) 0156 { 0157 for (int i = 0 ; i < listView()->topLevelItemCount() ; ++i) 0158 { 0159 FlickrListViewItem* const lvItem = dynamic_cast<FlickrListViewItem*>(listView()->topLevelItem(i)); 0160 0161 if (lvItem) 0162 { 0163 if (type == PUBLIC) 0164 { 0165 lvItem->setPublic(state); 0166 } 0167 else if (type == FAMILY) 0168 { 0169 lvItem->setFamily(state); 0170 } 0171 else if (type == FRIENDS) 0172 { 0173 lvItem->setFriends(state); 0174 } 0175 } 0176 } 0177 } 0178 } 0179 0180 void FlickrList::slotItemClicked(QTreeWidgetItem* item, int column) 0181 { 0182 // If a click occurs from one of the three permission checkbox columns, 0183 // it means something has changed in the permissions. 0184 0185 if ((column == PUBLIC) || (column == FAMILY) || (column == FRIENDS)) 0186 { 0187 singlePermissionChanged(item, column); 0188 } 0189 else if ((column == static_cast<int>(FlickrList::SAFETYLEVEL)) || (column == static_cast<int>(FlickrList::CONTENTTYPE))) 0190 { 0191 // If a click occurs in the Safety Level or Content Type column, it means 0192 // that editing should start on these items. 0193 0194 d->userIsEditing = true; 0195 ComboBoxDelegate* const cbDelegate = dynamic_cast<ComboBoxDelegate*>(listView()->itemDelegateForColumn(column)); 0196 0197 if (cbDelegate) 0198 { 0199 cbDelegate->startEditing(item, column); 0200 } 0201 } 0202 } 0203 0204 void FlickrList::slotItemChanged(QTreeWidgetItem* item, int column) 0205 { 0206 // If an item in the Safety Level or Content Type column changes, it should 0207 // be distributed further. 0208 0209 if ((column == SAFETYLEVEL) || (column == CONTENTTYPE)) 0210 { 0211 singleComboBoxChanged(item, column); 0212 } 0213 } 0214 0215 void FlickrList::singlePermissionChanged(QTreeWidgetItem* item, int column) 0216 { 0217 /* 0218 * Callback for when the user clicks a checkbox in one of the permission 0219 * columns. 0220 */ 0221 0222 if ((column == PUBLIC) || (column == FAMILY) || (column == FRIENDS)) 0223 { 0224 // Call the toggled() method of the item on which the selection 0225 // occurred. 0226 0227 FlickrListViewItem* const lvItem = dynamic_cast<FlickrListViewItem*>(item); 0228 0229 if (lvItem) 0230 { 0231 lvItem->toggled(); 0232 0233 // Count the number of set checkboxes for the selected column. 0234 0235 int numChecked = 0; 0236 0237 for (int i = 0 ; i < listView()->topLevelItemCount() ; ++i) 0238 { 0239 FlickrListViewItem* const titem = dynamic_cast<FlickrListViewItem*>(listView()->topLevelItem(i)); 0240 0241 if (titem) 0242 { 0243 if (((column == PUBLIC) && (titem->isPublic())) || 0244 ((column == FAMILY) && (titem->isFamily())) || 0245 ((column == FRIENDS) && (titem->isFriends()))) 0246 { 0247 numChecked += 1; 0248 } 0249 } 0250 } 0251 0252 // Determine the new state. 0253 0254 Qt::CheckState state = Qt::PartiallyChecked; 0255 0256 if (numChecked == 0) 0257 { 0258 state = Qt::Unchecked; 0259 } 0260 else if (numChecked == listView()->topLevelItemCount()) 0261 { 0262 state = Qt::Checked; 0263 } 0264 0265 // If needed, signal the change. 0266 0267 if ((column == PUBLIC) && (state != d->isPublic)) 0268 { 0269 setPublic(state); 0270 Q_EMIT signalPermissionChanged(PUBLIC, state); 0271 } 0272 0273 if ((column == FAMILY) && (state != d->isFamily)) 0274 { 0275 setFamily(state); 0276 Q_EMIT signalPermissionChanged(FAMILY, state); 0277 } 0278 0279 if ((column == FRIENDS) && (state != d->isFriends)) 0280 { 0281 setFriends(state); 0282 Q_EMIT signalPermissionChanged(FRIENDS, state); 0283 } 0284 } 0285 } 0286 } 0287 0288 void FlickrList::singleComboBoxChanged(QTreeWidgetItem* item, int column) 0289 { 0290 /* 0291 * Callback for when one of the comboboxes for Safety Level or Content 0292 * Type changes. 0293 */ 0294 0295 // Make sure to only process changes from user editing, because this 0296 // function also responds to programmatic changes, which it causes itself 0297 // again. 0298 0299 if (((column == SAFETYLEVEL) || (column == CONTENTTYPE)) && d->userIsEditing) 0300 { 0301 // The user has stopped editing. 0302 0303 d->userIsEditing = false; 0304 0305 // Convert the value from the model to the setting for the 0306 // FlickrListViewItem. 0307 0308 FlickrListViewItem* const lvItem = dynamic_cast<FlickrListViewItem*>(item); 0309 0310 if (lvItem) 0311 { 0312 int data = lvItem->data(column, Qt::DisplayRole).toInt(); 0313 0314 if (column == SAFETYLEVEL) 0315 { 0316 lvItem->setSafetyLevel(static_cast<SafetyLevel>(data)); 0317 } 0318 else if (column == CONTENTTYPE) 0319 { 0320 lvItem->setContentType(static_cast<ContentType>(data)); 0321 } 0322 0323 // Determine how much photos are set to different Safety Levels/Content 0324 // Types. 0325 0326 QMap<int, int> nums = QMap<int, int>(); 0327 0328 for (int i = 0 ; i < listView()->topLevelItemCount() ; ++i) 0329 { 0330 FlickrListViewItem* const titem = dynamic_cast<FlickrListViewItem*>(listView()->topLevelItem(i)); 0331 0332 if (titem) 0333 { 0334 if (column == SAFETYLEVEL) 0335 { 0336 nums[lvItem->safetyLevel()]++; 0337 } 0338 else if (column == CONTENTTYPE) 0339 { 0340 nums[lvItem->contentType()]++; 0341 } 0342 } 0343 } 0344 0345 // If there's only one Safety Level or Content Type, make everything 0346 // uniform 0347 0348 if (nums.count() == 1) 0349 { 0350 QMapIterator<int, int> i(nums); 0351 i.next(); 0352 0353 if (column == SAFETYLEVEL) 0354 { 0355 SafetyLevel safetyLevel = static_cast<SafetyLevel>(i.key()); 0356 setSafetyLevels(safetyLevel); 0357 Q_EMIT signalSafetyLevelChanged(safetyLevel); 0358 } 0359 else if (column == CONTENTTYPE) 0360 { 0361 ContentType contentType = static_cast<ContentType>(i.key()); 0362 setContentTypes(contentType); 0363 Q_EMIT signalContentTypeChanged(contentType); 0364 } 0365 } 0366 else 0367 { 0368 // If there are different Safety Levels/Content Types among the photos, 0369 // signal that. 0370 0371 if (column == SAFETYLEVEL) 0372 { 0373 setSafetyLevels(MIXEDLEVELS); 0374 Q_EMIT signalSafetyLevelChanged(MIXEDLEVELS); 0375 } 0376 else if (column == CONTENTTYPE) 0377 { 0378 setContentTypes(MIXEDTYPES); 0379 Q_EMIT signalContentTypeChanged(MIXEDTYPES); 0380 } 0381 } 0382 } 0383 } 0384 } 0385 0386 void FlickrList::slotAddImages(const QList<QUrl>& list) 0387 { 0388 /* 0389 * Replaces the ImagesList::slotAddImages method, so that 0390 * FlickrListViewItems can be added instead of ImagesListViewItems 0391 */ 0392 0393 // Figure out which permissions should be used. If permissions are set to 0394 // intermediate, default to the most public option. 0395 0396 bool isPublic, isFamily, isFriends; 0397 (d->isPublic == Qt::PartiallyChecked) ? isPublic = true : isPublic = d->isPublic; 0398 (d->isFamily == Qt::PartiallyChecked) ? isFamily = true : isFamily = d->isFamily; 0399 (d->isFriends == Qt::PartiallyChecked) ? isFriends = true : isFriends = d->isFriends; 0400 0401 // Figure out safety level and content type. If these are intermediate, use 0402 // the Flickr defaults. 0403 0404 SafetyLevel safetyLevel; 0405 ContentType contentType; 0406 (d->safetyLevel == MIXEDLEVELS) ? safetyLevel = SAFE : safetyLevel = d->safetyLevel; 0407 (d->contentType == MIXEDTYPES) ? contentType = PHOTO : contentType = d->contentType; 0408 0409 // Figure out which of the supplied URL's should actually be added and which 0410 // of them already exist. 0411 0412 bool found; 0413 QList<QUrl> added_urls; 0414 QList<QUrl>::const_iterator it; 0415 0416 for (it = list.constBegin() ; it != list.constEnd() ; ++it) 0417 { 0418 QUrl imageUrl = *it; 0419 found = false; 0420 0421 for (int i = 0 ; i < listView()->topLevelItemCount() ; ++i) 0422 { 0423 FlickrListViewItem* const currItem = dynamic_cast<FlickrListViewItem*>(listView()->topLevelItem(i)); 0424 0425 if (currItem && (currItem->url() == imageUrl)) 0426 { 0427 found = true; 0428 break; 0429 } 0430 } 0431 0432 if (!found) 0433 { 0434 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Inserting new item " << imageUrl.fileName(); 0435 new FlickrListViewItem(listView(), imageUrl, 0436 isPublic, isFamily, isFriends, 0437 safetyLevel, contentType); 0438 added_urls.append(imageUrl); 0439 } 0440 } 0441 0442 // Duplicate the signalImageListChanged of the ImageWindow, to enable the 0443 // upload button again. 0444 0445 Q_EMIT signalImageListChanged(); 0446 } 0447 0448 // ------------------------------------------------------------------------------------------------ 0449 0450 class Q_DECL_HIDDEN FlickrListViewItem::Private 0451 { 0452 public: 0453 0454 explicit Private() 0455 : isPublic (true), 0456 isFamily (true), 0457 isFriends (true), 0458 safetyLevel(FlickrList::SAFE), 0459 contentType(FlickrList::PHOTO), 0460 tagLineEdit(nullptr) 0461 { 0462 } 0463 0464 bool isPublic; 0465 bool isFamily; 0466 bool isFriends; 0467 0468 FlickrList::SafetyLevel safetyLevel; 0469 FlickrList::ContentType contentType; 0470 0471 /** 0472 * LineEdit used for extra tags per image. 0473 */ 0474 DTextEdit* tagLineEdit; 0475 }; 0476 0477 FlickrListViewItem::FlickrListViewItem(DItemsListView* const view, 0478 const QUrl& url, 0479 bool accessPublic = true, 0480 bool accessFamily = true, 0481 bool accessFriends = true, 0482 FlickrList::SafetyLevel safetyLevel = FlickrList::SAFE, 0483 FlickrList::ContentType contentType = FlickrList::PHOTO) 0484 : DItemsListViewItem(view, url), 0485 d(new Private) 0486 { 0487 /* 0488 * Initialize the FlickrListViewItem with the ImagesListView and a QUrl 0489 * object pointing to the location on disk. 0490 * The access_public, access_family and access_friends flags determine if 0491 * the public, family and friends permissions of this particular photo. 0492 */ 0493 0494 // Set the flags for checkboxes to appear 0495 0496 setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); 0497 0498 // Set the text and checkbox for the public column. 0499 0500 setCheckState(static_cast<DItemsListView::ColumnType>(FlickrList::PUBLIC), accessPublic ? Qt::Checked : Qt::Unchecked); 0501 0502 // Set the tooltips to guide the user to the mass settings options. 0503 0504 setToolTip(static_cast<DItemsListView::ColumnType>(FlickrList::PUBLIC), 0505 i18n("Check if photo should be publicly visible or use Upload " 0506 "Options tab to specify this for all images")); 0507 setToolTip(static_cast<DItemsListView::ColumnType>(FlickrList::FAMILY), 0508 i18n("Check if photo should be visible to family or use Upload " 0509 "Options tab to specify this for all images")); 0510 setToolTip(static_cast<DItemsListView::ColumnType>(FlickrList::FRIENDS), 0511 i18n("Check if photo should be visible to friends or use " 0512 "Upload Options tab to specify this for all images")); 0513 setToolTip(static_cast<DItemsListView::ColumnType>(FlickrList::SAFETYLEVEL), 0514 i18n("Indicate the safety level for the photo or use Upload " 0515 "Options tab to specify this for all images")); 0516 setToolTip(static_cast<DItemsListView::ColumnType>(FlickrList::CONTENTTYPE), 0517 i18n("Indicate what kind of image this is or use Upload " 0518 "Options tab to specify this for all images")); 0519 0520 // Set the other checkboxes. 0521 0522 setFamily(accessFamily); 0523 setFriends(accessFriends); 0524 setPublic(accessPublic); 0525 setSafetyLevel(safetyLevel); 0526 setContentType(contentType); 0527 0528 // Extra per image tags handling. 0529 0530 setToolTip(static_cast<DItemsListView::ColumnType>( 0531 FlickrList::TAGS), 0532 i18n("Add extra tags per image or use Upload Options tab to " 0533 "add tags for all images")); 0534 0535 this->updateItemWidgets(); 0536 } 0537 0538 FlickrListViewItem::~FlickrListViewItem() 0539 { 0540 delete d; 0541 } 0542 0543 void FlickrListViewItem::updateItemWidgets() 0544 { 0545 d->tagLineEdit = new DTextEdit(view()); 0546 d->tagLineEdit->setLinesVisible(1); 0547 d->tagLineEdit->setToolTip(i18n("Enter extra tags, separated by commas.")); 0548 view()->setItemWidget(this, static_cast<DItemsListView::ColumnType>( 0549 FlickrList::TAGS), d->tagLineEdit); 0550 } 0551 0552 QStringList FlickrListViewItem::extraTags() const 0553 { 0554 return d->tagLineEdit->text().split(QLatin1Char(','), QT_SKIP_EMPTY_PARTS); 0555 } 0556 0557 void FlickrListViewItem::toggled() 0558 { 0559 // The d->isFamily and d->isFriends states should be set first, so that the 0560 // setPublic method has the proper values to work with. 0561 0562 if (data(FlickrList::FAMILY, Qt::CheckStateRole) != QVariant()) 0563 { 0564 setFamily(checkState(static_cast<DItemsListView::ColumnType>(FlickrList::FAMILY))); 0565 } 0566 0567 if (data(FlickrList::FRIENDS, Qt::CheckStateRole) != QVariant()) 0568 { 0569 setFriends(checkState(static_cast<DItemsListView::ColumnType>(FlickrList::FRIENDS))); 0570 } 0571 0572 setPublic(checkState(static_cast<DItemsListView::ColumnType>(FlickrList::PUBLIC))); 0573 } 0574 0575 void FlickrListViewItem::setPublic(bool status) 0576 { 0577 /* 0578 * Set the public status of the entry. If public is true, hide the 0579 * family and friends checkboxes, otherwise, make them appear. 0580 */ 0581 0582 // Set the status. 0583 0584 d->isPublic = status; 0585 0586 // Toggle the family and friends checkboxes, if applicable. 0587 0588 if (d->isPublic) 0589 { 0590 // Hide the checkboxes by feeding them a bogus QVariant for the 0591 // CheckStateRole. This might seem like a hack, but it's described in 0592 // the Qt FAQ at 0593 // www.qtsoftware.com/developer/faqs/faq.2007-04-23.8353273326. 0594 0595 setData(static_cast<DItemsListView::ColumnType>(FlickrList::FAMILY), Qt::CheckStateRole, QVariant()); 0596 setData(static_cast<DItemsListView::ColumnType>(FlickrList::FRIENDS), Qt::CheckStateRole, QVariant()); 0597 } 0598 else 0599 { 0600 // Show the checkboxes. 0601 0602 setCheckState(static_cast<DItemsListView::ColumnType>(FlickrList::FAMILY), d->isFamily ? Qt::Checked : Qt::Unchecked); 0603 setCheckState(static_cast<DItemsListView::ColumnType>(FlickrList::FRIENDS), d->isFriends ? Qt::Checked : Qt::Unchecked); 0604 } 0605 0606 // Toggle the public checkboxes 0607 0608 if (d->isPublic) 0609 { 0610 setCheckState(FlickrList::PUBLIC, Qt::Checked); 0611 } 0612 else 0613 { 0614 setCheckState(FlickrList::PUBLIC, Qt::Unchecked); 0615 } 0616 0617 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Public status set to" << d->isPublic; 0618 } 0619 0620 void FlickrListViewItem::setFamily(bool status) 0621 { 0622 /* Set the family status. */ 0623 0624 d->isFamily = status; 0625 0626 if (data(FlickrList::FAMILY, Qt::CheckStateRole) != QVariant()) 0627 { 0628 setCheckState(FlickrList::FAMILY, d->isFamily ? Qt::Checked : Qt::Unchecked); 0629 } 0630 0631 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Family status set to" << d->isFamily; 0632 } 0633 0634 void FlickrListViewItem::setFriends(bool status) 0635 { 0636 /* Set the family status. */ 0637 0638 d->isFriends = status; 0639 0640 if (data(FlickrList::FRIENDS, Qt::CheckStateRole) != QVariant()) 0641 { 0642 setCheckState(FlickrList::FRIENDS, d->isFriends ? Qt::Checked : Qt::Unchecked); 0643 } 0644 0645 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Friends status set to" << d->isFriends; 0646 } 0647 0648 void FlickrListViewItem::setSafetyLevel(FlickrList::SafetyLevel safetyLevel) 0649 { 0650 d->safetyLevel = safetyLevel; 0651 setData(FlickrList::SAFETYLEVEL, Qt::DisplayRole, QVariant(safetyLevel)); 0652 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Safety level set to" << safetyLevel; 0653 } 0654 0655 void FlickrListViewItem::setContentType(FlickrList::ContentType contentType) 0656 { 0657 d->contentType = contentType; 0658 setData(FlickrList::CONTENTTYPE, Qt::DisplayRole, QVariant(contentType)); 0659 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Content type set to" << contentType; 0660 } 0661 0662 bool FlickrListViewItem::isPublic() const 0663 { 0664 /* Return whether the photo is public. */ 0665 0666 return d->isPublic; 0667 } 0668 0669 bool FlickrListViewItem::isFamily() const 0670 { 0671 /* Return whether the photo is accessible for family. */ 0672 0673 return d->isFamily; 0674 } 0675 0676 bool FlickrListViewItem::isFriends() const 0677 { 0678 /* Return whether the photo is accessible for friends. */ 0679 0680 return d->isFriends; 0681 } 0682 0683 FlickrList::SafetyLevel FlickrListViewItem::safetyLevel() const 0684 { 0685 return d->safetyLevel; 0686 } 0687 0688 FlickrList::ContentType FlickrListViewItem::contentType() const 0689 { 0690 return d->contentType; 0691 } 0692 0693 } // namespace DigikamGenericFlickrPlugin 0694 0695 #include "moc_flickrlist.cpp"