1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2009-12-05
7  * Description : Side Bar Widget for People
8  *
9  * Copyright (C) 2009-2010 by Johannes Wienke <languitar at semipol dot de>
10  * Copyright (C) 2010-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  * Copyright (C) 2012      by Andi Clemens <andi dot clemens at gmail dot com>
12  * Copyright (C) 2014      by Mohamed_Anwer <m_dot_anwer at gmx dot com>
13  * Copyright (C) 2010      by Aditya Bhatt <adityabhatt1991 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 "peoplesidebarwidget.h"
29 
30 // Qt includes
31 
32 #include <QLabel>
33 #include <QScrollArea>
34 #include <QApplication>
35 #include <QStyle>
36 #include <QPushButton>
37 #include <QIcon>
38 #include <QHBoxLayout>
39 #include <QVBoxLayout>
40 
41 // KDE includes
42 
43 #include <kconfiggroup.h>
44 #include <klocalizedstring.h>
45 
46 // Local includes
47 
48 #include "digikam_debug.h"
49 #include "searchtextbardb.h"
50 #include "tagfolderview.h"
51 #include "timelinewidget.h"
52 #include "facescanwidget.h"
53 #include "facesdetector.h"
54 #include "dnotificationwidget.h"
55 #include "applicationsettings.h"
56 
57 namespace Digikam
58 {
59 
60 class Q_DECL_HIDDEN PeopleSideBarWidget::Private
61 {
62 public:
63 
Private()64     explicit Private()
65       : rescanButton            (nullptr),
66         searchModificationHelper(nullptr),
67         settingsWdg             (nullptr),
68         tagFolderView           (nullptr),
69         tagSearchBar            (nullptr)
70     {
71     }
72 
73     QPushButton*              rescanButton;
74     SearchModificationHelper* searchModificationHelper;
75     FaceScanWidget*           settingsWdg;
76     TagFolderView*            tagFolderView;
77     SearchTextBarDb*          tagSearchBar;
78 };
79 
PeopleSideBarWidget(QWidget * const parent,TagModel * const model,SearchModificationHelper * const searchModificationHelper)80 PeopleSideBarWidget::PeopleSideBarWidget(QWidget* const parent,
81                                          TagModel* const model,
82                                          SearchModificationHelper* const searchModificationHelper)
83     : SidebarWidget(parent),
84       d            (new Private)
85 {
86     setObjectName(QLatin1String("People Sidebar"));
87     setProperty("Shortcut", Qt::CTRL + Qt::SHIFT + Qt::Key_F9);
88     d->searchModificationHelper   = searchModificationHelper;
89 
90     const int spacing             = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
91 
92     QWidget* const     mainView   = new QWidget(this);
93     QScrollArea* const scrollArea = new QScrollArea(this);
94     QVBoxLayout* const mainLayout = new QVBoxLayout(this);
95 
96     mainLayout->addWidget(scrollArea);
97     mainLayout->setContentsMargins(0, 0, spacing, 0);
98     scrollArea->setWidget(mainView);
99     scrollArea->setWidgetResizable(true);
100 
101     model->setColumnHeader(getCaption());
102 
103     QVBoxLayout* const vlay     = new QVBoxLayout;
104     d->tagFolderView            = new TagFolderView(this, model);
105     d->tagFolderView->setConfigGroup(getConfigGroup());
106     d->tagFolderView->setAlbumManagerCurrentAlbum(true);
107     d->tagFolderView->setShowDeleteFaceTagsAction(true);
108 
109     d->tagFolderView->filteredModel()->listOnlyTagsWithProperty(TagPropertyName::person());
110     d->tagFolderView->filteredModel()->setFilterBehavior(AlbumFilterModel::StrictFiltering);
111 
112     d->tagSearchBar   = new SearchTextBarDb(this, QLatin1String("ItemIconViewPeopleSearchBar"));
113     d->tagSearchBar->setHighlightOnResult(true);
114     d->tagSearchBar->setModel(d->tagFolderView->filteredModel(),
115                               AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole);
116     d->tagSearchBar->setFilterModel(d->tagFolderView->albumFilterModel());
117 
118     d->settingsWdg    = new FaceScanWidget(this);
119 
120     d->rescanButton   = new QPushButton;
121     d->rescanButton->setText(i18n("Scan collection for faces"));
122 
123     vlay->addWidget(d->tagFolderView, 10);
124     vlay->addWidget(d->tagSearchBar);
125     vlay->addWidget(d->settingsWdg);
126     vlay->addWidget(d->rescanButton);
127     vlay->setContentsMargins(spacing, spacing, spacing, spacing);
128 
129     mainView->setLayout(vlay);
130 
131     connect(d->tagFolderView, SIGNAL(signalFindDuplicates(QList<TAlbum*>)),
132             this, SIGNAL(signalFindDuplicates(QList<TAlbum*>)));
133 
134     connect(d->rescanButton, SIGNAL(pressed()),
135             this, SLOT(slotScanForFaces()) );
136 }
137 
~PeopleSideBarWidget()138 PeopleSideBarWidget::~PeopleSideBarWidget()
139 {
140     delete d;
141 }
142 
slotInit()143 void PeopleSideBarWidget::slotInit()
144 {
145     loadState();
146 }
147 
setActive(bool active)148 void PeopleSideBarWidget::setActive(bool active)
149 {
150     emit requestFaceMode(active);
151 
152     if (active)
153     {
154         d->tagFolderView->setCurrentAlbums(QList<Album*>() << d->tagFolderView->currentAlbum());
155 
156         if (!ApplicationSettings::instance()->getHelpBoxNotificationSeen())
157         {
158             QString msg = i18n("Welcome to Face Management in digiKam. "
159                                "If this is your first time using this feature, please consider "
160                                "using the Help Box in the Bottom Left Side Panel.");
161             emit signalNotificationError(msg, DNotificationWidget::Information);
162             ApplicationSettings::instance()->setHelpBoxNotificationSeen(true);
163         }
164     }
165 }
166 
doLoadState()167 void PeopleSideBarWidget::doLoadState()
168 {
169     d->tagFolderView->loadState();
170     d->settingsWdg->loadState();
171 }
172 
doSaveState()173 void PeopleSideBarWidget::doSaveState()
174 {
175     d->tagFolderView->saveState();
176     d->settingsWdg->saveState();
177 }
178 
applySettings()179 void PeopleSideBarWidget::applySettings()
180 {
181     ApplicationSettings* const settings = ApplicationSettings::instance();
182     d->tagFolderView->setExpandNewCurrentItem(settings->getExpandNewCurrentItem());
183 }
184 
changeAlbumFromHistory(const QList<Album * > & album)185 void PeopleSideBarWidget::changeAlbumFromHistory(const QList<Album*>& album)
186 {
187     d->tagFolderView->setCurrentAlbums(album);
188 }
189 
slotScanForFaces()190 void PeopleSideBarWidget::slotScanForFaces()
191 {
192     FaceScanSettings faceScanSettings = d->settingsWdg->settings();
193 
194     if (!d->settingsWdg->settingsConflicted())
195     {
196         FacesDetector* const tool = new FacesDetector(faceScanSettings);
197         tool->start();
198 
199         d->settingsWdg->setEnabled(false);
200         d->rescanButton->setEnabled(false);
201 
202         connect(tool, SIGNAL(signalComplete()),
203                 this, SLOT(slotScanComplete()));
204 
205         connect(tool, SIGNAL(signalCanceled()),
206                 this, SLOT(slotScanComplete()));
207     }
208     else
209     {
210         emit signalNotificationError(i18n("Face recognition is aborted, because "
211                                           "there are no identities to recognize. "
212                                           "Please add new identities."),
213                                      DNotificationWidget::Information);
214     }
215 }
216 
slotScanComplete()217 void PeopleSideBarWidget::slotScanComplete()
218 {
219     d->settingsWdg->setEnabled(true);
220     d->rescanButton->setEnabled(true);
221 }
222 
getIcon()223 const QIcon PeopleSideBarWidget::getIcon()
224 {
225     return QIcon::fromTheme(QLatin1String("edit-image-face-show"));
226 }
227 
getCaption()228 const QString PeopleSideBarWidget::getCaption()
229 {
230     return i18nc("Browse images sorted by depicted people", "People");
231 }
232 
233 } // namespace Digikam
234