]> git.sesse.net Git - kdenlive/blob - src/utils/resourcewidget.cpp
Minor optimization
[kdenlive] / src / utils / resourcewidget.cpp
1 /***************************************************************************
2  *   Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *                                                                         *
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.                                   *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  ***************************************************************************/
20
21
22 #include "resourcewidget.h"
23 #include "freesound.h"
24 #include "openclipart.h"
25 #include "archiveorg.h"
26
27 #include <QPushButton>
28 #include <QSpinBox>
29 #include <QListWidget>
30 #include <QAction>
31 #include <QMenu>
32
33 #include <KDebug>
34 #include <kdeversion.h>
35 #include "kdenlivesettings.h"
36 #include <KGlobalSettings>
37 #include <KMessageBox>
38 #include <KFileDialog>
39 #include <kio/job.h>
40 #include <KIO/NetAccess>
41 #include <Solid/Networking>
42 #include <KRun>
43 #if KDE_IS_VERSION(4,4,0)
44 #include <KPixmapSequence>
45 #include <KPixmapSequenceOverlayPainter>
46 #endif
47 #include <KFileItem>
48
49 #ifdef USE_NEPOMUK
50 #if KDE_IS_VERSION(4,6,0)
51 #include <Nepomuk/Variant>
52 #include <Nepomuk/Resource>
53 #include <Nepomuk/ResourceManager>
54 #include <Nepomuk/Vocabulary/NIE>
55 #include <Nepomuk/Vocabulary/NCO>
56 #include <Nepomuk/Vocabulary/NDO>
57 #endif
58 #endif
59
60 #ifdef USE_NEPOMUKCORE
61 #include <Nepomuk2/Variant>
62 #include <Nepomuk2/Resource>
63 #include <Nepomuk2/ResourceManager>
64 #include <Nepomuk2/Vocabulary/NIE>
65 #include <Nepomuk2/Vocabulary/NCO>
66 #include <Nepomuk2/Vocabulary/NDO>
67 #endif
68
69 ResourceWidget::ResourceWidget(const QString & folder, QWidget * parent) :
70     QDialog(parent),
71     m_folder(folder),
72     m_currentService(NULL)
73 {
74     setFont(KGlobalSettings::toolBarFont());
75     setupUi(this);
76     setAttribute(Qt::WA_DeleteOnClose);
77 #ifdef USE_QJSON
78     service_list->addItem(i18n("Freesound Audio Library"), FREESOUND);
79     service_list->addItem(i18n("Archive.org Video Library"), ARCHIVEORG);
80 #endif
81     service_list->addItem(i18n("Open Clip Art Graphic Library"), OPENCLIPART);
82     setWindowTitle(i18n("Search Online Resources"));
83     info_browser->setStyleSheet(QString("QTextBrowser { background-color: transparent;}"));
84     connect(button_search, SIGNAL(clicked()), this, SLOT(slotStartSearch()));
85     connect(search_results, SIGNAL(currentRowChanged(int)), this, SLOT(slotUpdateCurrentSound()));
86     connect(button_preview, SIGNAL(clicked()), this, SLOT(slotPlaySound()));
87     connect(button_import, SIGNAL(clicked()), this, SLOT(slotSaveItem()));
88     connect(item_license, SIGNAL(leftClickedUrl(QString)), this, SLOT(slotOpenUrl(QString)));
89     connect(service_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeService()));
90     if (Solid::Networking::status() == Solid::Networking::Unconnected) {
91         slotOffline();
92     }
93     connect(Solid::Networking::notifier(), SIGNAL(shouldConnect()), this, SLOT(slotOnline()));
94     connect(Solid::Networking::notifier(), SIGNAL(shouldDisconnect()), this, SLOT(slotOffline()));
95     connect(page_next, SIGNAL(clicked()), this, SLOT(slotNextPage()));
96     connect(page_prev, SIGNAL(clicked()), this, SLOT(slotPreviousPage()));
97     connect(page_number, SIGNAL(valueChanged(int)), this, SLOT(slotStartSearch(int)));
98     connect(info_browser, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenLink(QUrl)));
99     
100     m_autoPlay = new QAction(i18n("Auto Play"), this);
101     m_autoPlay->setCheckable(true);
102     QMenu *resourceMenu = new QMenu;
103     resourceMenu->addAction(m_autoPlay);
104     config_button->setMenu(resourceMenu);
105     config_button->setIcon(KIcon("configure"));
106
107 #if KDE_IS_VERSION(4,4,0)
108     m_busyWidget = new KPixmapSequenceOverlayPainter(this);
109     m_busyWidget->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
110     m_busyWidget->setWidget(search_results->viewport());
111 #endif
112     
113     sound_box->setEnabled(false);
114     search_text->setFocus();
115 #ifdef USE_NEPOMUK
116 #if KDE_IS_VERSION(4,6,0)    
117     Nepomuk::ResourceManager::instance()->init();
118 #endif
119 #endif
120     slotChangeService();
121 }
122
123 ResourceWidget::~ResourceWidget()
124 {
125     delete m_currentService;
126     KIO::NetAccess::removeTempFile(m_tmpThumbFile);
127 }
128
129 void ResourceWidget::slotStartSearch(int page)
130 {
131     page_number->blockSignals(true);
132     page_number->setValue(page);
133     page_number->blockSignals(false);
134 #if KDE_IS_VERSION(4,4,0)
135     m_busyWidget->start();
136 #endif
137     m_currentService->slotStartSearch(search_text->text(), page);
138 }
139
140 void ResourceWidget::slotUpdateCurrentSound()
141 {
142     KIO::NetAccess::removeTempFile(m_tmpThumbFile);
143     if (!m_autoPlay->isChecked())
144         m_currentService->stopItemPreview(NULL);
145     item_license->clear();
146     m_title.clear();
147     m_image.clear();
148     m_desc.clear();
149     m_meta.clear();
150     QListWidgetItem *item = search_results->currentItem();
151     if (!item) {
152         sound_box->setEnabled(false);
153         return;
154     }
155     m_currentInfo = m_currentService->displayItemDetails(item);
156     
157     if (m_autoPlay->isChecked() && m_currentService->hasPreview) m_currentService->startItemPreview(item);
158     sound_box->setEnabled(true);
159     QString title = "<h3>" + m_currentInfo.itemName;
160     if (!m_currentInfo.infoUrl.isEmpty())
161         title += QString(" (<a href=\"%1\">%2</a>)").arg(m_currentInfo.infoUrl).arg(i18nc("the url link pointing to a web page", "link"));
162     title.append("</h3>");
163     
164     if (!m_currentInfo.authorUrl.isEmpty()) {
165         title += QString("<a href=\"%1\">").arg(m_currentInfo.authorUrl);
166         if (!m_currentInfo.author.isEmpty())
167             title.append(m_currentInfo.author);
168         else title.append(i18n("Author"));
169         title.append("</a><br />");
170     }
171     else if (!m_currentInfo.author.isEmpty())
172         title.append(m_currentInfo.author + "<br />");
173     else
174         title.append("<br />");
175     
176     slotSetTitle(title);
177     if (!m_currentInfo.description.isEmpty()) slotSetDescription(m_currentInfo.description);
178     if (!m_currentInfo.license.isEmpty()) parseLicense(m_currentInfo.license);
179 }
180
181
182 void ResourceWidget::slotLoadThumb(const QString &url)
183 {
184     KUrl img(url);
185     if (img.isEmpty()) return;
186     if (KIO::NetAccess::exists(img, KIO::NetAccess::SourceSide, this)) {
187         if (KIO::NetAccess::download(img, m_tmpThumbFile, this)) {
188             slotSetImage(m_tmpThumbFile);
189             /*QPixmap pix(tmpFile);
190
191             int newHeight = pix.height() * item_image->width() / pix.width();
192             if (newHeight > 200) {
193                 item_image->setScaledContents(false);
194                 //item_image->setFixedHeight(item_image->width());
195             }
196             else {
197                 item_image->setScaledContents(true);
198                 item_image->setFixedHeight(newHeight);
199             }
200             item_image->setPixmap(pix);*/
201         }
202     }
203 }
204
205
206 void ResourceWidget::slotDisplayMetaInfo(const QMap<QString, QString> &metaInfo)
207 {
208     if (metaInfo.contains("license")) {
209         parseLicense(metaInfo.value("license"));
210     }
211     if (metaInfo.contains("description")) {
212         slotSetDescription(metaInfo.value("description"));
213     }
214 }
215
216
217 void ResourceWidget::slotPlaySound()
218 {
219     if (!m_currentService) return;
220     bool started = m_currentService->startItemPreview(search_results->currentItem());
221     if (started) button_preview->setText(i18n("Preview"));
222     else button_preview->setText(i18n("Stop"));
223 }
224
225
226 void ResourceWidget::slotSaveItem(const QString &originalUrl)
227 {
228     //if (m_currentUrl.isEmpty()) return;
229     QListWidgetItem *item = search_results->currentItem();
230     if (!item) return;
231     QString path = m_folder;
232     QString ext;
233     if (!path.endsWith('/')) path.append('/');
234     if (!originalUrl.isEmpty()) {
235         path.append(KUrl(originalUrl).fileName());
236         ext = "*." + KUrl(originalUrl).fileName().section('.', -1);
237         m_currentInfo.itemDownload = originalUrl;
238     }
239     else {
240         path.append(m_currentService->getDefaultDownloadName(item));
241         ext = m_currentService->getExtension(search_results->currentItem());
242     }
243     QString saveUrl = KFileDialog::getSaveFileName(KUrl(path), ext);
244     KIO::UDSEntry entry;
245     KUrl srcUrl(m_currentInfo.itemDownload);
246     if (saveUrl.isEmpty() || !KIO::NetAccess::stat(srcUrl, entry, this)) return;
247     KIO::FileCopyJob * getJob = KIO::file_copy(srcUrl, KUrl(saveUrl), -1, KIO::Overwrite);
248     
249     KFileItem info(entry, srcUrl);
250     getJob->setSourceSize(info.size());
251     getJob->setProperty("license", item_license->text());
252     getJob->setProperty("licenseurl", item_license->url());
253     getJob->setProperty("originurl", m_currentInfo.itemDownload);
254     if (!m_currentInfo.authorUrl.isEmpty()) getJob->setProperty("author", m_currentInfo.authorUrl);
255     else if (!m_currentInfo.author.isEmpty()) getJob->setProperty("author", m_currentInfo.author);
256     connect(getJob, SIGNAL(result(KJob*)), this, SLOT(slotGotFile(KJob*)));
257     getJob->start();
258 }
259
260 void ResourceWidget::slotGotFile(KJob *job)
261 {
262     if (job->error() != 0 ) return;
263     KIO::FileCopyJob* copyJob = static_cast<KIO::FileCopyJob*>( job );
264     const KUrl filePath = copyJob->destUrl();
265 #ifdef USE_NEPOMUK
266 #if KDE_IS_VERSION(4,6,0)
267     Nepomuk::Resource res( filePath );
268     res.setProperty( Nepomuk::Vocabulary::NIE::license(), (Nepomuk::Variant) job->property("license") );
269     res.setProperty( Nepomuk::Vocabulary::NIE::licenseType(), (Nepomuk::Variant) job->property("licenseurl") );
270     res.setProperty( Nepomuk::Vocabulary::NDO::copiedFrom(), (Nepomuk::Variant) job->property("originurl") );
271     res.setProperty( Nepomuk::Vocabulary::NCO::creator(), (Nepomuk::Variant) job->property("author") );
272     //res.setDescription(item_description->toPlainText());
273     //res.setProperty( Soprano::Vocabulary::NAO::description(),
274 #endif
275 #endif
276
277 #ifdef USE_NEPOMUKCORE
278     Nepomuk2::Resource res( filePath );
279     res.setProperty( Nepomuk2::Vocabulary::NIE::license(), (Nepomuk2::Variant) job->property("license") );
280     res.setProperty( Nepomuk2::Vocabulary::NIE::licenseType(), (Nepomuk2::Variant) job->property("licenseurl") );
281     res.setProperty( Nepomuk2::Vocabulary::NDO::copiedFrom(), (Nepomuk2::Variant) job->property("originurl") );
282     res.setProperty( Nepomuk2::Vocabulary::NCO::creator(), (Nepomuk2::Variant) job->property("author") );
283     //res.setDescription(item_description->toPlainText());
284     //res.setProperty( Soprano::Vocabulary::NAO::description(),
285 #endif
286
287     emit addClip(filePath, stringMap());
288 }
289
290 void ResourceWidget::slotOpenUrl(const QString &url)
291 {
292     new KRun(KUrl(url), this);
293 }
294
295 void ResourceWidget::slotChangeService()
296 {
297     if (m_currentService) {
298         delete m_currentService;
299         m_currentService = NULL;
300     }
301     SERVICETYPE service = (SERVICETYPE) service_list->itemData(service_list->currentIndex()).toInt();
302     if (service == FREESOUND) {
303         m_currentService = new FreeSound(search_results);
304     }
305     else if (service == OPENCLIPART) {
306         m_currentService = new OpenClipArt(search_results);
307     }
308     else if (service == ARCHIVEORG) {
309         m_currentService = new ArchiveOrg(search_results);
310     }
311
312     connect(m_currentService, SIGNAL(gotMetaInfo(QString)), this, SLOT(slotSetMetadata(QString)));
313     connect(m_currentService, SIGNAL(gotMetaInfo(QMap<QString,QString>)), this, SLOT(slotDisplayMetaInfo(QMap<QString,QString>)));
314     connect(m_currentService, SIGNAL(maxPages(int)), this, SLOT(slotSetMaximum(int)));
315     connect(m_currentService, SIGNAL(searchInfo(QString)), search_info, SLOT(setText(QString)));
316     connect(m_currentService, SIGNAL(gotThumb(QString)), this, SLOT(slotLoadThumb(QString)));
317 #if KDE_IS_VERSION(4,4,0)
318     connect(m_currentService, SIGNAL(searchDone()), m_busyWidget, SLOT(stop()));
319 #endif
320     
321     button_preview->setVisible(m_currentService->hasPreview);
322     button_import->setVisible(!m_currentService->inlineDownload);
323     search_info->setText(QString());
324     if (!search_text->text().isEmpty()) slotStartSearch();
325 }
326
327 void ResourceWidget::slotSetMaximum(int max)
328 {
329     page_number->setMaximum(max);
330 }
331
332 void ResourceWidget::slotOnline()
333 {
334     button_search->setEnabled(true);
335     search_info->setText(QString());
336 }
337
338 void ResourceWidget::slotOffline()
339 {
340     button_search->setEnabled(false);
341     search_info->setText(i18n("You need to be online\n for searching"));
342 }
343
344 void ResourceWidget::slotNextPage()
345 {
346     int ix = page_number->value();
347     if (search_results->count() > 0) page_number->setValue(ix + 1);
348 }
349
350 void ResourceWidget::slotPreviousPage()
351 {
352     int ix = page_number->value();
353     if (ix > 1) page_number->setValue(ix - 1);
354 }
355
356 void ResourceWidget::parseLicense(const QString &licenseUrl)
357 {
358     QString licenseName;
359     if (licenseUrl.contains("/sampling+/"))
360         licenseName = "Sampling+";
361     else if (licenseUrl.contains("/by/"))
362         licenseName = "Attribution";
363     else if (licenseUrl.contains("/by-nd/"))
364         licenseName = "Attribution-NoDerivs";
365     else if (licenseUrl.contains("/by-nc-sa/"))
366         licenseName = "Attribution-NonCommercial-ShareAlike";
367     else if (licenseUrl.contains("/by-sa/"))
368         licenseName = "Attribution-ShareAlike";
369     else if (licenseUrl.contains("/by-nc/"))
370         licenseName = "Attribution-NonCommercial";
371     else if (licenseUrl.contains("/by-nc-nd/"))
372         licenseName = "Attribution-NonCommercial-NoDerivs";
373     else if (licenseUrl.contains("/publicdomain/zero/"))
374         licenseName = "Creative Commons 0";
375     else if (licenseUrl.endsWith("/publicdomain"))
376         licenseName = "Public Domain";
377     else licenseName = i18n("Unknown");
378     item_license->setText(licenseName);
379     item_license->setUrl(licenseUrl);
380 }
381
382
383 void ResourceWidget::slotOpenLink(const QUrl &url)
384 {
385     QString path = url.toEncoded();
386     if (path.endsWith("_import")) {
387         path.chop(7);
388         // import file in Kdenlive
389         slotSaveItem(path);
390     }
391     else {
392         slotOpenUrl(path);
393     }
394 }
395
396 void ResourceWidget::slotSetDescription(const QString &desc)
397 {
398     if(m_desc != desc) {
399         m_desc = desc;
400         updateLayout();
401     }
402 }
403
404 void ResourceWidget::slotSetMetadata(const QString &desc)
405 {
406     if (m_meta != desc) {
407         m_meta = desc;
408         updateLayout();
409     }
410 }
411
412 void ResourceWidget::slotSetImage(const QString &desc)
413 {
414     m_image = QString("<img src=\"%1\" style=\"max-height:150px\" max-width=\"%2px\" />").arg(desc).arg((int) (info_browser->width() * 0.9));
415     updateLayout();
416 }
417
418 void ResourceWidget::slotSetTitle(const QString &desc)
419 {
420     if (m_title != desc) {
421         m_title = desc;
422         updateLayout();
423     }
424 }
425
426 void ResourceWidget::updateLayout()
427 {
428     QString content = m_title;
429     if (!m_image.isEmpty()) content.append(m_image + "<br clear=\"all\" />");
430     if (!m_desc.isEmpty()) content.append(m_desc);
431     if (!m_meta.isEmpty()) content.append(m_meta);
432     info_browser->setHtml(content);
433 }
434
435
436 #include "resourcewidget.moc"