mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-23 18:32:53 +00:00
381 lines
11 KiB
C++
381 lines
11 KiB
C++
/*
|
|
Gwenview: an image viewer
|
|
Copyright 2007 Aurélien Gâteau <agateau@kde.org>
|
|
|
|
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
|
|
of the License, 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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
#include "moc_infocontextmanageritem.cpp"
|
|
|
|
// Qt
|
|
#include <QApplication>
|
|
#include <QGridLayout>
|
|
#include <QtGui/qevent.h>
|
|
#include <QLabel>
|
|
#include <QPainter>
|
|
#include <QPointer>
|
|
#include <QPushButton>
|
|
#include <QScrollArea>
|
|
#include <QTextBrowser>
|
|
#include <QToolTip>
|
|
#include <QVBoxLayout>
|
|
|
|
// KDE
|
|
#include <KFileItem>
|
|
#include <KLocale>
|
|
#include <KSqueezedTextLabel>
|
|
|
|
// Local
|
|
#include "imagemetainfodialog.h"
|
|
#include "sidebar.h"
|
|
#include <lib/contextmanager.h>
|
|
#include <lib/eventwatcher.h>
|
|
#include <lib/gvdebug.h>
|
|
#include <lib/gwenviewconfig.h>
|
|
#include <lib/preferredimagemetainfomodel.h>
|
|
#include <lib/document/document.h>
|
|
#include <lib/document/documentfactory.h>
|
|
|
|
namespace Gwenview
|
|
{
|
|
|
|
/**
|
|
* This widget is capable of showing multiple lines of key/value pairs.
|
|
*/
|
|
class KeyValueWidget : public QWidget
|
|
{
|
|
struct Row
|
|
{
|
|
Row(QWidget* parent)
|
|
: keyLabel(new QLabel(parent))
|
|
, valueLabel(new QLabel(parent))
|
|
{
|
|
initLabel(keyLabel);
|
|
initLabel(valueLabel);
|
|
|
|
QPalette pal = keyLabel->palette();
|
|
QColor color = pal.color(QPalette::WindowText);
|
|
color.setAlphaF(0.65);
|
|
pal.setColor(QPalette::WindowText, color);
|
|
keyLabel->setPalette(pal);
|
|
|
|
valueLabel->setContentsMargins(6, 0, 0, 6);
|
|
}
|
|
|
|
~Row()
|
|
{
|
|
delete keyLabel;
|
|
delete valueLabel;
|
|
}
|
|
|
|
int setLabelGeometries(int rowY, int labelWidth)
|
|
{
|
|
int labelHeight = keyLabel->heightForWidth(labelWidth);
|
|
keyLabel->setGeometry(0, rowY, labelWidth, labelHeight);
|
|
rowY += labelHeight;
|
|
labelHeight = valueLabel->heightForWidth(labelWidth);
|
|
valueLabel->setGeometry(0, rowY, labelWidth, labelHeight);
|
|
rowY += labelHeight;
|
|
return rowY;
|
|
}
|
|
|
|
int heightForWidth(int width) const
|
|
{
|
|
return keyLabel->heightForWidth(width) + valueLabel->heightForWidth(width);
|
|
}
|
|
|
|
static void initLabel(QLabel* label)
|
|
{
|
|
label->setWordWrap(true);
|
|
label->show();
|
|
label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
|
|
}
|
|
|
|
QLabel* keyLabel;
|
|
QLabel* valueLabel;
|
|
};
|
|
public:
|
|
KeyValueWidget(QWidget* parent = 0)
|
|
: QWidget(parent)
|
|
{
|
|
QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
policy.setHeightForWidth(true);
|
|
setSizePolicy(policy);
|
|
}
|
|
|
|
QSize sizeHint() const
|
|
{
|
|
int width = 150;
|
|
int height = heightForWidth(width);
|
|
return QSize(width, height);
|
|
}
|
|
|
|
int heightForWidth(int w) const
|
|
{
|
|
int height = 0;
|
|
Q_FOREACH(Row* row, mRows) {
|
|
height += row->heightForWidth(w);
|
|
}
|
|
return height;
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
qDeleteAll(mRows);
|
|
mRows.clear();
|
|
updateGeometry();
|
|
}
|
|
|
|
void addRow(const QString& key, const QString& value)
|
|
{
|
|
Row* row = new Row(this);
|
|
row->keyLabel->setText(i18nc(
|
|
"@item:intext %1 is a key, we append a colon to it. A value is displayed after",
|
|
"%1:", key));
|
|
row->valueLabel->setText(value);
|
|
mRows << row;
|
|
}
|
|
|
|
static bool rowsLessThan(const Row* row1, const Row* row2)
|
|
{
|
|
return row1->keyLabel->text() < row2->keyLabel->text();
|
|
}
|
|
|
|
void finishAddRows()
|
|
{
|
|
qSort(mRows.begin(), mRows.end(), KeyValueWidget::rowsLessThan);
|
|
updateGeometry();
|
|
}
|
|
|
|
void layoutRows()
|
|
{
|
|
// Layout labels manually: I tried to use a QVBoxLayout but for some
|
|
// reason when using software animations the widget blinks when going
|
|
// from one image to another
|
|
int rowY = 0;
|
|
const int labelWidth = width();
|
|
Q_FOREACH(Row* row, mRows) {
|
|
rowY = row->setLabelGeometries(rowY, labelWidth);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
void showEvent(QShowEvent* event)
|
|
{
|
|
QWidget::showEvent(event);
|
|
layoutRows();
|
|
}
|
|
|
|
void resizeEvent(QResizeEvent* event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
layoutRows();
|
|
}
|
|
|
|
private:
|
|
QVector<Row*> mRows;
|
|
};
|
|
|
|
struct InfoContextManagerItemPrivate
|
|
{
|
|
InfoContextManagerItem* q;
|
|
SideBarGroup* mGroup;
|
|
|
|
// One selection fields
|
|
QScrollArea* mOneFileWidget;
|
|
KeyValueWidget* mKeyValueWidget;
|
|
Document::Ptr mDocument;
|
|
|
|
// Multiple selection fields
|
|
QLabel* mMultipleFilesLabel;
|
|
|
|
QPointer<ImageMetaInfoDialog> mImageMetaInfoDialog;
|
|
|
|
void updateMetaInfoDialog()
|
|
{
|
|
if (!mImageMetaInfoDialog) {
|
|
return;
|
|
}
|
|
ImageMetaInfoModel* model = mDocument ? mDocument->metaInfo() : 0;
|
|
mImageMetaInfoDialog->setMetaInfo(model, GwenviewConfig::preferredMetaInfoKeyList());
|
|
}
|
|
|
|
void setupGroup()
|
|
{
|
|
mOneFileWidget = new QScrollArea();
|
|
mOneFileWidget->setFrameStyle(QFrame::NoFrame);
|
|
mOneFileWidget->setWidgetResizable(true);
|
|
|
|
mKeyValueWidget = new KeyValueWidget;
|
|
|
|
QLabel* moreLabel = new QLabel(mOneFileWidget);
|
|
moreLabel->setText(QString("<a href='#'>%1</a>").arg(i18nc("@action show more image meta info", "More...")));
|
|
moreLabel->setAlignment(Qt::AlignRight);
|
|
|
|
QWidget* content = new QWidget;
|
|
QVBoxLayout* layout = new QVBoxLayout(content);
|
|
layout->setMargin(2);
|
|
layout->setSpacing(2);
|
|
layout->addWidget(mKeyValueWidget);
|
|
layout->addWidget(moreLabel);
|
|
|
|
mOneFileWidget->setWidget(content);
|
|
|
|
mMultipleFilesLabel = new QLabel();
|
|
|
|
mGroup = new SideBarGroup(i18nc("@title:group", "Meta Information"));
|
|
q->setWidget(mGroup);
|
|
mGroup->addWidget(mOneFileWidget);
|
|
mGroup->addWidget(mMultipleFilesLabel);
|
|
|
|
EventWatcher::install(mGroup, QEvent::Show, q, SLOT(updateSideBarContent()));
|
|
|
|
QObject::connect(moreLabel, SIGNAL(linkActivated(QString)),
|
|
q, SLOT(showMetaInfoDialog()));
|
|
}
|
|
|
|
void forgetCurrentDocument()
|
|
{
|
|
if (mDocument) {
|
|
QObject::disconnect(mDocument.data(), 0, q, 0);
|
|
// "Garbage collect" document
|
|
mDocument = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
InfoContextManagerItem::InfoContextManagerItem(ContextManager* manager)
|
|
: AbstractContextManagerItem(manager)
|
|
, d(new InfoContextManagerItemPrivate)
|
|
{
|
|
d->q = this;
|
|
d->setupGroup();
|
|
connect(contextManager(), SIGNAL(selectionChanged()),
|
|
SLOT(updateSideBarContent()));
|
|
connect(contextManager(), SIGNAL(selectionDataChanged()),
|
|
SLOT(updateSideBarContent()));
|
|
}
|
|
|
|
InfoContextManagerItem::~InfoContextManagerItem()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void InfoContextManagerItem::updateSideBarContent()
|
|
{
|
|
kDebug() << "updateSideBarContent";
|
|
if (!d->mGroup->isVisible()) {
|
|
kDebug() << "updateSideBarContent: not visible, not updating";
|
|
return;
|
|
}
|
|
kDebug() << "updateSideBarContent: really updating";
|
|
|
|
KFileItemList itemList = contextManager()->selectedFileItemList();
|
|
if (itemList.count() == 0) {
|
|
d->forgetCurrentDocument();
|
|
d->mOneFileWidget->hide();
|
|
d->mMultipleFilesLabel->hide();
|
|
d->updateMetaInfoDialog();
|
|
return;
|
|
}
|
|
|
|
KFileItem item = itemList.first();
|
|
if (itemList.count() == 1 && !item.isDir()) {
|
|
fillOneFileGroup(item);
|
|
} else {
|
|
fillMultipleItemsGroup(itemList);
|
|
}
|
|
d->updateMetaInfoDialog();
|
|
}
|
|
|
|
void InfoContextManagerItem::fillOneFileGroup(const KFileItem& item)
|
|
{
|
|
d->mOneFileWidget->show();
|
|
d->mMultipleFilesLabel->hide();
|
|
|
|
d->forgetCurrentDocument();
|
|
d->mDocument = DocumentFactory::instance()->load(item.url());
|
|
connect(d->mDocument.data(), SIGNAL(metaInfoUpdated()),
|
|
SLOT(updateOneFileInfo()));
|
|
|
|
d->updateMetaInfoDialog();
|
|
updateOneFileInfo();
|
|
}
|
|
|
|
void InfoContextManagerItem::fillMultipleItemsGroup(const KFileItemList& itemList)
|
|
{
|
|
d->forgetCurrentDocument();
|
|
|
|
int folderCount = 0, fileCount = 0;
|
|
Q_FOREACH(const KFileItem & item, itemList) {
|
|
if (item.isDir()) {
|
|
folderCount++;
|
|
} else {
|
|
fileCount++;
|
|
}
|
|
}
|
|
|
|
if (folderCount == 0) {
|
|
d->mMultipleFilesLabel->setText(i18ncp("@label", "%1 file selected", "%1 files selected", fileCount));
|
|
} else if (fileCount == 0) {
|
|
d->mMultipleFilesLabel->setText(i18ncp("@label", "%1 folder selected", "%1 folders selected", folderCount));
|
|
} else {
|
|
d->mMultipleFilesLabel->setText(i18nc("@label. The two parameters are strings like '2 folders' and '1 file'.",
|
|
"%1 and %2 selected", i18np("%1 folder", "%1 folders", folderCount), i18np("%1 file", "%1 files", fileCount)));
|
|
}
|
|
d->mOneFileWidget->hide();
|
|
d->mMultipleFilesLabel->show();
|
|
}
|
|
|
|
void InfoContextManagerItem::updateOneFileInfo()
|
|
{
|
|
if (!d->mDocument) {
|
|
return;
|
|
}
|
|
|
|
ImageMetaInfoModel* metaInfoModel = d->mDocument->metaInfo();
|
|
d->mKeyValueWidget->clear();
|
|
Q_FOREACH(const QString & key, GwenviewConfig::preferredMetaInfoKeyList()) {
|
|
QString label;
|
|
QString value;
|
|
metaInfoModel->getInfoForKey(key, &label, &value);
|
|
if (!label.isEmpty() && !value.isEmpty()) {
|
|
d->mKeyValueWidget->addRow(label, value);
|
|
}
|
|
}
|
|
d->mKeyValueWidget->finishAddRows();
|
|
d->mKeyValueWidget->layoutRows();
|
|
}
|
|
|
|
void InfoContextManagerItem::showMetaInfoDialog()
|
|
{
|
|
if (!d->mImageMetaInfoDialog) {
|
|
d->mImageMetaInfoDialog = new ImageMetaInfoDialog(d->mOneFileWidget);
|
|
d->mImageMetaInfoDialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
connect(d->mImageMetaInfoDialog, SIGNAL(preferredMetaInfoKeyListChanged(QStringList)),
|
|
SLOT(slotPreferredMetaInfoKeyListChanged(QStringList)));
|
|
}
|
|
d->mImageMetaInfoDialog->setMetaInfo(d->mDocument ? d->mDocument->metaInfo() : 0, GwenviewConfig::preferredMetaInfoKeyList());
|
|
d->mImageMetaInfoDialog->show();
|
|
}
|
|
|
|
void InfoContextManagerItem::slotPreferredMetaInfoKeyListChanged(const QStringList& list)
|
|
{
|
|
GwenviewConfig::setPreferredMetaInfoKeyList(list);
|
|
GwenviewConfig::self()->writeConfig();
|
|
updateOneFileInfo();
|
|
}
|
|
|
|
} // namespace
|