1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2009-03-25
7  * Description : Tree View for album models
8  *
9  * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  * Copyright (C) 2010-2011 by Andi Clemens <andi dot clemens at gmail dot com>
11  * Copyright (C) 2014      by Mohamed_Anwer <m_dot_anwer at gmx dot com>
12  * Copyright (C) 2014      by Michael G. Hansen <mike at mghansen dot de>
13  * Copyright (C) 2009-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
14  *
15  * This program is free software; you can redistribute it
16  * and/or modify it under the terms of the GNU General
17  * Public License as published by the Free Software Foundation;
18  * either version 2, or (at your option)
19  * any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * ============================================================ */
27 
28 #include "abstractcheckablealbumtreeview.h"
29 
30 // KDE includes
31 
32 #include <kconfiggroup.h>
33 
34 // Local includes
35 
36 #include "abstractalbumtreeview_p.h"
37 
38 namespace Digikam
39 {
40 
41 class Q_DECL_HIDDEN AbstractCheckableAlbumTreeView::Private
42 {
43 public:
44 
Private()45     explicit Private()
46     {
47     }
48 
49     static const QString configCheckedAlbumsEntry;
50     static const QString configPartiallyCheckedAlbumsEntry;
51     static const QString configRestoreCheckedEntry;
52 
53     QList<int>           checkedAlbumIds;
54     QList<int>           partiallyCheckedAlbumIds;
55 };
56 
57 const QString AbstractCheckableAlbumTreeView::Private::configCheckedAlbumsEntry(QLatin1String("Checked"));
58 const QString AbstractCheckableAlbumTreeView::Private::configPartiallyCheckedAlbumsEntry(QLatin1String("PartiallyChecked"));
59 const QString AbstractCheckableAlbumTreeView::Private::configRestoreCheckedEntry(QLatin1String("RestoreChecked"));
60 
61 // --------------------------------------------------------
62 
AbstractCheckableAlbumTreeView(QWidget * const parent,Flags flags)63 AbstractCheckableAlbumTreeView::AbstractCheckableAlbumTreeView(QWidget* const parent, Flags flags)
64     : AbstractCountingAlbumTreeView(parent, flags & ~CreateDefaultFilterModel),
65       d                            (new Private)
66 {
67     m_checkOnMiddleClick = true;
68     m_restoreCheckState  = false;
69 
70     if (flags & CreateDefaultFilterModel)
71     {
72         setAlbumFilterModel(new CheckableAlbumFilterModel(this));
73     }
74 }
75 
~AbstractCheckableAlbumTreeView()76 AbstractCheckableAlbumTreeView::~AbstractCheckableAlbumTreeView()
77 {
78     delete d;
79 }
80 
albumModel() const81 AbstractCheckableAlbumModel* AbstractCheckableAlbumTreeView::albumModel() const
82 {
83     return dynamic_cast<AbstractCheckableAlbumModel*>(m_albumModel);
84 }
85 
albumFilterModel() const86 CheckableAlbumFilterModel* AbstractCheckableAlbumTreeView::albumFilterModel() const
87 {
88     return dynamic_cast<CheckableAlbumFilterModel*> (m_albumFilterModel);
89 }
90 
setCheckOnMiddleClick(bool doThat)91 void AbstractCheckableAlbumTreeView::setCheckOnMiddleClick(bool doThat)
92 {
93     m_checkOnMiddleClick = doThat;
94 }
95 
middleButtonPressed(Album * a)96 void AbstractCheckableAlbumTreeView::middleButtonPressed(Album* a)
97 {
98     AbstractCheckableAlbumModel* const model = static_cast<AbstractCheckableAlbumModel*>(m_albumModel);
99 
100     if (!model)
101     {
102         return;
103     }
104 
105     if (model->isCheckable())
106     {
107         if (model->isTristate())
108         {
109             switch (model->checkState(a))
110             {
111                 case Qt::Unchecked:
112                     model->setCheckState(a, Qt::PartiallyChecked);
113                     break;
114                 case Qt::PartiallyChecked:
115                     model->setCheckState(a, Qt::Checked);
116                     break;
117                 case Qt::Checked:
118                     model->setCheckState(a, Qt::Unchecked);
119                     break;
120             }
121         }
122         else
123         {
124             model->toggleChecked(a);
125         }
126     }
127 }
128 
isRestoreCheckState() const129 bool AbstractCheckableAlbumTreeView::isRestoreCheckState() const
130 {
131     return m_restoreCheckState;
132 }
133 
setRestoreCheckState(bool restore)134 void AbstractCheckableAlbumTreeView::setRestoreCheckState(bool restore)
135 {
136     m_restoreCheckState = restore;
137 }
138 
doLoadState()139 void AbstractCheckableAlbumTreeView::doLoadState()
140 {
141     AbstractCountingAlbumTreeView::doLoadState();
142 
143     KConfigGroup group = getConfigGroup();
144 
145     if (!m_restoreCheckState)
146     {
147         m_restoreCheckState = group.readEntry(entryName(d->configRestoreCheckedEntry), false);
148     }
149 
150     if (!m_restoreCheckState || !checkableModel()->isCheckable())
151     {
152         return;
153     }
154 
155     const QStringList checkedAlbums = group.readEntry(entryName(d->configCheckedAlbumsEntry), QStringList());
156 
157     d->checkedAlbumIds.clear();
158 
159     foreach (const QString& albumId, checkedAlbums)
160     {
161         bool ok;
162         const int id = albumId.toInt(&ok);
163 
164         if (ok)
165         {
166             d->checkedAlbumIds << id;
167         }
168     }
169 
170     const QStringList partiallyCheckedAlbums = group.readEntry(entryName(d->configPartiallyCheckedAlbumsEntry), QStringList());
171     d->partiallyCheckedAlbumIds.clear();
172 
173     foreach (const QString& albumId, partiallyCheckedAlbums)
174     {
175         bool ok;
176         const int id = albumId.toInt(&ok);
177 
178         if (ok)
179         {
180             d->partiallyCheckedAlbumIds << id;
181         }
182     }
183 
184     // initially sync with the albums that are already in the model
185 
186     restoreCheckStateForHierarchy(QModelIndex());
187     horizontalScrollBar()->setValue(0);
188 }
189 
rowsInserted(const QModelIndex & parent,int start,int end)190 void AbstractCheckableAlbumTreeView::rowsInserted(const QModelIndex& parent, int start, int end)
191 {
192     AbstractCountingAlbumTreeView::rowsInserted(parent, start, end);
193 
194     if (!d->checkedAlbumIds.isEmpty())
195     {
196         for (int i = start ; i <= end ; ++i)
197         {
198             const QModelIndex child = checkableModel()->index(i, 0, parent);
199             restoreCheckState(child);
200         }
201     }
202 }
203 
restoreCheckStateForHierarchy(const QModelIndex & index)204 void AbstractCheckableAlbumTreeView::restoreCheckStateForHierarchy(const QModelIndex& index)
205 {
206     // recurse children
207 
208     for (int i = 0 ; i < checkableModel()->rowCount(index) ; ++i)
209     {
210         const QModelIndex child = checkableModel()->index(i, 0, index);
211         restoreCheckState(child);
212         restoreCheckStateForHierarchy(child);
213     }
214 }
215 
restoreCheckState(const QModelIndex & index)216 void AbstractCheckableAlbumTreeView::restoreCheckState(const QModelIndex& index)
217 {
218     Album* const album = checkableModel()->albumForIndex(index);
219 
220     if (!album || !(album->id()))
221     {
222         return;
223     }
224 
225     if (d->checkedAlbumIds.contains(album->id()))
226     {
227         checkableModel()->setCheckState(album, Qt::Checked);
228         d->checkedAlbumIds.removeOne(album->id());
229     }
230 
231     if (d->partiallyCheckedAlbumIds.contains(album->id()))
232     {
233         checkableModel()->setCheckState(album, Qt::PartiallyChecked);
234         d->partiallyCheckedAlbumIds.removeOne(album->id());
235     }
236 }
237 
doSaveState()238 void AbstractCheckableAlbumTreeView::doSaveState()
239 {
240     AbstractCountingAlbumTreeView::doSaveState();
241 
242     KConfigGroup group = getConfigGroup();
243 
244     group.writeEntry(entryName(d->configRestoreCheckedEntry), m_restoreCheckState);
245 
246     if (!m_restoreCheckState || !checkableModel()->isCheckable())
247     {
248         return;
249     }
250 
251     const QList<Album*> checkedAlbums = checkableModel()->checkedAlbums();
252     QStringList checkedIds;
253 
254     foreach (Album* const album, checkedAlbums)
255     {
256         checkedIds << QString::number(album->id());
257     }
258 
259     group.writeEntry(entryName(d->configCheckedAlbumsEntry), checkedIds);
260 
261     if (!checkableModel()->isTristate())
262     {
263         return;
264     }
265 
266     const QList<Album*> partiallyCheckedAlbums = checkableModel()->partiallyCheckedAlbums();
267     QStringList partiallyCheckedIds;
268 
269     foreach (Album* const album, partiallyCheckedAlbums)
270     {
271         partiallyCheckedIds << QString::number(album->id());
272     }
273 
274     group.writeEntry(entryName(d->configPartiallyCheckedAlbumsEntry), partiallyCheckedIds);
275 }
276 
277 } // namespace Digikam
278