1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2009-04-30
7  * Description : rating icon view item at mouse hover
8  *
9  * Copyright (C) 2008      by Peter Penz <peter dot penz at gmx dot at>
10  * Copyright (C) 2009      by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
11  * Copyright (C) 2009-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #include "itemratingoverlay.h"
27 
28 // Local includes
29 
30 #include "itemdelegate.h"
31 #include "itemmodel.h"
32 #include "itemcategorizedview.h"
33 #include "ratingwidget.h"
34 
35 namespace Digikam
36 {
37 
ItemRatingOverlay(QObject * const parent)38 ItemRatingOverlay::ItemRatingOverlay(QObject* const parent)
39     : AbstractWidgetDelegateOverlay(parent)
40 {
41 }
42 
ratingWidget() const43 RatingWidget* ItemRatingOverlay::ratingWidget() const
44 {
45     return static_cast<RatingWidget*>(m_widget);
46 }
47 
createWidget()48 QWidget* ItemRatingOverlay::createWidget()
49 {
50     RatingWidget* const w = new RatingWidget(parentWidget());
51     w->setFading(true);
52     w->setTracking(false);
53 
54     return w;
55 }
56 
setActive(bool active)57 void ItemRatingOverlay::setActive(bool active)
58 {
59     AbstractWidgetDelegateOverlay::setActive(active);
60 
61     if (active)
62     {
63         connect(ratingWidget(), SIGNAL(signalRatingChanged(int)),
64                 this, SLOT(slotRatingChanged(int)));
65 
66         if (view()->model())
67         {
68             connect(view()->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
69                     this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
70         }
71     }
72     else
73     {
74         // widget is deleted
75 
76         if (view() && view()->model())
77         {
78             disconnect(view()->model(), nullptr, this, nullptr);
79         }
80     }
81 }
82 
visualChange()83 void ItemRatingOverlay::visualChange()
84 {
85     if (m_widget &&
86         m_widget->isVisible())
87     {
88         updatePosition();
89     }
90 }
91 
widgetEnterEvent()92 void ItemRatingOverlay::widgetEnterEvent()
93 {
94     widgetEnterNotifyMultiple(m_index);
95 }
96 
widgetLeaveEvent()97 void ItemRatingOverlay::widgetLeaveEvent()
98 {
99     widgetLeaveNotifyMultiple();
100 }
101 
hide()102 void ItemRatingOverlay::hide()
103 {
104     delegate()->setRatingEdited(QModelIndex());
105     AbstractWidgetDelegateOverlay::hide();
106 }
107 
updatePosition()108 void ItemRatingOverlay::updatePosition()
109 {
110     if (!m_index.isValid() || !m_widget)
111     {
112         return;
113     }
114 
115     QRect rect = delegate()->ratingRect();
116 
117     if (rect.width() > ratingWidget()->maximumVisibleWidth())
118     {
119         int offset = (rect.width() - ratingWidget()->maximumVisibleWidth()) / 2;
120         rect.adjust(offset, 0, -offset, 0);
121     }
122 
123     QRect visualRect = m_view->visualRect(m_index);
124     rect.translate(visualRect.topLeft());
125 
126     m_widget->setFixedSize(rect.width() + 1, rect.height() + 1);
127     m_widget->move(rect.topLeft());
128 }
129 
updateRating()130 void ItemRatingOverlay::updateRating()
131 {
132     if (!m_index.isValid() || !m_widget)
133     {
134         return;
135     }
136 
137     ItemInfo info = ItemModel::retrieveItemInfo(m_index);
138     ratingWidget()->setRating(info.rating());
139 }
140 
slotRatingChanged(int rating)141 void ItemRatingOverlay::slotRatingChanged(int rating)
142 {
143     if (m_widget              &&
144         m_widget->isVisible() &&
145         m_index.isValid())
146     {
147         emit ratingEdited(affectedIndexes(m_index), rating);
148     }
149 }
150 
slotEntered(const QModelIndex & index)151 void ItemRatingOverlay::slotEntered(const QModelIndex& index)
152 {
153     AbstractWidgetDelegateOverlay::slotEntered(index);
154 
155     // See bug 228810, this is a small workaround
156     if (m_widget              &&
157         m_widget->isVisible() &&
158         m_index.isValid()     &&
159         index == m_index)
160     {
161         ratingWidget()->setVisibleImmediately();
162     }
163 
164     m_index = index;
165 
166     updatePosition();
167     updateRating();
168 
169     delegate()->setRatingEdited(m_index);
170     view()->update(m_index);
171 }
172 
slotDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)173 void ItemRatingOverlay::slotDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
174 {
175     if (m_widget              &&
176         m_widget->isVisible() &&
177         QItemSelectionRange(topLeft, bottomRight).contains(m_index))
178     {
179         updateRating();
180     }
181 }
182 
183 } // namespace Digikam
184