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