1
/* ============================================================
3
* This file is a part of digiKam project
4
* http://www.digikam.org
7
* Description : User interface for searches
9
* Copyright (C) 2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
11
* This program is free software; you can redistribute it
12
* and/or modify it under the terms of the GNU General
13
* Public License as published by the Free Software Foundation;
14
* either version 2, or (at your option)
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU General Public License for more details.
22
* ============================================================ */
24
#include "searchgroup.moc"
28
#include <QGridLayout>
31
#include <QRadioButton>
32
#include <QStackedLayout>
33
#include <QVBoxLayout>
37
#include <kcombobox.h>
38
#include <kiconloader.h>
40
#include <kstandarddirs.h>
45
#include "searchfieldgroup.h"
46
#include "searchfields.h"
47
#include "searchutilities.h"
48
#include "searchview.h"
53
SearchGroup::SearchGroup(SearchView* parent)
54
: AbstractSearchGroupContainer(parent),
55
m_view(parent), m_layout(0), m_label(0), m_groupType(FirstGroup)
59
void SearchGroup::setup(Type type)
63
m_layout = new QVBoxLayout;
64
m_layout->setContentsMargins(0, 0, 0, 0);
65
m_layout->setSpacing(0);
67
m_label = new SearchGroupLabel(m_view, m_groupType, this);
68
m_layout->addWidget(m_label);
70
connect(m_label, SIGNAL(removeClicked()),
71
this, SIGNAL(removeRequested()));
73
SearchFieldGroup* group;
74
SearchFieldGroupLabel* label;
78
group = new SearchFieldGroup(this);
79
group->addField(SearchField::createField("keyword", group));
80
m_fieldGroups << group;
81
m_layout->addWidget(group);
83
// this group has no label. Need to show, else it is hidden forever
84
group->setFieldsVisible(true);
88
label = new SearchFieldGroupLabel(this);
89
label->setTitle(i18n("File, Album, Tags"));
90
group = new SearchFieldGroup(this);
91
group->setLabel(label);
93
group->addField(SearchField::createField("albumid", group));
94
group->addField(SearchField::createField("albumname", group));
95
group->addField(SearchField::createField("tagid", group));
96
group->addField(SearchField::createField("tagname", group));
97
group->addField(SearchField::createField("notag", group));
98
group->addField(SearchField::createField("filename", group));
100
m_fieldLabels << label;
101
m_fieldGroups << group;
102
m_layout->addWidget(label);
103
m_layout->addWidget(group);
107
label = new SearchFieldGroupLabel(this);
108
label->setTitle(i18n("Picture Properties"));
109
group = new SearchFieldGroup(this);
110
group->setLabel(label);
112
group->addField(SearchField::createField("creationdate", group));
113
group->addField(SearchField::createField("rating", group));
114
group->addField(SearchField::createField("dimension", group));
115
group->addField(SearchField::createField("pageorientation", group));
116
group->addField(SearchField::createField("width", group));
117
group->addField(SearchField::createField("height", group));
118
group->addField(SearchField::createField("format", group));
119
group->addField(SearchField::createField("colordepth", group));
120
group->addField(SearchField::createField("colormodel", group));
121
group->addField(SearchField::createField("modificationdate", group));
122
group->addField(SearchField::createField("digitizationdate", group));
123
group->addField(SearchField::createField("filesize", group));
125
m_fieldLabels << label;
126
m_fieldGroups << group;
127
m_layout->addWidget(label);
128
m_layout->addWidget(group);
132
label = new SearchFieldGroupLabel(this);
133
label->setTitle(i18n("Caption, Comment, Title"));
134
group = new SearchFieldGroup(this);
135
group->setLabel(label);
137
group->addField(SearchField::createField("comment", group));
138
group->addField(SearchField::createField("commentauthor", group));
139
group->addField(SearchField::createField("headline", group));
140
group->addField(SearchField::createField("title", group));
142
m_fieldLabels << label;
143
m_fieldGroups << group;
144
m_layout->addWidget(label);
145
m_layout->addWidget(group);
149
label = new SearchFieldGroupLabel(this);
150
label->setTitle(i18n("Photograph Information"));
151
group = new SearchFieldGroup(this);
152
group->setLabel(label);
154
group->addField(SearchField::createField("make", group));
155
group->addField(SearchField::createField("model", group));
156
group->addField(SearchField::createField("aperture", group));
157
group->addField(SearchField::createField("focallength", group));
158
group->addField(SearchField::createField("focallength35", group));
159
group->addField(SearchField::createField("exposuretime", group));
160
group->addField(SearchField::createField("exposureprogram", group));
161
group->addField(SearchField::createField("exposuremode", group));
162
group->addField(SearchField::createField("sensitivity", group));
163
group->addField(SearchField::createField("orientation", group));
164
group->addField(SearchField::createField("flashmode", group));
165
group->addField(SearchField::createField("whitebalance", group));
166
group->addField(SearchField::createField("whitebalancecolortemperature", group));
167
group->addField(SearchField::createField("meteringmode", group));
168
group->addField(SearchField::createField("subjectdistance", group));
169
group->addField(SearchField::createField("subjectdistancecategory", group));
171
m_fieldLabels << label;
172
m_fieldGroups << group;
173
m_layout->addWidget(label);
174
m_layout->addWidget(group);
179
label = new SearchFieldGroupLabel(this);
180
label->setTitle(i18n("Geographic position");
181
group = new SearchFieldGroup(this);
182
group->setLabel(label);
184
group->addField(SearchField::createField("latitude", group));
185
group->addField(SearchField::createField("longitude", group));
186
group->addField(SearchField::createField("altitude", group));
187
group->addField(SearchField::createField("nogps", group));
189
m_fieldLabels << label;
190
m_fieldGroups << group;
191
m_layout->addWidget(label);
192
m_layout->addWidget(group);
197
// prepare subgroup layout
198
QHBoxLayout* indentLayout = new QHBoxLayout;
199
indentLayout->setContentsMargins(0, 0, 0, 0);
200
indentLayout->setSpacing(0);
203
option.initFrom(this);
204
int indent = 5 * style()->pixelMetric(QStyle::PM_LayoutLeftMargin, &option, this);
205
indent = qMax(indent, 20);
206
indentLayout->addSpacing(indent);
208
m_subgroupLayout = new QVBoxLayout;
209
m_subgroupLayout->setContentsMargins(0, 0, 0, 0);
210
m_subgroupLayout->setSpacing(0);
212
indentLayout->addLayout(m_subgroupLayout);
214
m_layout->addLayout(indentLayout);
218
m_layout->addStretch(1);
223
// initialization as empty group
227
void SearchGroup::read(SearchXmlCachingReader& reader)
231
m_label->setGroupOperator(reader.groupOperator());
232
m_label->setDefaultFieldOperator(reader.defaultFieldOperator());
234
startReadingGroups(reader);
236
while (!reader.atEnd())
240
if (reader.isEndElement())
246
if (reader.isGroupElement())
251
if (reader.isFieldElement())
253
QString name = reader.fieldName();
255
SearchField* field = 0;
256
SearchFieldGroup* fieldGroup = 0;
257
foreach (fieldGroup, m_fieldGroups)
259
if ( (field = fieldGroup->fieldForName(name)) )
268
fieldGroup->markField(field);
269
fieldGroup->setFieldsVisible(true);
273
kWarning() << "Unhandled search field in XML with field name" << name;
274
reader.readToEndOfElement();
279
finishReadingGroups();
282
SearchGroup* SearchGroup::createSearchGroup()
284
// create a sub group - view is the same
285
SearchGroup* group = new SearchGroup(m_view);
286
group->setup(SearchGroup::ChainGroup);
290
void SearchGroup::addGroupToLayout(SearchGroup* group)
292
// insert in front of the stretch
293
m_subgroupLayout->addWidget(group);
296
void SearchGroup::write(SearchXmlWriter& writer)
299
writer.setGroupOperator(m_label->groupOperator());
300
writer.setDefaultFieldOperator(m_label->defaultFieldOperator());
302
foreach (SearchFieldGroup* fieldGroup, m_fieldGroups)
304
fieldGroup->write(writer);
307
// take care for subgroups
310
writer.finishGroup();
313
void SearchGroup::reset()
315
foreach (SearchFieldGroup* fieldGroup, m_fieldGroups)
320
m_label->setGroupOperator(SearchXml::standardGroupOperator());
321
m_label->setDefaultFieldOperator(SearchXml::standardFieldOperator());
324
SearchGroup::Type SearchGroup::groupType() const
329
QList<QRect> SearchGroup::startupAnimationArea() const
333
rects += startupAnimationAreaOfGroups();
335
foreach (SearchFieldGroup* fieldGroup, m_fieldGroups)
337
rects += fieldGroup->areaOfMarkedFields();
340
// adjust position relative to parent
341
for (QList<QRect>::iterator it = rects.begin(); it != rects.end(); ++it)
343
(*it).translate(pos());
349
// -------------------------------------------------------------------------
351
class RadioButtonHBox : public QHBoxLayout
355
RadioButtonHBox(QWidget* left, QWidget* right, Qt::LayoutDirection dir)
358
if (dir == Qt::RightToLeft)
360
addWidget(right, Qt::AlignRight);
366
addWidget(right, Qt::AlignLeft);
373
SearchGroupLabel::SearchGroupLabel(SearchViewThemedPartsCache* cache, SearchGroup::Type type, QWidget* parent)
375
m_extended(false), m_groupOp(SearchXml::And), m_fieldOp(SearchXml::And),
376
m_groupOpLabel(0), m_stackedLayout(0), m_themeCache(cache)
378
QGridLayout* m_layout = new QGridLayout;
380
// leave styling to style sheet (by object name)
382
QLabel* mainLabel = new QLabel(i18n("Find Pictures"));
383
mainLabel->setObjectName("SearchGroupLabel_MainLabel");
385
// Use radio button with a separate label to fix styling problem, see bug 195809
386
m_allBox = new QRadioButton;
387
QLabel* allBoxLabel = new QLabel(i18n("Meet All of the following conditions"));
388
allBoxLabel->setObjectName("SearchGroupLabel_CheckBox");
390
m_anyBox = new QRadioButton;
391
QLabel* anyBoxLabel = new QLabel(i18n("Meet Any of the following conditions"));
392
anyBoxLabel->setObjectName("SearchGroupLabel_CheckBox");
394
m_noneBox = new QRadioButton;
395
QLabel* noneBoxLabel = new QLabel(i18n("None of these conditions are met"));
396
noneBoxLabel->setObjectName("SearchGroupLabel_CheckBox");
398
m_oneNotBox = new QRadioButton;
399
QLabel* oneNotBoxLabel = new QLabel(i18n("At least one of these conditions is not met"));
400
oneNotBoxLabel->setObjectName("SearchGroupLabel_CheckBox");
402
connect(m_allBox, SIGNAL(toggled(bool)),
403
this, SLOT(boxesToggled()));
404
connect(m_anyBox, SIGNAL(toggled(bool)),
405
this, SLOT(boxesToggled()));
406
connect(m_noneBox, SIGNAL(toggled(bool)),
407
this, SLOT(boxesToggled()));
408
connect(m_oneNotBox, SIGNAL(toggled(bool)),
409
this, SLOT(boxesToggled()));
411
if (type == SearchGroup::FirstGroup)
413
QLabel* logo = new QLabel;
414
logo->setPixmap(QPixmap(KStandardDirs::locate("data", "digikam/data/logo-digikam.png"))
415
.scaled(96, 96, Qt::KeepAspectRatio, Qt::SmoothTransformation));
417
m_optionsLabel = new RClickLabel;
418
m_optionsLabel->setObjectName("SearchGroupLabel_OptionsLabel");
419
connect(m_optionsLabel, SIGNAL(activated()),
420
this, SLOT(toggleShowOptions()));
422
QWidget* simpleHeader = new QWidget;
423
QVBoxLayout* headerLayout = new QVBoxLayout;
424
QLabel* simpleLabel1 = new QLabel;
425
//simpleLabel->setText(i18n("Find Pictures meeting all of these conditions"));
426
//simpleLabel->setPixmap(SmallIcon("edit-find", 128));
427
simpleLabel1->setText(i18n("<qt><p>Search your collection<br/>for pictures meeting the following conditions</p></qt>"));
428
simpleLabel1->setObjectName("SearchGroupLabel_SimpleLabel");
429
headerLayout->addStretch(3);
430
headerLayout->addWidget(simpleLabel1);
431
headerLayout->addStretch(1);
432
headerLayout->setMargin(0);
433
simpleHeader->setLayout(headerLayout);
435
QWidget* optionsBox = new QWidget;
436
QGridLayout* optionsLayout = new QGridLayout;
437
optionsLayout->addLayout(new RadioButtonHBox(m_allBox, allBoxLabel, layoutDirection()), 0, 0);
438
optionsLayout->addLayout(new RadioButtonHBox(m_anyBox, anyBoxLabel, layoutDirection()), 1, 0);
439
optionsLayout->addLayout(new RadioButtonHBox(m_noneBox, noneBoxLabel, layoutDirection()), 0, 1);
440
optionsLayout->addLayout(new RadioButtonHBox(m_oneNotBox, oneNotBoxLabel, layoutDirection()), 1, 1);
441
optionsLayout->setMargin(0);
442
optionsBox->setLayout(optionsLayout);
444
m_stackedLayout = new QStackedLayout;
445
m_stackedLayout->addWidget(simpleHeader);
446
m_stackedLayout->addWidget(optionsBox);
447
m_stackedLayout->setMargin(0);
449
m_layout->addWidget(mainLabel, 0, 0, 1, 1);
450
m_layout->addLayout(m_stackedLayout, 1, 0, 1, 1);
451
m_layout->addWidget(m_optionsLabel, 1, 1, 1, 1, Qt::AlignRight | Qt::AlignBottom);
452
m_layout->addWidget(logo, 0, 2, 2, 1, Qt::AlignTop);
453
m_layout->setColumnStretch(1, 10);
459
m_groupOpLabel = new RClickLabel;
460
m_groupOpLabel->setObjectName("SearchGroupLabel_GroupOpLabel");
461
connect(m_groupOpLabel, SIGNAL(activated()),
462
this, SLOT(toggleGroupOperator()));
464
m_removeLabel = new RClickLabel(i18n("Remove Group"));
465
m_removeLabel->setObjectName("SearchGroupLabel_RemoveLabel");
466
connect(m_removeLabel, SIGNAL(activated()),
467
this, SIGNAL(removeClicked()));
469
m_layout->addWidget(m_groupOpLabel, 0, 0, 1, 1);
470
m_layout->addLayout(new RadioButtonHBox(m_allBox, allBoxLabel, layoutDirection()), 1, 0, 1, 1);
471
m_layout->addLayout(new RadioButtonHBox(m_anyBox, anyBoxLabel, layoutDirection()), 2, 0, 1, 1);
472
m_layout->addLayout(new RadioButtonHBox(m_noneBox, noneBoxLabel, layoutDirection()), 3, 0, 1, 1);
473
m_layout->addLayout(new RadioButtonHBox(m_oneNotBox, oneNotBoxLabel, layoutDirection()), 4, 0, 1, 1);
474
m_layout->addWidget(m_removeLabel, 0, 2, 1, 1);
475
m_layout->setColumnStretch(1, 10);
481
setGroupOperator(SearchXml::standardGroupOperator());
482
setDefaultFieldOperator(SearchXml::standardFieldOperator());
485
void SearchGroupLabel::setExtended(bool extended)
487
m_extended = extended;
489
if (!m_stackedLayout)
496
m_stackedLayout->setCurrentIndex(1);
497
m_allBox->setVisible(true);
498
m_anyBox->setVisible(true);
499
m_noneBox->setVisible(true);
500
m_oneNotBox->setVisible(true);
501
m_optionsLabel->setText(i18n("Hide Options <<"));
505
m_stackedLayout->setCurrentIndex(0);
506
// hide to reduce reserved space in stacked layout
507
m_allBox->setVisible(false);
508
m_anyBox->setVisible(false);
509
m_noneBox->setVisible(false);
510
m_oneNotBox->setVisible(false);
511
m_optionsLabel->setText(i18n("Options >>"));
515
void SearchGroupLabel::toggleShowOptions()
517
setExtended(!m_extended);
520
void SearchGroupLabel::toggleGroupOperator()
522
if (m_groupOp == SearchXml::And)
524
m_groupOp = SearchXml::Or;
526
else if (m_groupOp == SearchXml::Or)
528
m_groupOp = SearchXml::And;
530
else if (m_groupOp == SearchXml::AndNot)
532
m_groupOp = SearchXml::OrNot;
534
else if (m_groupOp == SearchXml::OrNot)
536
m_groupOp = SearchXml::AndNot;
542
void SearchGroupLabel::boxesToggled()
545
if (m_allBox->isChecked() || m_oneNotBox->isChecked())
547
m_fieldOp = SearchXml::And;
551
m_fieldOp = SearchXml::Or;
555
if (m_allBox->isChecked() || m_anyBox->isChecked())
557
if (m_groupOp == SearchXml::AndNot)
559
m_groupOp = SearchXml::And;
561
else if (m_groupOp == SearchXml::OrNot)
563
m_groupOp = SearchXml::Or;
568
if (m_groupOp == SearchXml::And)
570
m_groupOp = SearchXml::AndNot;
572
else if (m_groupOp == SearchXml::Or)
574
m_groupOp = SearchXml::OrNot;
579
void SearchGroupLabel::setGroupOperator(SearchXml::Operator op)
582
adjustOperatorOptions();
586
void SearchGroupLabel::updateGroupLabel()
590
if (m_groupOp == SearchXml::And || m_groupOp == SearchXml::AndNot)
592
m_groupOpLabel->setText(i18n("AND"));
596
m_groupOpLabel->setText(i18n("OR"));
601
void SearchGroupLabel::setDefaultFieldOperator(SearchXml::Operator op)
604
adjustOperatorOptions();
607
void SearchGroupLabel::adjustOperatorOptions()
609
// In the UI, the NOT is done at the level of the field operator,
610
// but in fact we put a NOT in front of the whole group, so it is the group operator!
612
// 1. allBox, All of these conditions are met: (A && B && C), Group And/Or, Field And
613
// 2. anyBox, Any of these conditions are met: (A || B || C), Group And/Or, Field Or
614
// 3. oneNotBox, At least one of these conditions is not met: !(A && B && C) = (!A || !B || !C),
615
// Group AndNot/OrNot, Field And
616
// 4. noneBox, None of these conditions are met: !(A || B || C) = (!A && !B && !C),
617
// Group AndNot/OrNot, Field Or
624
if (m_fieldOp == SearchXml::And)
626
m_allBox->setChecked(true);
630
m_anyBox->setChecked(true);
634
case SearchXml::AndNot:
635
case SearchXml::OrNot:
637
if (m_fieldOp == SearchXml::And)
639
m_oneNotBox->setChecked(true);
643
m_noneBox->setChecked(true);
649
if (!m_allBox->isChecked())
655
SearchXml::Operator SearchGroupLabel::groupOperator() const
660
SearchXml::Operator SearchGroupLabel::defaultFieldOperator() const
662
if (m_anyBox->isChecked() || m_noneBox->isChecked())
664
return SearchXml::Or;
668
return SearchXml::And;
672
void SearchGroupLabel::paintEvent(QPaintEvent*)
674
// paint themed background
676
p.drawPixmap(0, 0, m_themeCache->groupLabelPixmap(width(), height()));
679
} // namespace Digikam