1 /***************************************************************************
2 * Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
22 #include "resourcewidget.h"
23 #include "freesound.h"
24 #include "openclipart.h"
25 #include "archiveorg.h"
27 #include <QPushButton>
29 #include <QListWidget>
34 #include <kdeversion.h>
35 #include "kdenlivesettings.h"
36 #include <KGlobalSettings>
37 #include <KMessageBox>
38 #include <KFileDialog>
40 #include <KIO/NetAccess>
41 #include <Solid/Networking>
43 #include <KPixmapSequence>
44 #include <KPixmapSequenceOverlayPainter>
48 #if KDE_IS_VERSION(4,6,0)
49 #include <Nepomuk/Variant>
50 #include <Nepomuk/Resource>
51 #include <Nepomuk/ResourceManager>
52 #include <Nepomuk/Vocabulary/NIE>
53 #include <Nepomuk/Vocabulary/NCO>
54 #include <Nepomuk/Vocabulary/NDO>
55 #include <kfileitem.h>
59 ResourceWidget::ResourceWidget(const QString & folder, QWidget * parent) :
62 m_currentService(NULL)
64 setFont(KGlobalSettings::toolBarFont());
66 setAttribute(Qt::WA_DeleteOnClose);
68 service_list->addItem(i18n("Freesound Audio Library"), FREESOUND);
69 service_list->addItem(i18n("Archive.org Video Library"), ARCHIVEORG);
71 service_list->addItem(i18n("Open Clip Art Graphic Library"), OPENCLIPART);
72 setWindowTitle(i18n("Search Online Resources"));
73 info_browser->setStyleSheet(QString("QTextBrowser { background-color: transparent;}"));
74 connect(button_search, SIGNAL(clicked()), this, SLOT(slotStartSearch()));
75 connect(search_results, SIGNAL(currentRowChanged(int)), this, SLOT(slotUpdateCurrentSound()));
76 connect(button_preview, SIGNAL(clicked()), this, SLOT(slotPlaySound()));
77 connect(button_import, SIGNAL(clicked()), this, SLOT(slotSaveItem()));
78 connect(item_license, SIGNAL(leftClickedUrl(const QString &)), this, SLOT(slotOpenUrl(const QString &)));
79 connect(service_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeService()));
80 if (Solid::Networking::status() == Solid::Networking::Unconnected) {
83 connect(Solid::Networking::notifier(), SIGNAL(shouldConnect()), this, SLOT(slotOnline()));
84 connect(Solid::Networking::notifier(), SIGNAL(shouldDisconnect()), this, SLOT(slotOffline()));
85 connect(page_next, SIGNAL(clicked()), this, SLOT(slotNextPage()));
86 connect(page_prev, SIGNAL(clicked()), this, SLOT(slotPreviousPage()));
87 connect(page_number, SIGNAL(valueChanged(int)), this, SLOT(slotStartSearch(int)));
88 connect(info_browser, SIGNAL(anchorClicked(const QUrl &)), this, SLOT(slotOpenLink(const QUrl &)));
90 m_autoPlay = new QAction(i18n("Auto Play"), this);
91 m_autoPlay->setCheckable(true);
92 QMenu *resourceMenu = new QMenu;
93 resourceMenu->addAction(m_autoPlay);
94 config_button->setMenu(resourceMenu);
95 config_button->setIcon(KIcon("configure"));
97 m_busyWidget = new KPixmapSequenceOverlayPainter(this);
98 m_busyWidget->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
99 m_busyWidget->setWidget(search_results->viewport());
101 sound_box->setEnabled(false);
102 search_text->setFocus();
104 #if KDE_IS_VERSION(4,6,0)
105 Nepomuk::ResourceManager::instance()->init();
111 ResourceWidget::~ResourceWidget()
113 if (m_currentService) delete m_currentService;
114 KIO::NetAccess::removeTempFile(m_tmpThumbFile);
117 void ResourceWidget::slotStartSearch(int page)
119 page_number->blockSignals(true);
120 page_number->setValue(page);
121 page_number->blockSignals(false);
122 m_busyWidget->start();
123 m_currentService->slotStartSearch(search_text->text(), page);
126 void ResourceWidget::slotUpdateCurrentSound()
128 KIO::NetAccess::removeTempFile(m_tmpThumbFile);
129 if (!m_autoPlay->isChecked()) m_currentService->stopItemPreview(NULL);
130 item_license->clear();
135 QListWidgetItem *item = search_results->currentItem();
137 sound_box->setEnabled(false);
140 m_currentInfo = m_currentService->displayItemDetails(item);
142 if (m_autoPlay->isChecked() && m_currentService->hasPreview) m_currentService->startItemPreview(item);
143 sound_box->setEnabled(true);
144 QString title = "<h3>" + m_currentInfo.itemName;
145 if (!m_currentInfo.infoUrl.isEmpty()) title += QString(" (<a href=\"%1\">%2</a>)").arg(m_currentInfo.infoUrl).arg(i18nc("the url link pointing to a web page", "link"));
146 title.append("</h3>");
148 if (!m_currentInfo.authorUrl.isEmpty()) {
149 title += QString("<a href=\"%1\">").arg(m_currentInfo.authorUrl);
150 if (!m_currentInfo.author.isEmpty())
151 title.append(m_currentInfo.author);
152 else title.append(i18n("Author"));
153 title.append("</a><br />");
155 else if (!m_currentInfo.author.isEmpty())
156 title.append(m_currentInfo.author + "<br />");
157 else title.append("<br />");
160 if (!m_currentInfo.description.isEmpty()) slotSetDescription(m_currentInfo.description);
161 if (!m_currentInfo.license.isEmpty()) parseLicense(m_currentInfo.license);
165 void ResourceWidget::slotLoadThumb(const QString url)
168 if (img.isEmpty()) return;
169 if (KIO::NetAccess::exists(img, KIO::NetAccess::SourceSide, this)) {
170 if (KIO::NetAccess::download(img, m_tmpThumbFile, this)) {
171 slotSetImage(m_tmpThumbFile);
172 /*QPixmap pix(tmpFile);
174 int newHeight = pix.height() * item_image->width() / pix.width();
175 if (newHeight > 200) {
176 item_image->setScaledContents(false);
177 //item_image->setFixedHeight(item_image->width());
180 item_image->setScaledContents(true);
181 item_image->setFixedHeight(newHeight);
183 item_image->setPixmap(pix);*/
189 void ResourceWidget::slotDisplayMetaInfo(QMap <QString, QString> metaInfo)
191 if (metaInfo.contains("license")) {
192 parseLicense(metaInfo.value("license"));
194 if (metaInfo.contains("description")) {
195 slotSetDescription(metaInfo.value("description"));
200 void ResourceWidget::slotPlaySound()
202 if (!m_currentService) return;
203 bool started = m_currentService->startItemPreview(search_results->currentItem());
204 if (started) button_preview->setText(i18n("Preview"));
205 else button_preview->setText(i18n("Stop"));
209 void ResourceWidget::slotForcePlaySound(bool play)
212 if (m_service != FREESOUND) return;
213 m_previewProcess->close();
214 if (m_currentPreview.isEmpty()) return;
216 m_previewProcess->start("ffplay", QStringList() << m_currentPreview << "-nodisp");
220 void ResourceWidget::slotPreviewStatusChanged(QProcess::ProcessState state)
222 /*if (state == QProcess::NotRunning)
223 button_preview->setText(i18n("Preview"));
225 button_preview->setText(i18n("Stop"));*/
228 void ResourceWidget::slotSaveItem(const QString originalUrl)
230 //if (m_currentUrl.isEmpty()) return;
231 QListWidgetItem *item = search_results->currentItem();
233 QString path = m_folder;
235 if (!path.endsWith('/')) path.append('/');
236 if (!originalUrl.isEmpty()) {
237 path.append(KUrl(originalUrl).fileName());
238 ext = "*." + KUrl(originalUrl).fileName().section(".", -1);
239 m_currentInfo.itemDownload = originalUrl;
242 path.append(m_currentService->getDefaultDownloadName(item));
243 ext = m_currentService->getExtension(search_results->currentItem());
245 QString saveUrl = KFileDialog::getSaveFileName(KUrl(path), ext);
247 KUrl srcUrl(m_currentInfo.itemDownload);
248 if (saveUrl.isEmpty() || !KIO::NetAccess::stat(srcUrl, entry, this)) return;
249 KIO::FileCopyJob * getJob = KIO::file_copy(srcUrl, KUrl(saveUrl), -1, KIO::Overwrite);
251 KFileItem info(entry, srcUrl);
252 getJob->setSourceSize(info.size());
253 getJob->setProperty("license", item_license->text());
254 getJob->setProperty("licenseurl", item_license->url());
255 getJob->setProperty("originurl", m_currentInfo.itemDownload);
256 if (!m_currentInfo.authorUrl.isEmpty()) getJob->setProperty("author", m_currentInfo.authorUrl);
257 else if (!m_currentInfo.author.isEmpty()) getJob->setProperty("author", m_currentInfo.author);
258 connect(getJob, SIGNAL(result(KJob*)), this, SLOT(slotGotFile(KJob*)));
262 void ResourceWidget::slotGotFile(KJob *job)
264 if (job->error() != 0 ) return;
265 KIO::FileCopyJob* copyJob = static_cast<KIO::FileCopyJob*>( job );
266 const KUrl filePath = copyJob->destUrl();
268 #if KDE_IS_VERSION(4,6,0)
269 Nepomuk::Resource res( filePath );
270 res.setProperty( Nepomuk::Vocabulary::NIE::license(), (Nepomuk::Variant) job->property("license") );
271 res.setProperty( Nepomuk::Vocabulary::NIE::licenseType(), (Nepomuk::Variant) job->property("licenseurl") );
272 res.setProperty( Nepomuk::Vocabulary::NDO::copiedFrom(), (Nepomuk::Variant) job->property("originurl") );
273 res.setProperty( Nepomuk::Vocabulary::NDO::copiedFrom(), (Nepomuk::Variant) job->property("originurl") );
274 res.setProperty( Nepomuk::Vocabulary::NCO::creator(), (Nepomuk::Variant) job->property("author") );
275 //res.setDescription(item_description->toPlainText());
276 //res.setProperty( Soprano::Vocabulary::NAO::description(),
279 emit addClip(filePath, QString());
282 void ResourceWidget::slotOpenUrl(const QString &url)
284 new KRun(KUrl(url), this);
287 void ResourceWidget::slotChangeService()
289 if (m_currentService) {
290 delete m_currentService;
291 m_currentService = NULL;
293 SERVICETYPE service = (SERVICETYPE) service_list->itemData(service_list->currentIndex()).toInt();
294 if (service == FREESOUND) {
295 m_currentService = new FreeSound(search_results);
297 else if (service == OPENCLIPART) {
298 m_currentService = new OpenClipArt(search_results);
300 else if (service == ARCHIVEORG) {
301 m_currentService = new ArchiveOrg(search_results);
304 connect(m_currentService, SIGNAL(gotMetaInfo(const QString)), this, SLOT(slotSetMetadata(const QString)));
305 connect(m_currentService, SIGNAL(gotMetaInfo(QMap <QString, QString>)), this, SLOT(slotDisplayMetaInfo(QMap <QString, QString>)));
306 connect(m_currentService, SIGNAL(maxPages(int)), page_number, SLOT(setMaximum(int)));
307 connect(m_currentService, SIGNAL(searchInfo(QString)), search_info, SLOT(setText(QString)));
308 connect(m_currentService, SIGNAL(gotThumb(const QString)), this, SLOT(slotLoadThumb(const QString)));
309 connect(m_currentService, SIGNAL(searchDone()), m_busyWidget, SLOT(stop()));
311 button_preview->setVisible(m_currentService->hasPreview);
312 button_import->setVisible(!m_currentService->inlineDownload);
313 search_info->setText(QString());
314 if (!search_text->text().isEmpty()) slotStartSearch();
317 void ResourceWidget::slotOnline()
319 button_search->setEnabled(true);
320 search_info->setText(QString());
323 void ResourceWidget::slotOffline()
325 button_search->setEnabled(false);
326 search_info->setText(i18n("You need to be online\n for searching"));
329 void ResourceWidget::slotNextPage()
331 int ix = page_number->value();
332 if (search_results->count() > 0) page_number->setValue(ix + 1);
335 void ResourceWidget::slotPreviousPage()
337 int ix = page_number->value();
338 if (ix > 1) page_number->setValue(ix - 1);
341 void ResourceWidget::parseLicense(const QString &licenseUrl)
344 if (licenseUrl.contains("/sampling+/"))
345 licenseName = "Sampling+";
346 else if (licenseUrl.contains("/by/"))
347 licenseName = "Attribution";
348 else if (licenseUrl.contains("/by-nd/"))
349 licenseName = "Attribution-NoDerivs";
350 else if (licenseUrl.contains("/by-nc-sa/"))
351 licenseName = "Attribution-NonCommercial-ShareAlike";
352 else if (licenseUrl.contains("/by-sa/"))
353 licenseName = "Attribution-ShareAlike";
354 else if (licenseUrl.contains("/by-nc/"))
355 licenseName = "Attribution-NonCommercial";
356 else if (licenseUrl.contains("/by-nc-nd/"))
357 licenseName = "Attribution-NonCommercial-NoDerivs";
358 else if (licenseUrl.contains("/publicdomain/zero/"))
359 licenseName = "Creative Commons 0";
360 else if (licenseUrl.endsWith("/publicdomain"))
361 licenseName = "Public Domain";
362 else licenseName = i18n("Unknown");
363 item_license->setText(licenseName);
364 item_license->setUrl(licenseUrl);
368 void ResourceWidget::slotOpenLink(const QUrl &url)
370 QString path = url.toEncoded();
371 if (path.endsWith("_import")) {
373 // import file in Kdenlive
381 void ResourceWidget::slotSetDescription(const QString desc)
387 void ResourceWidget::slotSetMetadata(const QString desc)
393 void ResourceWidget::slotSetImage(const QString desc)
395 m_image = QString("<img src=\"%1\" style=\"max-height:150px\" max-width=\"%2px\" />").arg(desc).arg((int) (info_browser->width() * 0.9));
399 void ResourceWidget::slotSetTitle(const QString desc)
405 void ResourceWidget::updateLayout()
407 QString content = m_title;
408 if (!m_image.isEmpty()) content.append(m_image + "<br clear=\"all\" />");
409 if (!m_desc.isEmpty()) content.append(m_desc);
410 if (!m_meta.isEmpty()) content.append(m_meta);
411 info_browser->setHtml(content);