File indexing completed on 2023-09-24 08:19:51

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