]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/informationpanelcontent.cpp
When the Back, Forward and Up buttons in the toolbar are clicked with
[dolphin.git] / src / panels / information / informationpanelcontent.cpp
1 /***************************************************************************
2 * Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "informationpanelcontent.h"
21
22 #include <config-nepomuk.h>
23
24 #include <kdialog.h>
25 #include <kfileitem.h>
26 #include <kfileplacesmodel.h>
27 #include <kio/previewjob.h>
28 #include <kiconeffect.h>
29 #include <kiconloader.h>
30 #include <klocale.h>
31 #include <kmenu.h>
32 #include <kseparator.h>
33
34 #include <Phonon/BackendCapabilities>
35 #include <Phonon/MediaObject>
36 #include <Phonon/SeekSlider>
37
38 #include <QEvent>
39 #include <QLabel>
40 #include <QPixmap>
41 #include <QPointer>
42 #include <QResizeEvent>
43 #include <QScrollArea>
44 #include <QTextLayout>
45 #include <QTextLine>
46 #include <QTimer>
47 #include <QVBoxLayout>
48
49 #include "dolphin_informationpanelsettings.h"
50 #include "settings/dolphinsettings.h"
51 #include "kmetadatawidget.h"
52 #include "kmetadataconfigurationdialog.h"
53 #include "phononwidget.h"
54 #include "pixmapviewer.h"
55
56 InformationPanelContent::InformationPanelContent(QWidget* parent) :
57 Panel(parent),
58 m_item(),
59 m_pendingPreview(false),
60 m_outdatedPreviewTimer(0),
61 m_preview(0),
62 m_phononWidget(0),
63 m_nameLabel(0),
64 m_metaDataWidget(0),
65 m_metaDataArea(0)
66 {
67 parent->installEventFilter(this);
68
69 // Initialize timer for disabling an outdated preview with a small
70 // delay. This prevents flickering if the new preview can be generated
71 // within a very small timeframe.
72 m_outdatedPreviewTimer = new QTimer(this);
73 m_outdatedPreviewTimer->setInterval(300);
74 m_outdatedPreviewTimer->setSingleShot(true);
75 connect(m_outdatedPreviewTimer, SIGNAL(timeout()),
76 this, SLOT(markOutdatedPreview()));
77
78 QVBoxLayout* layout = new QVBoxLayout;
79 layout->setSpacing(KDialog::spacingHint());
80
81 // preview
82 const int minPreviewWidth = KIconLoader::SizeEnormous + KIconLoader::SizeMedium;
83
84 m_preview = new PixmapViewer(parent);
85 m_preview->setMinimumWidth(minPreviewWidth);
86 m_preview->setMinimumHeight(KIconLoader::SizeEnormous);
87
88 m_phononWidget = new PhononWidget(parent);
89 m_phononWidget->setMinimumWidth(minPreviewWidth);
90 connect(m_phononWidget, SIGNAL(playingStarted()),
91 this, SLOT(slotPlayingStarted()));
92 connect(m_phononWidget, SIGNAL(playingStopped()),
93 this, SLOT(slotPlayingStopped()));
94
95 // name
96 m_nameLabel = new QLabel(parent);
97 QFont font = m_nameLabel->font();
98 font.setBold(true);
99 m_nameLabel->setFont(font);
100 m_nameLabel->setAlignment(Qt::AlignHCenter);
101 m_nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
102
103 const bool showPreview = InformationPanelSettings::showPreview();
104 m_preview->setVisible(showPreview);
105
106 m_metaDataWidget = new KMetaDataWidget(parent);
107 m_metaDataWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
108
109 // Encapsulate the MetaDataWidget inside a container that has a dummy widget
110 // at the bottom. This prevents that the meta data widget gets vertically stretched
111 // in the case where the height of m_metaDataArea > m_metaDataWidget.
112 QWidget* metaDataWidgetContainer = new QWidget(parent);
113 QVBoxLayout* containerLayout = new QVBoxLayout(metaDataWidgetContainer);
114 containerLayout->setContentsMargins(0, 0, 0, 0);
115 containerLayout->setSpacing(0);
116 containerLayout->addWidget(m_metaDataWidget);
117 QWidget* stretchWidget = new QWidget(metaDataWidgetContainer);
118 stretchWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
119 containerLayout->addWidget(stretchWidget);
120
121 m_metaDataArea = new QScrollArea(parent);
122 m_metaDataArea->setWidget(metaDataWidgetContainer);
123 m_metaDataArea->setWidgetResizable(true);
124 m_metaDataArea->setFrameShape(QFrame::NoFrame);
125
126 QWidget* viewport = m_metaDataArea->viewport();
127 viewport->installEventFilter(this);
128
129 QPalette palette = viewport->palette();
130 palette.setColor(viewport->backgroundRole(), QColor(Qt::transparent));
131 viewport->setPalette(palette);
132
133 layout->addWidget(m_preview);
134 layout->addWidget(m_phononWidget);
135 layout->addWidget(m_nameLabel);
136 layout->addWidget(new KSeparator());
137 layout->addWidget(m_metaDataArea);
138 parent->setLayout(layout);
139 }
140
141 InformationPanelContent::~InformationPanelContent()
142 {
143 InformationPanelSettings::self()->writeConfig();
144 }
145
146 void InformationPanelContent::showItem(const KFileItem& item)
147 {
148 m_pendingPreview = false;
149
150 const KUrl itemUrl = item.url();
151 if (!applyPlace(itemUrl)) {
152 // try to get a preview pixmap from the item...
153 m_pendingPreview = true;
154
155 // Mark the currently shown preview as outdated. This is done
156 // with a small delay to prevent a flickering when the next preview
157 // can be shown within a short timeframe. This timer is not started
158 // for directories, as directory previews might fail and return the
159 // same icon.
160 if (!item.isDir()) {
161 m_outdatedPreviewTimer->start();
162 }
163
164 KIO::PreviewJob* job = KIO::filePreview(KFileItemList() << item,
165 m_preview->width(),
166 m_preview->height(),
167 0,
168 0,
169 false,
170 true);
171
172 connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
173 this, SLOT(showPreview(const KFileItem&, const QPixmap&)));
174 connect(job, SIGNAL(failed(const KFileItem&)),
175 this, SLOT(showIcon(const KFileItem&)));
176
177 setNameLabelText(itemUrl.fileName());
178 }
179
180 if (m_metaDataWidget != 0) {
181 m_metaDataWidget->setItem(item);
182 }
183
184 if (InformationPanelSettings::showPreview()) {
185 const QString mimeType = item.mimetype();
186 const bool usePhonon = Phonon::BackendCapabilities::isMimeTypeAvailable(mimeType) &&
187 (mimeType != "image/png"); // TODO: workaround, as Phonon
188 // thinks it supports PNG images
189 if (usePhonon) {
190 m_phononWidget->show();
191 PhononWidget::Mode mode = mimeType.startsWith(QLatin1String("video"))
192 ? PhononWidget::Video
193 : PhononWidget::Audio;
194 m_phononWidget->setMode(mode);
195 m_phononWidget->setUrl(item.url());
196 if ((mode == PhononWidget::Video) && m_preview->isVisible()) {
197 m_phononWidget->setVideoSize(m_preview->size());
198 }
199 } else {
200 m_phononWidget->hide();
201 m_preview->setVisible(true);
202 }
203 } else {
204 m_phononWidget->hide();
205 }
206
207 m_item = item;
208 }
209
210 void InformationPanelContent::showItems(const KFileItemList& items)
211 {
212 m_pendingPreview = false;
213
214 KIconLoader iconLoader;
215 QPixmap icon = iconLoader.loadIcon("dialog-information",
216 KIconLoader::NoGroup,
217 KIconLoader::SizeEnormous);
218 m_preview->setPixmap(icon);
219 setNameLabelText(i18ncp("@info", "%1 item selected", "%1 items selected", items.count()));
220
221 if (m_metaDataWidget != 0) {
222 m_metaDataWidget->setItems(items);
223 }
224
225 m_phononWidget->hide();
226
227 m_item = KFileItem();
228 }
229
230 bool InformationPanelContent::eventFilter(QObject* obj, QEvent* event)
231 {
232 if (event->type() == QEvent::Resize) {
233 QResizeEvent* resizeEvent = static_cast<QResizeEvent*>(event);
234 if (obj == m_metaDataArea->viewport()) {
235 // The size of the meta text area has changed. Adjust the fixed
236 // width in a way that no horizontal scrollbar needs to be shown.
237 m_metaDataWidget->setFixedWidth(resizeEvent->size().width());
238 } else if (obj == parent()) {
239 // If the text inside the name label or the info label cannot
240 // get wrapped, then the maximum width of the label is increased
241 // so that the width of the information panel gets increased.
242 // To prevent this, the maximum width is adjusted to
243 // the current width of the panel.
244 const int maxWidth = resizeEvent->size().width() - KDialog::spacingHint() * 4;
245 m_nameLabel->setMaximumWidth(maxWidth);
246
247 // The metadata widget also contains a text widget which may return
248 // a large preferred width.
249 if (m_metaDataWidget != 0) {
250 m_metaDataWidget->setMaximumWidth(maxWidth);
251 }
252
253 // try to increase the preview as large as possible
254 m_preview->setSizeHint(QSize(maxWidth, maxWidth));
255
256 if (m_phononWidget->isVisible() && (m_phononWidget->mode() == PhononWidget::Video)) {
257 // assure that the size of the video player is the same as the preview size
258 m_phononWidget->setVideoSize(QSize(maxWidth, maxWidth));
259 }
260 }
261 }
262 return Panel::eventFilter(obj, event);
263 }
264
265 void InformationPanelContent::configureSettings()
266 {
267 KMenu popup(this);
268
269 QAction* previewAction = popup.addAction(i18nc("@action:inmenu", "Preview"));
270 previewAction->setIcon(KIcon("view-preview"));
271 previewAction->setCheckable(true);
272 previewAction->setChecked(InformationPanelSettings::showPreview());
273
274 QAction* configureAction = popup.addAction(i18nc("@action:inmenu", "Configure..."));
275 configureAction->setIcon(KIcon("configure"));
276
277 // Open the popup and adjust the settings for the
278 // selected action.
279 QAction* action = popup.exec(QCursor::pos());
280 if (action == 0) {
281 return;
282 }
283
284 const bool isChecked = action->isChecked();
285 if (action == previewAction) {
286 m_preview->setVisible(isChecked);
287 InformationPanelSettings::setShowPreview(isChecked);
288 } else if (action == configureAction) {
289 QPointer<KMetaDataConfigurationDialog> dialog = new KMetaDataConfigurationDialog(m_metaDataWidget, this, Qt::Dialog);
290 dialog->setDescription(i18nc("@label::textbox",
291 "Configure which data should be shown in the Information Panel."));
292 dialog->exec();
293 delete dialog;
294 }
295
296 if (!m_item.isNull() && m_item.nepomukUri().isValid()) {
297 showItem(m_item);
298 }
299 }
300
301 void InformationPanelContent::showIcon(const KFileItem& item)
302 {
303 m_outdatedPreviewTimer->stop();
304 m_pendingPreview = false;
305 if (!applyPlace(item.url())) {
306 m_preview->setPixmap(item.pixmap(KIconLoader::SizeEnormous));
307 }
308 }
309
310 void InformationPanelContent::showPreview(const KFileItem& item,
311 const QPixmap& pixmap)
312 {
313 m_outdatedPreviewTimer->stop();
314
315 Q_UNUSED(item);
316 if (m_pendingPreview) {
317 m_preview->setPixmap(pixmap);
318 m_pendingPreview = false;
319 }
320 }
321
322 void InformationPanelContent::markOutdatedPreview()
323 {
324 KIconEffect iconEffect;
325 QPixmap disabledPixmap = iconEffect.apply(m_preview->pixmap(),
326 KIconLoader::Desktop,
327 KIconLoader::DisabledState);
328 m_preview->setPixmap(disabledPixmap);
329 }
330
331 void InformationPanelContent::slotPlayingStarted()
332 {
333 m_preview->setVisible(m_phononWidget->mode() != PhononWidget::Video);
334 }
335
336 void InformationPanelContent::slotPlayingStopped()
337 {
338 m_preview->setVisible(true);
339 }
340
341 bool InformationPanelContent::applyPlace(const KUrl& url)
342 {
343 KFilePlacesModel* placesModel = DolphinSettings::instance().placesModel();
344 int count = placesModel->rowCount();
345
346 for (int i = 0; i < count; ++i) {
347 QModelIndex index = placesModel->index(i, 0);
348
349 if (url.equals(placesModel->url(index), KUrl::CompareWithoutTrailingSlash)) {
350 setNameLabelText(placesModel->text(index));
351 m_preview->setPixmap(placesModel->icon(index).pixmap(128, 128));
352 return true;
353 }
354 }
355
356 return false;
357 }
358
359 void InformationPanelContent::setNameLabelText(const QString& text)
360 {
361 QTextOption textOption;
362 textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
363
364 QTextLayout textLayout(text);
365 textLayout.setFont(m_nameLabel->font());
366 textLayout.setTextOption(textOption);
367
368 QString wrappedText;
369 wrappedText.reserve(text.length());
370
371 // wrap the text to fit into the width of m_nameLabel
372 textLayout.beginLayout();
373 QTextLine line = textLayout.createLine();
374 while (line.isValid()) {
375 line.setLineWidth(m_nameLabel->width());
376 wrappedText += text.mid(line.textStart(), line.textLength());
377
378 line = textLayout.createLine();
379 if (line.isValid()) {
380 wrappedText += QChar::LineSeparator;
381 }
382 }
383 textLayout.endLayout();
384
385 m_nameLabel->setText(wrappedText);
386 }
387
388 #include "informationpanelcontent.moc"