diff --git a/src/filemetadatawidget.cpp b/src/filemetadatawidget.cpp index 6cc8fb0..8df7d56 100644 --- a/src/filemetadatawidget.cpp +++ b/src/filemetadatawidget.cpp @@ -1,316 +1,401 @@ /* Copyright (C) 2012-2013 Vishesh Handa Adapted from KFileMetadataWidget Copyright (C) 2008 by Sebastian Trueg Copyright (C) 2009-2010 by Peter Penz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "filemetadatawidget.h" #include "metadatafilter.h" #include "widgetfactory.h" #include "filemetadataprovider.h" +#include +#include + #include #include +#include #include #include #include #include #include #include #include #include #include using namespace Baloo; class Baloo::FileMetaDataWidget::Private { public: struct Row { + QCheckBox* checkBox; QLabel* label; QWidget* value; }; Private(FileMetaDataWidget* parent); ~Private(); void deleteRows(); void slotLoadingFinished(); void slotLinkActivated(const QString& link); void slotDataChangeStarted(); void slotDataChangeFinished(); QStringList sortedKeys(const QVariantMap& data) const; QLabel* createLabel(const QString &key, const QString& itemLabel, FileMetaDataWidget* parent); + void saveConfig(); + QList m_rows; FileMetaDataProvider* m_provider; QGridLayout* m_gridLayout; MetadataFilter* m_filter; WidgetFactory* m_widgetFactory; + QMap m_visibilityChanged; + bool m_configureVisibleProperties = false; + private: FileMetaDataWidget* const q; }; FileMetaDataWidget::Private::Private(FileMetaDataWidget* parent) : m_rows() , m_provider(nullptr) , m_gridLayout(nullptr) , q(parent) { m_filter = new MetadataFilter(q); m_widgetFactory = new WidgetFactory(q); connect(m_widgetFactory, &WidgetFactory::urlActivated, q, &FileMetaDataWidget::urlActivated); // TODO: If KFileMetaDataProvider might get a public class in future KDE releases, // the following code should be moved into KFileMetaDataWidget::setModel(): m_provider = new FileMetaDataProvider(q); connect(m_provider, SIGNAL(loadingFinished()), q, SLOT(slotLoadingFinished())); } FileMetaDataWidget::Private::~Private() { } void FileMetaDataWidget::Private::deleteRows() { foreach (const Row& row, m_rows) { delete row.label; row.value->deleteLater(); + if (row.checkBox) { + row.checkBox->deleteLater(); + } } m_rows.clear(); } QLabel* FileMetaDataWidget::Private::createLabel(const QString &key, const QString& itemLabel, FileMetaDataWidget* parent) { QLabel* label = new QLabel(itemLabel + QLatin1Char(':'), parent); label->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); label->setForegroundRole(parent->foregroundRole()); label->setFont(parent->font()); label->setWordWrap(true); label->setAlignment(Qt::AlignTop | Qt::AlignRight); label->setObjectName(QStringLiteral("L_%1").arg(key)); return label; } void FileMetaDataWidget::Private::slotLoadingFinished() { deleteRows(); if (m_gridLayout == nullptr) { m_gridLayout = new QGridLayout(q); m_gridLayout->setContentsMargins(0, 0, 0, 0); m_gridLayout->setSpacing(q->fontMetrics().height() / 4); } - QVariantMap data = m_filter->filter( m_provider->data() ); - m_widgetFactory->setNoLinks( m_provider->realTimeIndexing() ); + QVariantMap data = m_provider->data(); + QStringList active; + if (m_configureVisibleProperties) { + active = m_filter->filter(data).keys(); + auto changedIt = m_visibilityChanged.constBegin(); + while (changedIt != m_visibilityChanged.constEnd()) { + if (changedIt.value()) { + active.append(changedIt.key()); + } else { + active.removeAll(changedIt.key()); + } + changedIt++; + } + m_widgetFactory->setNoLinks(true); + m_widgetFactory->setReadOnly(true); + m_gridLayout->setColumnStretch(0, 1); + m_gridLayout->setColumnStretch(1, 3); + m_gridLayout->setColumnStretch(2, 0); + m_gridLayout->setColumnStretch(3, 6); + } else { + data = m_filter->filter(data); + m_widgetFactory->setNoLinks( m_provider->realTimeIndexing() ); + m_gridLayout->setColumnStretch(0, 4); + m_gridLayout->setColumnStretch(1, 0); + m_gridLayout->setColumnStretch(2, 6); + m_gridLayout->setColumnStretch(3, 0); + } int rowIndex = 0; // Iterate through all remaining items. // Embed the label and the value as new row in the widget const QStringList keys = sortedKeys(data); + const int spacerWidth = QFontMetrics(q->font()).size(Qt::TextSingleLine, " ").width(); + + const int labelColumn = m_configureVisibleProperties ? 1 : 0; + for (const auto key: keys) { Row row; - const int spacerWidth = QFontMetrics(q->font()).size(Qt::TextSingleLine, " ").width(); - m_gridLayout->addItem(new QSpacerItem(spacerWidth, 1), rowIndex, 1); + if (m_configureVisibleProperties) { + row.checkBox = new QCheckBox(q); + if (active.contains(key)) { + row.checkBox->setChecked(true); + } + m_gridLayout->addWidget(row.checkBox, rowIndex, 0, Qt::AlignTop | Qt::AlignRight); + connect(row.checkBox, &QCheckBox::stateChanged, + q, [this, key](int state) { this->m_visibilityChanged[key] = (state == Qt::Checked); }); + } else { + row.checkBox = nullptr; + } row.label = createLabel(key, m_provider->label(key), q); - m_gridLayout->addWidget(row.label, rowIndex, 0, Qt::AlignRight); + m_gridLayout->addWidget(row.label, rowIndex, labelColumn + 0, Qt::AlignRight); + + m_gridLayout->addItem(new QSpacerItem(spacerWidth, 1), rowIndex, labelColumn + 1); row.value = m_widgetFactory->createWidget(key, data[key], q); - m_gridLayout->addWidget(row.value, rowIndex, 2, Qt::AlignLeft); + m_gridLayout->addWidget(row.value, rowIndex, labelColumn + 2, Qt::AlignLeft); // Remember the label and value-widget as row m_rows.append(row); ++rowIndex; } q->updateGeometry(); emit q->metaDataRequestFinished(m_provider->items()); } void FileMetaDataWidget::Private::slotLinkActivated(const QString& link) { const QUrl url = QUrl::fromUserInput(link); if (url.isValid()) { emit q->urlActivated(url); } } void FileMetaDataWidget::Private::slotDataChangeStarted() { q->setEnabled(false); } void FileMetaDataWidget::Private::slotDataChangeFinished() { q->setEnabled(true); } QStringList FileMetaDataWidget::Private::sortedKeys(const QVariantMap& data) const { // Create a map, where the translated label prefixed with the // sort priority acts as key. The data of each entry is the URI // of the data. By this the all URIs are sorted by the sort priority // and sub sorted by the translated labels. QMap map; QVariantMap::const_iterator hashIt = data.constBegin(); while (hashIt != data.constEnd()) { const QString propName = hashIt.key(); QString key = m_provider->group(propName); key += m_provider->label(propName); map.insertMulti(key, propName); ++hashIt; } // Apply the URIs from the map to the list that will get returned. // The list will then be alphabetically ordered by the translated labels of the URIs. QStringList list; QMap::const_iterator mapIt = map.constBegin(); while (mapIt != map.constEnd()) { list.append(mapIt.value()); ++mapIt; } return list; } +void FileMetaDataWidget::Private::saveConfig() +{ + if (m_visibilityChanged.isEmpty()) { + return; + } + + KConfig config("baloofileinformationrc", KConfig::NoGlobals); + KConfigGroup showGroup = config.group("Show"); + + auto changedIt = m_visibilityChanged.constBegin(); + while (changedIt != m_visibilityChanged.constEnd()) { + showGroup.writeEntry(changedIt.key(), changedIt.value()); + changedIt++; + } + + showGroup.sync(); +} + FileMetaDataWidget::FileMetaDataWidget(QWidget* parent) : QWidget(parent) , d(new Private(this)) { } FileMetaDataWidget::~FileMetaDataWidget() { delete d; } void FileMetaDataWidget::setItems(const KFileItemList& items) { KFileItemList localItemsList; QStringList list; bool xAttrSuppored = true; foreach(const KFileItem& item, items) { QUrl url = item.targetUrl(); if (url.isLocalFile()) { localItemsList << item; QString path = url.toLocalFile(); list << path; KFileMetaData::UserMetaData md(path); xAttrSuppored &= md.isSupported(); } } setReadOnly(!xAttrSuppored); d->m_provider->setItems(localItemsList); d->m_widgetFactory->setItems(list); setReadOnly(!xAttrSuppored); } KFileItemList FileMetaDataWidget::items() const { return d->m_provider->items(); } void FileMetaDataWidget::setReadOnly(bool readOnly) { d->m_provider->setReadOnly(readOnly); d->m_widgetFactory->setReadOnly(readOnly); } bool FileMetaDataWidget::isReadOnly() const { return d->m_provider->isReadOnly(); } void FileMetaDataWidget::setDateFormat(const DateFormats format) { d->m_widgetFactory->setDateFormat(format); } DateFormats FileMetaDataWidget::dateFormat() const { return d->m_widgetFactory->dateFormat(); } QSize FileMetaDataWidget::sizeHint() const { if (d->m_gridLayout == nullptr) { return QWidget::sizeHint(); } // Calculate the required width for the labels and values int leftWidthMax = 0; int rightWidthMax = 0; int rightWidthAverage = 0; foreach (const Private::Row& row, d->m_rows) { const QWidget* valueWidget = row.value; const int rightWidth = valueWidget->sizeHint().width(); rightWidthAverage += rightWidth; if (rightWidth > rightWidthMax) { rightWidthMax = rightWidth; } const int leftWidth = row.label->sizeHint().width(); if (leftWidth > leftWidthMax) { leftWidthMax = leftWidth; } } // Some value widgets might return a very huge width for the size hint. // Limit the maximum width to the double width of the overall average // to assure a less messed layout. if (d->m_rows.count() > 1) { rightWidthAverage /= d->m_rows.count(); if (rightWidthMax > rightWidthAverage * 2) { rightWidthMax = rightWidthAverage * 2; } } // Based on the available width calculate the required height int height = d->m_gridLayout->margin() * 2 + d->m_gridLayout->spacing() * (d->m_rows.count() - 1); foreach (const Private::Row& row, d->m_rows) { const QWidget* valueWidget = row.value; const int rowHeight = qMax(row.label->heightForWidth(leftWidthMax), valueWidget->heightForWidth(rightWidthMax)); height += rowHeight; } const int width = d->m_gridLayout->margin() * 2 + leftWidthMax + d->m_gridLayout->spacing() + rightWidthMax; return QSize(width, height); } +void FileMetaDataWidget::setConfigurationMode(ConfigurationMode mode) +{ + if (mode == ConfigurationMode::ReStart) { + d->m_configureVisibleProperties = true; + } else if (mode == ConfigurationMode::Accept) { + d->saveConfig(); + d->m_configureVisibleProperties = false; + } else if (mode == ConfigurationMode::Cancel) { + d->m_configureVisibleProperties = false; + } + d->m_visibilityChanged.clear(); + d->slotLoadingFinished(); +} + #include "moc_filemetadatawidget.cpp" diff --git a/src/filemetadatawidget.h b/src/filemetadatawidget.h index 87ac8a8..20bf3e1 100644 --- a/src/filemetadatawidget.h +++ b/src/filemetadatawidget.h @@ -1,108 +1,124 @@ /* Copyright (C) 2012-2013 Vishesh Handa Adapted from KFileMetadataWidget Copyright (C) 2008 by Sebastian Trueg Copyright (C) 2009-2010 by Peter Penz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _BALOO_FILE_METADATAWIDGET_H #define _BALOO_FILE_METADATAWIDGET_H #include #include #include #include #include "widgets_export.h" namespace Baloo { /** * Modify format of date display */ enum class DateFormats { LongFormat = QLocale::LongFormat, ///< @see QLocale::LongFormat ShortFormat = QLocale::ShortFormat ///< @see QLocale::ShortFormat }; +enum class ConfigurationMode { + ReStart = 0, /**< Switch into configuration mode. The selection is + * initialized with the current configuration. + * In case the widget is in configuration mode already, + * the changes are discarded, and the mode is kept. + */ + Accept, /**< Save any changes, switch to regular mode */ + Cancel /**< Discard any changes, switch to regular mode */ +}; + class BALOO_WIDGETS_EXPORT FileMetaDataWidget : public QWidget { Q_OBJECT Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) Q_PROPERTY(DateFormats dateFormat READ dateFormat WRITE setDateFormat) public: explicit FileMetaDataWidget(QWidget* parent = nullptr); ~FileMetaDataWidget() override; /** * Sets the items for which the meta data should be shown. * The signal metaDataRequestFinished() will be emitted, * as soon as the meta data for the items has been received. */ void setItems(const KFileItemList& items); KFileItemList items() const; /** * If set to true, data such as the comment, tag or rating cannot be * changed by the user. Per default read-only is disabled. */ void setReadOnly(bool readOnly); bool isReadOnly() const; /** * Set date display format. * Per Default format is Long = @see QLocale::LongFormat */ void setDateFormat(const DateFormats format); DateFormats dateFormat() const; /** @see QWidget::sizeHint() */ QSize sizeHint() const override; + /** + * Switch between regular (view) and configuration mode. + * @since 19.08.00 + */ + void setConfigurationMode(ConfigurationMode mode); + Q_SIGNALS: /** * Is emitted, if a meta data represents an URL that has * been clicked by the user. */ void urlActivated(const QUrl& url); /** * Is emitted after the meta data has been received for the items * set by KFileMetaDataWidget::setItems(). * @since 4.6 */ void metaDataRequestFinished(const KFileItemList& items); private: class Private; Private* d; Q_PRIVATE_SLOT(d, void slotLoadingFinished()) Q_PRIVATE_SLOT(d, void slotLinkActivated(QString)) Q_PRIVATE_SLOT(d, void slotDataChangeStarted()) Q_PRIVATE_SLOT(d, void slotDataChangeFinished()) }; } Q_DECLARE_METATYPE(Baloo::DateFormats) #endif // _BALOO_FILE_METADATAWIDGET_H