#include <kdialog.h>
#include <kdirnotify.h>
-#include <kfileplacesmodel.h>
-#include <klocale.h>
-#include <kstandarddirs.h>
-#include <kio/previewjob.h>
#include <kfileitem.h>
-#include <kglobalsettings.h>
#include <kfilemetainfo.h>
+#include <kfileplacesmodel.h>
+#include <kglobalsettings.h>
+#include <kio/previewjob.h>
#include <kiconeffect.h>
-#include <kseparator.h>
#include <kiconloader.h>
+#include <klocale.h>
+#include <kmenu.h>
+#include <kseparator.h>
+
+#ifdef HAVE_NEPOMUK
+#include <Nepomuk/Resource>
+#include <Nepomuk/Types/Property>
+#include <Nepomuk/Variant>
+#endif
#include <Phonon/BackendCapabilities>
#include <Phonon/MediaObject>
#include <QPainter>
#include <QPixmap>
#include <QResizeEvent>
+#include <QScrollArea>
#include <QTextLayout>
#include <QTextLine>
#include <QTimer>
+#include <QScrollBar>
#include <QVBoxLayout>
+#include "dolphin_informationpanelsettings.h"
#include "settings/dolphinsettings.h"
#include "metadatawidget.h"
#include "metatextlabel.h"
#include "phononwidget.h"
#include "pixmapviewer.h"
+/**
+ * Helper function for sorting items with qSort() in
+ * InformationPanel::contextMenu().
+ */
+bool lessThan(const QAction* action1, const QAction* action2)
+{
+ return action1->text() < action2->text();
+}
+
+
InformationPanel::InformationPanel(QWidget* parent) :
Panel(parent),
m_initialized(false),
m_selection(),
m_nameLabel(0),
m_preview(0),
+ m_previewSeparator(0),
m_phononWidget(0),
m_metaDataWidget(0),
+ m_metaDataSeparator(0),
+ m_metaTextArea(0),
m_metaTextLabel(0)
{
}
InformationPanel::~InformationPanel()
{
+ InformationPanelSettings::self()->writeConfig();
}
QSize InformationPanel::sizeHint() const
const int maxWidth = event->size().width() - KDialog::spacingHint() * 4;
m_nameLabel->setMaximumWidth(maxWidth);
+ // The metadata widget also contains a text widget which may return
+ // a large preferred width.
+ if (m_metaDataWidget != 0) {
+ m_metaDataWidget->setMaximumWidth(maxWidth);
+ }
+
// try to increase the preview as large as possible
m_preview->setSizeHint(QSize(maxWidth, maxWidth));
m_urlCandidate = m_shownUrl; // reset the URL candidate if a resizing is done
m_infoTimer->start();
- }
+ if (m_phononWidget->isVisible() && (m_phononWidget->mode() == PhononWidget::Video)) {
+ // assure that the size of the video player is the same as the preview size
+ m_phononWidget->setVideoSize(QSize(maxWidth, maxWidth));
+ }
+ }
Panel::resizeEvent(event);
}
+bool InformationPanel::eventFilter(QObject* obj, QEvent* event)
+{
+ // Check whether the size of the meta text area has changed and adjust
+ // the fixed width in a way that no horizontal scrollbar needs to be shown.
+ if ((obj == m_metaTextArea->viewport()) && (event->type() == QEvent::Resize)) {
+ QResizeEvent* resizeEvent = static_cast<QResizeEvent*>(event);
+ m_metaTextLabel->setFixedWidth(resizeEvent->size().width());
+ }
+ return Panel::eventFilter(obj, event);
+}
+
+void InformationPanel::contextMenuEvent(QContextMenuEvent* event)
+{
+ Panel::contextMenuEvent(event);
+
+#ifdef HAVE_NEPOMUK
+ if (showMultipleSelectionInfo()) {
+ return;
+ }
+
+ KMenu popup(this);
+
+ QAction* previewAction = popup.addAction(i18nc("@action:inmenu", "Preview"));
+ previewAction->setIcon(KIcon("view-preview"));
+ previewAction->setCheckable(true);
+ previewAction->setChecked(InformationPanelSettings::showPreview());
+
+ const bool metaDataAvailable = MetaDataWidget::metaDataAvailable();
+
+ QAction* ratingAction = popup.addAction(i18nc("@action:inmenu", "Rating"));
+ ratingAction->setIcon(KIcon("rating"));
+ ratingAction->setCheckable(true);
+ ratingAction->setChecked(InformationPanelSettings::showRating());
+ ratingAction->setEnabled(metaDataAvailable);
+
+ QAction* commentAction = popup.addAction(i18nc("@action:inmenu", "Comment"));
+ commentAction->setIcon(KIcon("text-plain"));
+ commentAction->setCheckable(true);
+ commentAction->setChecked(InformationPanelSettings::showComment());
+ commentAction->setEnabled(metaDataAvailable);
+
+ QAction* tagsAction = popup.addAction(i18nc("@action:inmenu", "Tags"));
+ tagsAction->setCheckable(true);
+ tagsAction->setChecked(InformationPanelSettings::showTags());
+ tagsAction->setEnabled(metaDataAvailable);
+
+ KConfig config("kmetainformationrc", KConfig::NoGlobals);
+ KConfigGroup settings = config.group("Show");
+ initMetaInfoSettings(settings);
+
+ QList<QAction*> actions;
+
+ // Get all meta information labels that are available for
+ // the currently shown file item and add them to the popup.
+ Nepomuk::Resource res(fileItem().url());
+ QHash<QUrl, Nepomuk::Variant> properties = res.properties();
+ QHash<QUrl, Nepomuk::Variant>::const_iterator it = properties.constBegin();
+ while (it != properties.constEnd()) {
+ Nepomuk::Types::Property prop(it.key());
+ const QString key = prop.label();
+
+ // Meta information provided by Nepomuk that is already
+ // available from KFileItem should not be configurable.
+ bool skip = (key == "fileExtension") ||
+ (key == "name") ||
+ (key == "sourceModified") ||
+ (key == "size") ||
+ (key == "mime type");
+ if (!skip) {
+ // Check whether there is already a meta information
+ // having the same label. In this case don't show it
+ // twice in the menu.
+ foreach (const QAction* action, actions) {
+ if (action->data().toString() == key) {
+ skip = true;
+ break;
+ }
+ }
+ }
+
+ if (!skip) {
+ const QString label = tunedLabel(key); // TODO
+ QAction* action = new QAction(label, &popup);
+ action->setCheckable(true);
+ action->setChecked(settings.readEntry(key, true));
+ action->setData(key);
+ actions.append(action);
+ }
+
+ ++it;
+ }
+
+ if (actions.count() > 0) {
+ popup.addSeparator();
+
+ // add all items alphabetically sorted to the popup
+ qSort(actions.begin(), actions.end(), lessThan);
+ foreach (QAction* action, actions) {
+ popup.addAction(action);
+ }
+ }
+
+ // Open the popup and adjust the settings for the
+ // selected action.
+ QAction* action = popup.exec(QCursor::pos());
+ if (action == 0) {
+ return;
+ }
+
+ const bool isChecked = action->isChecked();
+ if (action == previewAction) {
+ m_preview->setVisible(isChecked);
+ m_previewSeparator->setVisible(isChecked);
+ InformationPanelSettings::setShowPreview(isChecked);
+ updatePhononWidget();
+ } else if (action == ratingAction) {
+ m_metaDataWidget->setRatingVisible(isChecked);
+ InformationPanelSettings::setShowRating(isChecked);
+ } else if (action == commentAction) {
+ m_metaDataWidget->setCommentVisible(isChecked);
+ InformationPanelSettings::setShowComment(isChecked);
+ } else if (action == tagsAction) {
+ m_metaDataWidget->setTagsVisible(isChecked);
+ InformationPanelSettings::setShowTags(isChecked);
+ } else {
+ settings.writeEntry(action->data().toString(), action->isChecked());
+ settings.sync();
+ showMetaInfo();
+ }
+
+ if (m_metaDataWidget != 0) {
+ const bool visible = m_metaDataWidget->isRatingVisible() ||
+ m_metaDataWidget->isCommentVisible() ||
+ m_metaDataWidget->areTagsVisible();
+ m_metaDataSeparator->setVisible(visible);
+ }
+#endif
+}
+
void InformationPanel::showItemInfo()
{
if (!isVisible()) {
void InformationPanel::slotFileRenamed(const QString& source, const QString& dest)
{
if (m_shownUrl == KUrl(source)) {
- // the currently shown file has been renamed, hence update the item information
- // for the renamed file
- KFileItem item(KFileItem::Unknown, KFileItem::Unknown, KUrl(dest));
- requestDelayedItemInfo(item);
+ m_shownUrl = KUrl(dest);
+ m_fileItem = KFileItem(KFileItem::Unknown, KFileItem::Unknown, m_shownUrl);
+ showItemInfo();
}
}
if (m_shownUrl == KUrl(fileName)) {
// the currently shown item has been removed, show
// the parent directory as fallback
- m_shownUrl = url();
- showItemInfo();
+ reset();
break;
}
}
// has been unmounted. In this case no directory change will be
// done in Dolphin, but the Information Panel must be updated to
// indicate an invalid directory.
- m_shownUrl = url();
- showItemInfo();
+ reset();
}
}
+void InformationPanel::slotPlayingStarted()
+{
+ m_preview->setVisible(m_phononWidget->mode() != PhononWidget::Video);
+}
+
+void InformationPanel::slotPlayingStopped()
+{
+ m_preview->setVisible(true);
+}
+
bool InformationPanel::applyPlace(const KUrl& url)
{
KFilePlacesModel* placesModel = DolphinSettings::instance().placesModel();
m_metaTextLabel->add(i18nc("@label", "Size:"), KIO::convertSize(item.size()));
m_metaTextLabel->add(i18nc("@label", "Modified:"), item.timeString());
- if (item.isLocalFile()) {
- // TODO: See convertMetaInfo below, find a way to display only interesting information
- // in a readable way
- const KFileMetaInfo::WhatFlags flags = KFileMetaInfo::Fastest |
- KFileMetaInfo::TechnicalInfo |
- KFileMetaInfo::ContentInfo;
- const QString path = item.url().path();
- const KFileMetaInfo fileMetaInfo(path, QString(), flags);
- if (fileMetaInfo.isValid()) {
- const QHash<QString, KFileMetaInfoItem>& items = fileMetaInfo.items();
- QHash<QString, KFileMetaInfoItem>::const_iterator it = items.constBegin();
- const QHash<QString, KFileMetaInfoItem>::const_iterator end = items.constEnd();
- QString labelText;
- while (it != end) {
- const KFileMetaInfoItem& metaInfoItem = it.value();
- const QVariant& value = metaInfoItem.value();
- if (value.isValid() && convertMetaInfo(metaInfoItem.name(), labelText)) {
- m_metaTextLabel->add(labelText, value.toString());
- }
- ++it;
- }
+#ifdef HAVE_NEPOMUK
+ KConfig config("kmetainformationrc", KConfig::NoGlobals);
+ KConfigGroup settings = config.group("Show");
+ initMetaInfoSettings(settings);
+
+ Nepomuk::Resource res(item.url());
+
+ QHash<QUrl, Nepomuk::Variant> properties = res.properties();
+ QHash<QUrl, Nepomuk::Variant>::const_iterator it = properties.constBegin();
+ while (it != properties.constEnd()) {
+ Nepomuk::Types::Property prop(it.key());
+ const QString label = prop.label();
+ if (settings.readEntry(label, true)) {
+ // TODO #1: use Nepomuk::formatValue(res, prop) if available
+ // instead of it.value().toString()
+ // TODO #2: using tunedLabel() is a workaround for KDE 4.3 until
+ // we get translated labels
+ m_metaTextLabel->add(tunedLabel(label) + ':', it.value().toString());
}
+ ++it;
}
+#endif
}
if (m_metaDataWidget != 0) {
m_metaDataWidget->setFile(item.targetUrl());
}
-
- if (Phonon::BackendCapabilities::isMimeTypeAvailable(item.mimetype())) {
- if (m_phononWidget == 0) {
- m_phononWidget = new PhononWidget(this);
-
- QVBoxLayout* vBoxLayout = qobject_cast<QVBoxLayout*>(layout());
- Q_ASSERT(vBoxLayout != 0);
- vBoxLayout->insertWidget(3, m_phononWidget);
- }
- m_phononWidget->setUrl(item.url());
- } else {
- delete m_phononWidget;
- m_phononWidget = 0;
- }
}
-}
-bool InformationPanel::convertMetaInfo(const QString& key, QString& text) const
-{
- struct MetaKey {
- const char* key;
- QString text;
- };
-
- // sorted list of keys, where its data should be shown
- static const MetaKey keys[] = {
- { "http://freedesktop.org/standards/xesam/1.0/core#album", i18nc("@label", "Album:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#artist", i18nc("@label", "Artist:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#genre", i18nc("@label", "Genre:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#height", i18nc("@label", "Height:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#lineCount", i18nc("@label", "Lines:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#title", i18nc("@label", "Title:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#type", i18nc("@label", "Type:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#trackNumber", i18nc("@label", "Track:") },
- { "http://freedesktop.org/standards/xesam/1.0/core#width", i18nc("@label", "Width:") }
- };
-
- // do a binary search for the key...
- int top = 0;
- int bottom = sizeof(keys) / sizeof(MetaKey) - 1;
- while (top <= bottom) {
- const int middle = (top + bottom) / 2;
- const int result = key.compare(keys[middle].key);
- if (result < 0) {
- bottom = middle - 1;
- } else if (result > 0) {
- top = middle + 1;
- } else {
- text = keys[middle].text;
- return true;
- }
- }
-
- return false;
+ updatePhononWidget();
}
KFileItem InformationPanel::fileItem() const
m_nameLabel->setText(wrappedText);
}
-void InformationPanel::init()
+void InformationPanel::reset()
+{
+ m_selection.clear();
+ m_shownUrl = url();
+ m_fileItem = KFileItem();
+ showItemInfo();
+}
+
+void InformationPanel::initMetaInfoSettings(KConfigGroup& group)
+{
+ if (!group.readEntry("initialized", false)) {
+ // The resource file is read the first time. Assure
+ // that some meta information is disabled per default.
+
+ static const char* disabledProperties[] = {
+ "asText", "contentSize", "depth", "fileExtension",
+ "fileName", "fileSize", "isPartOf", "mimetype", "name",
+ "parentUrl", "plainTextContent", "sourceModified",
+ "size", "url",
+ 0 // mandatory last entry
+ };
+
+ int i = 0;
+ while (disabledProperties[i] != 0) {
+ group.writeEntry(disabledProperties[i], false);
+ ++i;
+ }
+
+ // mark the group as initialized
+ group.writeEntry("initialized", true);
+ }
+}
+
+void InformationPanel::updatePhononWidget()
{
- const int spacing = KDialog::spacingHint();
+ const bool multipleSelections = showMultipleSelectionInfo();
+ const bool showPreview = InformationPanelSettings::showPreview();
+
+ if (multipleSelections || !showPreview) {
+ m_phononWidget->hide();
+ } else if (!multipleSelections && showPreview) {
+ const KFileItem item = fileItem();
+ const QString mimeType = item.mimetype();
+ const bool usePhonon = Phonon::BackendCapabilities::isMimeTypeAvailable(mimeType) &&
+ (mimeType != "image/png"); // TODO: workaround, as Phonon
+ // thinks it supports PNG images
+ if (usePhonon) {
+ m_phononWidget->show();
+ PhononWidget::Mode mode = mimeType.startsWith(QLatin1String("video"))
+ ? PhononWidget::Video
+ : PhononWidget::Audio;
+ m_phononWidget->setMode(mode);
+ m_phononWidget->setUrl(item.url());
+ if ((mode == PhononWidget::Video) && m_preview->isVisible()) {
+ m_phononWidget->setVideoSize(m_preview->size());
+ }
+ } else {
+ m_phononWidget->hide();
+ m_preview->setVisible(true);
+ }
+ }
+}
+
+QString InformationPanel::tunedLabel(const QString& label) const
+{
+ QString tunedLabel;
+ const int labelLength = label.length();
+ if (labelLength > 0) {
+ tunedLabel.reserve(labelLength);
+ tunedLabel = label[0].toUpper();
+ for (int i = 1; i < labelLength; ++i) {
+ if (label[i].isUpper() && !label[i - 1].isSpace() && !label[i - 1].isUpper()) {
+ tunedLabel += ' ';
+ tunedLabel += label[i].toLower();
+ } else {
+ tunedLabel += label[i];
+ }
+ }
+ }
+ return tunedLabel;
+}
+void InformationPanel::init()
+{
m_infoTimer = new QTimer(this);
m_infoTimer->setInterval(300);
m_infoTimer->setSingleShot(true);
this, SLOT(markOutdatedPreview()));
QVBoxLayout* layout = new QVBoxLayout;
- layout->setSpacing(spacing);
+ layout->setSpacing(KDialog::spacingHint());
// name
m_nameLabel = new QLabel(this);
m_nameLabel->setFont(font);
m_nameLabel->setAlignment(Qt::AlignHCenter);
m_nameLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ m_nameLabel->setMaximumWidth(KIconLoader::SizeEnormous);
// preview
+ const int minPreviewWidth = KIconLoader::SizeEnormous + KIconLoader::SizeMedium;
+
m_preview = new PixmapViewer(this);
- m_preview->setMinimumWidth(KIconLoader::SizeEnormous + KIconLoader::SizeMedium);
+ m_preview->setMinimumWidth(minPreviewWidth);
m_preview->setMinimumHeight(KIconLoader::SizeEnormous);
+ m_phononWidget = new PhononWidget(this);
+ m_phononWidget->setMinimumWidth(minPreviewWidth);
+ connect(m_phononWidget, SIGNAL(playingStarted()),
+ this, SLOT(slotPlayingStarted()));
+ connect(m_phononWidget, SIGNAL(playingStopped()),
+ this, SLOT(slotPlayingStopped()));
+
+ m_previewSeparator = new KSeparator(this);
+
+ const bool showPreview = InformationPanelSettings::showPreview();
+ m_preview->setVisible(showPreview);
+ m_previewSeparator->setVisible(showPreview);
+
if (MetaDataWidget::metaDataAvailable()) {
// rating, comment and tags
m_metaDataWidget = new MetaDataWidget(this);
m_metaDataWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ m_metaDataWidget->setMaximumWidth(KIconLoader::SizeEnormous);
+
+ const bool showRating = InformationPanelSettings::showRating();
+ const bool showComment = InformationPanelSettings::showComment();
+ const bool showTags = InformationPanelSettings::showTags();
+
+ m_metaDataWidget->setRatingVisible(showRating);
+ m_metaDataWidget->setCommentVisible(showComment);
+ m_metaDataWidget->setTagsVisible(showTags);
+
+ m_metaDataSeparator = new KSeparator(this);
+ m_metaDataSeparator->setVisible(showRating || showComment || showTags);
}
// general meta text information
m_metaTextLabel = new MetaTextLabel(this);
- m_metaTextLabel->setMinimumWidth(spacing);
m_metaTextLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ m_metaTextArea = new QScrollArea(this);
+ m_metaTextArea->setWidget(m_metaTextLabel);
+ m_metaTextArea->setWidgetResizable(true);
+ m_metaTextArea->setFrameShape(QFrame::NoFrame);
+
+ QWidget* viewport = m_metaTextArea->viewport();
+ viewport->installEventFilter(this);
+
+ QPalette palette = viewport->palette();
+ palette.setColor(viewport->backgroundRole(), QColor(Qt::transparent));
+ viewport->setPalette(palette);
+
layout->addWidget(m_nameLabel);
layout->addWidget(new KSeparator(this));
layout->addWidget(m_preview);
- layout->addWidget(new KSeparator(this));
+ layout->addWidget(m_phononWidget);
+ layout->addWidget(m_previewSeparator);
if (m_metaDataWidget != 0) {
layout->addWidget(m_metaDataWidget);
- layout->addWidget(new KSeparator(this));
+ layout->addWidget(m_metaDataSeparator);
}
- layout->addWidget(m_metaTextLabel);
-
- // ensure that widgets in the information side bar are aligned towards the top
- layout->addStretch(1);
+ layout->addWidget(m_metaTextArea);
setLayout(layout);
org::kde::KDirNotify* dirNotify = new org::kde::KDirNotify(QString(), QString(),