[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    playground/network/videocatcher/src [POSSIBLY UNSAFE]
From:       Jonas Emanuel Müller <zanoi () zanoi ! net>
Date:       2010-11-26 17:24:53
Message-ID: 20101126172453.4EA23AC8A2 () svn ! kde ! org
[Download RAW message or body]

SVN commit 1201071 by jonasemuller:

create dynamic play menu based on downloaded file's mime type

 M  +28 -12    configurewidget.ui  
 M  +121 -9    mainwindowkde.cpp   [POSSIBLY UNSAFE: KRun::runCommand]
 M  +2 -1      mainwindowkde.h  


--- trunk/playground/network/videocatcher/src/configurewidget.ui #1201070:1201071
@@ -39,8 +39,8 @@
     </layout>
    </item>
    <item>
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout_6">
+     <item>
       <spacer name="verticalSpacer_3">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
@@ -53,7 +53,7 @@
        </property>
       </spacer>
      </item>
-     <item row="0" column="1">
+     <item>
       <spacer name="verticalSpacer_4">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
@@ -66,7 +66,11 @@
        </property>
       </spacer>
      </item>
-     <item row="1" column="0" rowspan="2">
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_5">
+     <item>
       <widget class="QLabel" name="label">
        <property name="text">
         <string>Video Folder</string>
@@ -76,10 +80,14 @@
        </property>
       </widget>
      </item>
-     <item row="1" column="1" rowspan="2">
+     <item>
       <widget class="KLineEdit" name="kcfg_videoPath"/>
      </item>
-     <item row="3" column="0">
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
@@ -92,7 +100,7 @@
        </property>
       </spacer>
      </item>
-     <item row="3" column="1">
+     <item>
       <spacer name="verticalSpacer_2">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
@@ -105,20 +113,28 @@
        </property>
       </spacer>
      </item>
-     <item row="4" column="0" rowspan="2">
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
       <widget class="QLabel" name="label_2">
        <property name="text">
-        <string>Playback program</string>
+        <string>Use custom playback command</string>
        </property>
        <property name="buddy">
         <cstring>kcfg_videoPlaybackCommand</cstring>
        </property>
       </widget>
      </item>
-     <item row="4" column="1" rowspan="2">
+     <item>
       <widget class="KLineEdit" name="kcfg_videoPlaybackCommand"/>
      </item>
-     <item row="6" column="0">
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
       <spacer name="verticalSpacer_5">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
@@ -131,7 +147,7 @@
        </property>
       </spacer>
      </item>
-     <item row="6" column="1">
+     <item>
       <spacer name="verticalSpacer_6">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
--- trunk/playground/network/videocatcher/src/mainwindowkde.cpp #1201070:1201071
@@ -49,6 +49,10 @@
 #include <KMenu>
 #include <KFileDialog>
 #include <KStandardShortcut>
+#include <KRun>
+#include <KMimeTypeTrader>
+#include <KMimeType>
+#include <KActionMenu>
 
 #if KDE_IS_VERSION(4,4,0)
 #include <KStatusNotifierItem>
@@ -103,6 +107,13 @@
     QMap<KJob *, unsigned long> *m_downloadSpeeds;
     // The search bar
     KLineEdit *m_searchText;
+    // This stores the play menu for easy access
+    KActionMenu *m_playMenu;
+    // This is a list of the current actions in 
+    // the play menu. The list is needed in order
+    // to be able to remove the actions from the
+    // menu.
+    QStringList *m_playMenuActions;
 };
 
 MainWindow::MainWindow(QWidget *parent) : KXmlGuiWindow(parent), d(new \
MainWindowPrivate) @@ -253,13 +264,15 @@
     connect(cancelEpisodeDownloadAction, SIGNAL(triggered()), this,
         SLOT(cancelEpisodeDownload()));
 
-    KAction *playEpisodeAction = new KAction(i18n("&Play Episode"), this);
-    playEpisodeAction->setShortcuts(KShortcut("Space"));
-    playEpisodeAction->setIcon(KIcon("media-playback-start"));
-    playEpisodeAction->setStatusTip(i18n("Play episode"));
-    playEpisodeAction->setEnabled(false);
-    actionCollection()->addAction("play", playEpisodeAction);
-    connect(playEpisodeAction, SIGNAL(triggered()), this, SLOT(playEpisode()));
+    d->m_playMenu = new KActionMenu(i18n("&Play Episode"), this);
+    d->m_playMenu->setShortcuts(KShortcut("Space"));
+    d->m_playMenu->setIcon(KIcon("media-playback-start"));
+    d->m_playMenu->setStatusTip(i18n("Play episode"));
+    d->m_playMenu->setEnabled(false);
+    d->m_playMenu->setDelayed(true);
+    actionCollection()->addAction("play", d->m_playMenu);
+    connect(d->m_playMenu, SIGNAL(triggered()), this, SLOT(playEpisode()));
+    d->m_playMenuActions = new QStringList;
 
     KAction *streamEpisodeAction = new KAction(i18n("&Stream Episode"), this);
     //streamEpisodeAction->setShortcut(i18n(""));
@@ -360,7 +373,21 @@
         d->m_episodeInformationWidget->setAttribute("Description:", \
                d->m_episodeModel->description(current));
         d->m_episodeInformationWidget->setAttribute("Size:", \
KIO::convertSize(d->m_episodeModel->videoSize(current)));  }
+
+    //update the play menu to show all registered applications
+    //for the currently selected channels video mimetype
+    QString videoPath = d->m_episodeModel->videoPath(current);
+
+    if(videoPath != "") {
+        KMimeType::Ptr mimeType;
+        //note that the fourth parameter enables fast_mode
+        //which means that no disk access is allowed
+        //this is to prevent constant disk access, but might
+        //be changed later.
+        mimeType = KMimeType::findByUrl(videoPath, 0, true, true);
+        updatePlayMenu(mimeType.data()->name());
 }
+}
 
 void MainWindow::updateEpisodeView()
 {
@@ -836,16 +863,32 @@
     }
 }
 
+/**
+ * This method will play the currently selected episode. If the action which
+ * called this slot has data set (with setData()) it  will be interpreted as 
+ * a QString name of the preferred service to play the episode with. Otherwise 
+ * the default service for the episodes mime type will be used.
+ */
 void MainWindow::playEpisode()
 {
+    QString preferredService;
+    QAction *action = qobject_cast<QAction*>(sender());
+    if(action) {
+        preferredService = action->data().toString();
+    }
+
     QModelIndex index = d->m_episodeView->currentIndex();
     if (!index.isValid()) {
         KMessageBox::information(this, i18n("No episode selected. Please select an \
episode."), i18n("Play Episode"));  return;
     }
 
+    if(preferredService.isEmpty()) {
     playEpisode(index);
+    } else {
+        playEpisode(index, preferredService);
 }
+}
 
 void MainWindow::streamEpisode()
 {
@@ -978,6 +1021,55 @@
     submitChannelsAndEpisodes();    
 }
 
+/**
+ * This method updates the play menu to display all registered applications for the \
given + * mime type. If a custom command is specified in the applications \
configuration dialog + * it will be appended to the menu.
+ *
+ * @param mimeType the mime type for which the registered applications should be \
shown. + */
+void MainWindow::updatePlayMenu(const QString &mimeType)
+{
+    for(int i=0; i < d->m_playMenuActions->size(); ++i) {
+        kDebug() << "removing actions: " << d->m_playMenuActions->at(i);
+            d->m_playMenu->removeAction(actionCollection()->action(d->m_playMenuActions->at(i)));
 +        }
+        d->m_playMenuActions->clear();
+
+        KService::List services = KMimeTypeTrader::self()->query(mimeType, \
"Application"); +
+        KService::List::ConstIterator it = services.constBegin();
+        const KService::List::ConstIterator end = services.constEnd();
+        for(; it != end; ++it) {
+            KAction *action;
+            const KService::Ptr service = *it;
+            kDebug() << "service: " << service->desktopEntryName();
+            action = new KAction((*it)->name(), this);
+            action->setIcon(KIcon((*it)->icon()));
+            action->setData((*it)->desktopEntryName());
+            connect(action, SIGNAL(triggered()), this, SLOT(playEpisode()));
+            actionCollection()->addAction((*it)->desktopEntryName(), action);
+            d->m_playMenu->addAction(action);
+            *d->m_playMenuActions << (*it)->desktopEntryName();
+        }
+
+        // append a custom command playback option, if a command is configured in \
the settings +        QString videoPlaybackCommand = \
Configure::videoPlaybackCommand(); +        if(!videoPlaybackCommand.isEmpty()) {
+            KAction *action;
+            kDebug() << "appending custom command: " << videoPlaybackCommand;
+            action = new KAction(videoPlaybackCommand, this);
+            //action->setIcon(KIcon((*it)->icon()));
+            action->setData("customCommand");
+            connect(action, SIGNAL(triggered()), this, SLOT(playEpisode()));
+            actionCollection()->addAction("customCommand", action);
+            d->m_playMenu->addAction(action);
+            *d->m_playMenuActions << "customCommand";
+
+        }
+
+}
+
 KUrl MainWindow::calculateEpisodeVideoPath(QModelIndex index)
 {
     QString hostname;
@@ -1063,11 +1155,31 @@
     }
 }
 
-void MainWindow::playEpisode(const QModelIndex row) {
+/**
+ * This method plays a particular episode with an external application. If the \
external application + * is not specified or cannot be found the systems default \
application for the files' mimetype will + * be used.
+ * 
+ * @param row a QModelIndex representing the row of the episode that is to be played
+ * @param preferredServiceName The name of the preferred service to play back the \
episode.  + * In case the service is not found it will fall back to the default \
service. If "customCommand" + * is passed, the episode will be played back using the \
shell command specified by the user + * in the applications configuration dialog. \
This is in order to play back using applications which are not + * registered as a \
service. + */
+void MainWindow::playEpisode(const QModelIndex row, const QString \
&preferredServiceName) { +    if(preferredServiceName == "customCommand") {
     QString videoPlaybackCommand = Configure::videoPlaybackCommand();
     kDebug() << "videoPlaybackCommand: " << videoPlaybackCommand << " " << \
                QStringList(d->m_episodeModel->videoPath(row));
-    QProcess::startDetached(videoPlaybackCommand, \
QStringList(d->m_episodeModel->videoPath(row))); +        QString command = \
videoPlaybackCommand + " " + d->m_episodeModel->videoPath(row); +        \
KRun::runCommand(command, this); +    } else {
+        KRun::KRun *run = new KRun::KRun(d->m_episodeModel->videoPath(row), this);
+        if (preferredServiceName != "") {
+            run->setPreferredService(preferredServiceName);
 }
+    }
+}
 
 void MainWindow::searchChanged(const QString & str)
 {
--- trunk/playground/network/videocatcher/src/mainwindowkde.h #1201070:1201071
@@ -59,7 +59,7 @@
 public:
     MainWindow(QWidget *parent = 0);
     ~MainWindow();
-    void playEpisode(const QModelIndex row);
+    void playEpisode(const QModelIndex row, const QString &preferredServiceName = \
"");  void refreshChannel(QModelIndex index);
     void cancelEpisodeDownload(QModelIndex index);
     void cancelAllEpisodeDownloads();
@@ -95,6 +95,7 @@
     void quit();
 
 protected:
+    void updatePlayMenu(const QString &mimeType);
     void closeEvent(QCloseEvent *event);
     KUrl calculateEpisodeVideoPath(QModelIndex episode);
     KUrl calculateChannelPath(QModelIndex channel);


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic