kdelibs/kexiv2/libkexiv2/subjectwidget.cpp
Ivailo Monev a0dbbaabdf generic: rename merged libraries directories for consistency
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2015-10-29 13:57:28 +02:00

601 lines
19 KiB
C++

/** ===========================================================
* @file
*
* This file is a part of digiKam project
* <a href="http://www.digikam.org">http://www.digikam.org</a>
*
* @date 2006-10-15
* @brief IPTC subjects editor.
*
* @author Copyright (C) 2006-2012 by Gilles Caulier
* <a href="mailto:caulier dot gilles at gmail dot com">caulier dot gilles at gmail dot com</a>
* @author Copyright (C) 2009-2012 by Andi Clemens
* <a href="mailto:andi dot clemens at googlemail dot com">andi dot clemens at googlemail dot com</a>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
#include "moc_subjectwidget.cpp"
// Qt includes
#include <QCheckBox>
#include <QtXml/qdom.h>
#include <QtXml/qdom.h>
#include <QFile>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QRadioButton>
#include <QValidator>
// KDE includes
#include <kcombobox.h>
#include <kdialog.h>
#include <kglobal.h>
#include <khbox.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <klistwidget.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kdebug.h>
namespace KExiv2Iface
{
class SubjectWidget::Private
{
public:
enum EditionMode
{
STANDARD = 0,
CUSTOM
};
Private()
{
addSubjectButton = 0;
delSubjectButton = 0;
repSubjectButton = 0;
subjectsBox = 0;
iprLabel = 0;
refLabel = 0;
nameLabel = 0;
matterLabel = 0;
detailLabel = 0;
btnGroup = 0;
stdBtn = 0;
customBtn = 0;
refCB = 0;
optionsBox = 0;
}
typedef QMap<QString, SubjectData> SubjectCodesMap;
SubjectCodesMap subMap;
QStringList subjectsList;
QWidget* optionsBox;
QPushButton* addSubjectButton;
QPushButton* delSubjectButton;
QPushButton* repSubjectButton;
QLabel* iprLabel;
QLabel* refLabel;
QLabel* nameLabel;
QLabel* matterLabel;
QLabel* detailLabel;
QButtonGroup* btnGroup;
QRadioButton* stdBtn;
QRadioButton* customBtn;
KComboBox* refCB;
KListWidget* subjectsBox;
};
// --------------------------------------------------------------------------------
SubjectWidget::SubjectWidget(QWidget* parent)
: QWidget(parent), d(new Private)
{
// Load subject codes provided by IPTC/NAA as xml file.
// See http://iptc.cms.apa.at/std/topicset/topicset.iptc-subjectcode.xml for details.
KGlobal::dirs()->addResourceDir("iptcschema", KStandardDirs::installPath("data") +
QString("libkexiv2/data"));
QString path = KGlobal::dirs()->findResource("iptcschema", "topicset.iptc-subjectcode.xml");
if (!loadSubjectCodesFromXML(KUrl(path)))
kDebug() << "Cannot load IPTC/NAA subject codes XML database";
// --------------------------------------------------------
// Subject Reference Number only accept digit.
QRegExp refDigitRx("^[0-9]{8}$");
QValidator *refValidator = new QRegExpValidator(refDigitRx, this);
// --------------------------------------------------------
m_subjectsCheck = new QCheckBox(i18n("Use structured definition of the subject matter:"), this);
d->optionsBox = new QWidget;
d->btnGroup = new QButtonGroup(this);
d->stdBtn = new QRadioButton;
d->customBtn = new QRadioButton;
d->refCB = new KComboBox;
QLabel* codeLink = new QLabel(i18n("Use standard "
"<b><a href='http://www.iptc.org/site/NewsCodes'>"
"reference code</a></b>"));
codeLink->setOpenExternalLinks(true);
codeLink->setWordWrap(false);
// By default, check box is not visible. (digiKam do not use it, kipi-plugins yes).
m_subjectsCheck->setVisible(false);
QLabel* customLabel = new QLabel(i18n("Use custom definition"));
d->btnGroup->addButton(d->stdBtn, Private::STANDARD);
d->btnGroup->addButton(d->customBtn, Private::CUSTOM);
d->btnGroup->setExclusive(true);
d->stdBtn->setChecked(true);
for (Private::SubjectCodesMap::Iterator it = d->subMap.begin();
it != d->subMap.end(); ++it)
d->refCB->addItem(it.key());
// --------------------------------------------------------
m_iprEdit = new KLineEdit;
m_iprEdit->setClearButtonShown(true);
m_iprEdit->setMaxLength(32);
// --------------------------------------------------------
m_refEdit = new KLineEdit;
m_refEdit->setClearButtonShown(true);
m_refEdit->setValidator(refValidator);
m_refEdit->setMaxLength(8);
// --------------------------------------------------------
m_nameEdit = new KLineEdit;
m_nameEdit->setClearButtonShown(true);
m_nameEdit->setMaxLength(64);
// --------------------------------------------------------
m_matterEdit = new KLineEdit;
m_matterEdit->setClearButtonShown(true);
m_matterEdit->setMaxLength(64);
// --------------------------------------------------------
m_detailEdit = new KLineEdit;
m_detailEdit->setClearButtonShown(true);
m_detailEdit->setMaxLength(64);
// --------------------------------------------------------
d->iprLabel = new QLabel(i18nc("Information Provider Reference: "
"A name, registered with the IPTC/NAA, "
"identifying the provider that guarantees "
"the uniqueness of the UNO", "I.P.R:"));
d->refLabel = new QLabel(i18n("Reference:"));
d->nameLabel = new QLabel(i18n("Name:"));
d->matterLabel = new QLabel(i18n("Matter:"));
d->detailLabel = new QLabel(i18n("Detail:"));
// --------------------------------------------------------
d->subjectsBox = new KListWidget;
d->subjectsBox->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
d->addSubjectButton = new QPushButton(i18n("&Add"));
d->delSubjectButton = new QPushButton(i18n("&Delete"));
d->repSubjectButton = new QPushButton(i18n("&Replace"));
d->addSubjectButton->setIcon(SmallIcon("list-add"));
d->delSubjectButton->setIcon(SmallIcon("edit-delete"));
d->repSubjectButton->setIcon(SmallIcon("view-refresh"));
d->delSubjectButton->setEnabled(false);
d->repSubjectButton->setEnabled(false);
// --------------------------------------------------------
m_note = new QLabel;
m_note->setMaximumWidth(150);
m_note->setOpenExternalLinks(true);
m_note->setWordWrap(true);
m_note->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
// --------------------------------------------------------
QGridLayout* optionsBoxLayout = new QGridLayout;
optionsBoxLayout->addWidget(d->stdBtn, 0, 0, 1, 1);
optionsBoxLayout->addWidget(codeLink, 0, 1, 1, 2);
optionsBoxLayout->addWidget(d->refCB, 0, 3, 1, 1);
optionsBoxLayout->addWidget(d->customBtn, 1, 0, 1, 4);
optionsBoxLayout->addWidget(customLabel, 1, 1, 1, 4);
optionsBoxLayout->addWidget(d->iprLabel, 2, 0, 1, 1);
optionsBoxLayout->addWidget(m_iprEdit, 2, 1, 1, 4);
optionsBoxLayout->addWidget(d->refLabel, 3, 0, 1, 1);
optionsBoxLayout->addWidget(m_refEdit, 3, 1, 1, 1);
optionsBoxLayout->addWidget(d->nameLabel, 4, 0, 1, 1);
optionsBoxLayout->addWidget(m_nameEdit, 4, 1, 1, 4);
optionsBoxLayout->addWidget(d->matterLabel, 5, 0, 1, 1);
optionsBoxLayout->addWidget(m_matterEdit, 5, 1, 1, 4);
optionsBoxLayout->addWidget(d->detailLabel, 6, 0, 1, 1);
optionsBoxLayout->addWidget(m_detailEdit, 6, 1, 1, 4);
optionsBoxLayout->setColumnStretch(4, 10);
optionsBoxLayout->setMargin(0);
optionsBoxLayout->setSpacing(KDialog::spacingHint());
d->optionsBox->setLayout(optionsBoxLayout);
// --------------------------------------------------------
QGridLayout* mainLayout = new QGridLayout;
mainLayout->setAlignment( Qt::AlignTop );
mainLayout->addWidget(m_subjectsCheck, 0, 0, 1, 4);
mainLayout->addWidget(d->optionsBox, 1, 0, 1, 4);
mainLayout->addWidget(d->subjectsBox, 2, 0, 5, 3);
mainLayout->addWidget(d->addSubjectButton, 2, 3, 1, 1);
mainLayout->addWidget(d->delSubjectButton, 3, 3, 1, 1);
mainLayout->addWidget(d->repSubjectButton, 4, 3, 1, 1);
mainLayout->addWidget(m_note, 5, 3, 1, 1);
mainLayout->setRowStretch(6, 10);
mainLayout->setColumnStretch(2, 1);
mainLayout->setMargin(0);
mainLayout->setSpacing(KDialog::spacingHint());
setLayout(mainLayout);
// --------------------------------------------------------
connect(d->subjectsBox, SIGNAL(itemSelectionChanged()),
this, SLOT(slotSubjectSelectionChanged()));
connect(d->addSubjectButton, SIGNAL(clicked()),
this, SLOT(slotAddSubject()));
connect(d->delSubjectButton, SIGNAL(clicked()),
this, SLOT(slotDelSubject()));
connect(d->repSubjectButton, SIGNAL(clicked()),
this, SLOT(slotRepSubject()));
connect(d->btnGroup, SIGNAL(buttonReleased(int)),
this, SLOT(slotEditOptionChanged(int)));
connect(d->refCB, SIGNAL(activated(int)),
this, SLOT(slotRefChanged()));
// --------------------------------------------------------
connect(m_subjectsCheck, SIGNAL(toggled(bool)),
this, SLOT(slotSubjectsToggled(bool)));
// --------------------------------------------------------
connect(m_subjectsCheck, SIGNAL(toggled(bool)),
this, SIGNAL(signalModified()));
connect(d->addSubjectButton, SIGNAL(clicked()),
this, SIGNAL(signalModified()));
connect(d->delSubjectButton, SIGNAL(clicked()),
this, SIGNAL(signalModified()));
connect(d->repSubjectButton, SIGNAL(clicked()),
this, SIGNAL(signalModified()));
// --------------------------------------------------------
slotEditOptionChanged(d->btnGroup->id(d->btnGroup->checkedButton()));
}
SubjectWidget::~SubjectWidget()
{
delete d;
}
void SubjectWidget::slotSubjectsToggled(bool b)
{
d->optionsBox->setEnabled(b);
d->subjectsBox->setEnabled(b);
d->addSubjectButton->setEnabled(b);
d->delSubjectButton->setEnabled(b);
d->repSubjectButton->setEnabled(b);
slotEditOptionChanged(d->btnGroup->id(d->btnGroup->checkedButton()));
}
void SubjectWidget::slotEditOptionChanged(int b)
{
if (b == Private::CUSTOM)
{
d->refCB->setEnabled(false);
m_iprEdit->setEnabled(true);
m_refEdit->setEnabled(true);
m_nameEdit->setEnabled(true);
m_matterEdit->setEnabled(true);
m_detailEdit->setEnabled(true);
}
else
{
d->refCB->setEnabled(true);
m_iprEdit->setEnabled(false);
m_refEdit->setEnabled(false);
m_nameEdit->setEnabled(false);
m_matterEdit->setEnabled(false);
m_detailEdit->setEnabled(false);
slotRefChanged();
}
}
void SubjectWidget::slotRefChanged()
{
QString key = d->refCB->currentText();
QString name, matter, detail;
for (Private::SubjectCodesMap::Iterator it = d->subMap.begin();
it != d->subMap.end(); ++it)
{
if (key == it.key())
{
name = it.value().name;
matter = it.value().matter;
detail = it.value().detail;
}
}
m_refEdit->setText(key);
m_nameEdit->setText(name);
m_matterEdit->setText(matter);
m_detailEdit->setText(detail);
}
QString SubjectWidget::buildSubject() const
{
QString subject = m_iprEdit->text();
subject.append(":");
subject.append(m_refEdit->text());
subject.append(":");
subject.append(m_nameEdit->text());
subject.append(":");
subject.append(m_matterEdit->text());
subject.append(":");
subject.append(m_detailEdit->text());
return subject;
}
void SubjectWidget::slotDelSubject()
{
QListWidgetItem* item = d->subjectsBox->currentItem();
if (!item) return;
d->subjectsBox->takeItem(d->subjectsBox->row(item));
delete item;
}
void SubjectWidget::slotRepSubject()
{
QString newSubject = buildSubject();
if (newSubject.isEmpty()) return;
if (!d->subjectsBox->selectedItems().isEmpty())
{
d->subjectsBox->selectedItems()[0]->setText(newSubject);
m_iprEdit->clear();
m_refEdit->clear();
m_nameEdit->clear();
m_matterEdit->clear();
m_detailEdit->clear();
}
}
void SubjectWidget::slotSubjectSelectionChanged()
{
if (!d->subjectsBox->selectedItems().isEmpty())
{
QString subject = d->subjectsBox->selectedItems()[0]->text();
m_iprEdit->setText(subject.section(':', 0, 0));
m_refEdit->setText(subject.section(':', 1, 1));
m_nameEdit->setText(subject.section(':', 2, 2));
m_matterEdit->setText(subject.section(':', 3, 3));
m_detailEdit->setText(subject.section(':', 4, 4));
d->delSubjectButton->setEnabled(true);
d->repSubjectButton->setEnabled(true);
}
else
{
d->delSubjectButton->setEnabled(false);
d->repSubjectButton->setEnabled(false);
}
}
void SubjectWidget::slotAddSubject()
{
QString newSubject = buildSubject();
if (newSubject.isEmpty()) return;
bool found = false;
for (int i = 0 ; i < d->subjectsBox->count(); i++)
{
QListWidgetItem* item = d->subjectsBox->item(i);
if (newSubject == item->text())
{
found = true;
break;
}
}
if (!found)
{
d->subjectsBox->insertItem(d->subjectsBox->count(), newSubject);
m_iprEdit->clear();
m_refEdit->clear();
m_nameEdit->clear();
m_matterEdit->clear();
m_detailEdit->clear();
}
}
bool SubjectWidget::loadSubjectCodesFromXML(const KUrl& url)
{
QFile xmlfile(url.toLocalFile());
if (!xmlfile.open(QIODevice::ReadOnly))
return false;
QDomDocument xmlDoc("NewsML");
if (!xmlDoc.setContent(&xmlfile))
return false;
QDomElement xmlDocElem = xmlDoc.documentElement();
if (xmlDocElem.tagName()!="NewsML")
return false;
for (QDomNode nbE1 = xmlDocElem.firstChild();
!nbE1.isNull(); nbE1 = nbE1.nextSibling())
{
QDomElement newsItemElement = nbE1.toElement();
if (newsItemElement.isNull()) continue;
if (newsItemElement.tagName() != "NewsItem") continue;
for (QDomNode nbE2 = newsItemElement.firstChild();
!nbE2.isNull(); nbE2 = nbE2.nextSibling())
{
QDomElement topicSetElement = nbE2.toElement();
if (topicSetElement.isNull()) continue;
if (topicSetElement.tagName() != "TopicSet") continue;
for (QDomNode nbE3 = topicSetElement.firstChild();
!nbE3.isNull(); nbE3 = nbE3.nextSibling())
{
QDomElement topicElement = nbE3.toElement();
if (topicElement.isNull()) continue;
if (topicElement.tagName() != "Topic") continue;
QString type, name, matter, detail, ref;
for (QDomNode nbE4 = topicElement.firstChild();
!nbE4.isNull(); nbE4 = nbE4.nextSibling())
{
QDomElement topicSubElement = nbE4.toElement();
if (topicSubElement.isNull()) continue;
if (topicSubElement.tagName() == "TopicType")
type = topicSubElement.attribute("FormalName");
if (topicSubElement.tagName() == "FormalName")
ref = topicSubElement.text();
if (topicSubElement.tagName() == "Description" &&
topicSubElement.attribute("Variant") == "Name")
{
if (type == "Subject")
name = topicSubElement.text();
else if (type == "SubjectMatter")
matter = topicSubElement.text();
else if (type == "SubjectDetail")
detail = topicSubElement.text();
}
}
d->subMap.insert(ref, SubjectData(name, matter, detail));
}
}
}
// Set the Subject Name everywhere on the map.
for (Private::SubjectCodesMap::Iterator it = d->subMap.begin();
it != d->subMap.end(); ++it)
{
QString name, keyPrefix;
if (it.key().endsWith(QLatin1String("00000")))
{
keyPrefix = it.key().left(3);
name = it.value().name;
for (Private::SubjectCodesMap::Iterator it2 = d->subMap.begin();
it2 != d->subMap.end(); ++it2)
{
if (it2.key().startsWith(keyPrefix) &&
!it2.key().endsWith(QLatin1String("00000")))
{
it2.value().name = name;
}
}
}
}
// Set the Subject Matter Name everywhere on the map.
for (Private::SubjectCodesMap::Iterator it = d->subMap.begin();
it != d->subMap.end(); ++it)
{
QString matter, keyPrefix;
if (it.key().endsWith(QLatin1String("000")))
{
keyPrefix = it.key().left(5);
matter = it.value().matter;
for (Private::SubjectCodesMap::Iterator it2 = d->subMap.begin();
it2 != d->subMap.end(); ++it2)
{
if (it2.key().startsWith(keyPrefix) &&
!it2.key().endsWith(QLatin1String("000")))
{
it2.value().matter = matter;
}
}
}
}
return true;
}
void SubjectWidget::setSubjectsList(const QStringList& list)
{
d->subjectsList = list;
blockSignals(true);
d->subjectsBox->clear();
m_subjectsCheck->setChecked(false);
if (!d->subjectsList.isEmpty())
{
d->subjectsBox->insertItems(0, d->subjectsList);
m_subjectsCheck->setChecked(true);
}
blockSignals(false);
slotSubjectsToggled(m_subjectsCheck->isChecked());
}
QStringList SubjectWidget::subjectsList() const
{
QStringList newSubjects;
for (int i = 0 ; i < d->subjectsBox->count(); i++)
{
QListWidgetItem* item = d->subjectsBox->item(i);
newSubjects.append(item->text());
}
return newSubjects;
}
} // namespace KExiv2Iface