From: Jean-Baptiste Mardelle Date: Tue, 7 Dec 2010 19:43:09 +0000 (+0000) Subject: Make jog shuttle buttons work, based on patch from P. Fleury, X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=16e43620d9ff9e432ea91ded529f1e365d03fd52;p=kdenlive Make jog shuttle buttons work, based on patch from P. Fleury, http://kdenlive.org/mantis/view.php?id=1895 svn path=/trunk/kdenlive/; revision=5148 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5ec9181..31a9238c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -257,6 +257,8 @@ set(kdenlive_SRCS kiss_fft/_kiss_fft_guts.h kiss_fft/kiss_fft.c kiss_fft/tools/kiss_fftr.c + jogaction.cpp + jogshuttleconfig.cpp ) add_subdirectory(${CMAKE_SOURCE_DIR}/src/colorcorrection) diff --git a/src/jogaction.cpp b/src/jogaction.cpp new file mode 100644 index 00000000..646cc9ff --- /dev/null +++ b/src/jogaction.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2010 by Pascal Fleury (fleury@users.sourceforge.net) * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "jogaction.h" + +#include +#include +#include + +// TODO(fleury): this should probably be a user configuration parameter (at least the max speed). +const double SPEEDS[] = {0.0, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0}; +const size_t SPEEDS_SIZE = sizeof(SPEEDS) / sizeof(double); + +JogShuttleAction::JogShuttleAction (const JogShuttle* jogShuttle, const QStringList& actionMap, QObject * parent) + : QObject(parent), m_jogShuttle(jogShuttle), m_actionMap(actionMap) +{ + // Add action map 0 used for stopping the monitor when the shuttle is in neutral position. + if (m_actionMap.size() == 0) + m_actionMap.append("monitor_pause"); + + connect(m_jogShuttle, SIGNAL( jogBack() ), this, SLOT( slotJogBack() )); + connect(m_jogShuttle, SIGNAL( jogForward() ), this, SLOT( slotJogForward() )); + connect(m_jogShuttle, SIGNAL( shuttlePos ( int ) ), this, SLOT( slotShuttlePos ( int ) )); + connect(m_jogShuttle, SIGNAL( button ( int ) ), this, SLOT( slotButton ( int ) )); + //for (int i = 0; i < actionMap.size(); i++) fprintf(stderr, "button #%d -> action '%s'\n", i, actionMap[i].toAscii().constData()); //DBG +} + +JogShuttleAction::~JogShuttleAction() +{ + disconnect(m_jogShuttle, SIGNAL( jogBack() ), this, SLOT( slotJogBack() )); + disconnect(m_jogShuttle, SIGNAL( jogForward() ), this, SLOT( slotJogForward() )); + disconnect(m_jogShuttle, SIGNAL( shuttlePos ( int ) ), this, SLOT( slotShuttlePos ( int ) )); + disconnect(m_jogShuttle, SIGNAL( button ( int ) ), this, SLOT( slotButton ( int ) )); +} + +void JogShuttleAction::slotJogBack() +{ + emit rewindOneFrame(); +} + +void JogShuttleAction::slotJogForward() +{ + emit forwardOneFrame(); +} + +void JogShuttleAction::slotShuttlePos(int shuttle_pos) +{ + size_t magnitude = abs(shuttle_pos); + if (magnitude < SPEEDS_SIZE) { + if (shuttle_pos < 0) + emit rewind(-SPEEDS[magnitude]); + if (shuttle_pos == 0) + emit action(m_actionMap[0]); + if (shuttle_pos > 0) + emit forward(SPEEDS[magnitude]); + } +} + +void JogShuttleAction::slotButton(int button_id) +{ + if (button_id >= m_actionMap.size() || m_actionMap[button_id] == "") { + // TODO(fleury): Shoudl this go to the status bar to inform the user ? + fprintf(stderr, "Button %d has no action\n", button_id); + return; + } + //fprintf(stderr, "Button #%d maps to action '%s'\n", button_id, m_actionMap[button_id].toAscii().constData()); //DBG + emit action(m_actionMap[button_id]); +} diff --git a/src/jogaction.h b/src/jogaction.h new file mode 100644 index 00000000..cd0788d0 --- /dev/null +++ b/src/jogaction.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2010 by Pascal Fleury (fleury@users.sourceforge.net) * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef JOG_SHUTTLE_ACTION_H +#define JOG_SHUTTLE_ACTION_H + +#include +#include + +#include "jogshuttle.h" + +class JogShuttleAction: public QObject +{ +Q_OBJECT public: + explicit JogShuttleAction(const JogShuttle* jogShuttle, const QStringList& actionMap, QObject * parent = 0); + ~JogShuttleAction(); + + +private: + const JogShuttle* m_jogShuttle; + // this is indexed by button ID, having QString() for any non-used ones. + QStringList m_actionMap; + +public slots: + void slotJogBack(); + void slotJogForward(); + void slotShuttlePos(int); + void slotButton(int); + +signals: + void rewindOneFrame(); + void forwardOneFrame(); + void rewind(double); + void forward(double); + void action(const QString&); +}; + +#endif diff --git a/src/jogshuttle.cpp b/src/jogshuttle.cpp index 752869a7..b5dd0e8c 100644 --- a/src/jogshuttle.cpp +++ b/src/jogshuttle.cpp @@ -60,15 +60,12 @@ // Constants for the signals sent. #define JOG_BACK1 10001 #define JOG_FWD1 10002 +#define KEY_EVENT_OFFSET 20000 // middle value for shuttle, will be +/-MAX_SHUTTLE_RANGE -#define JOG_STOP 10010 +#define JOG_STOP 10020 #define MAX_SHUTTLE_RANGE 7 -// TODO(fleury): this should probably be a user configuration parameter (at least the max speed). -const double SPEEDS[MAX_SHUTTLE_RANGE + 1] = {0.0, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0}; - - void ShuttleThread::init(QObject *parent, QString device) { m_parent = parent; @@ -104,7 +101,7 @@ void ShuttleThread::run() int num_warnings = 0; while (!stop_me) { if (read(fd, &ev, sizeof(ev)) < 0) { - if (num_warnings % 100 == 0) + if (num_warnings % 10000 == 0) fprintf(stderr, "Failed to read event from Jog Shuttle FILE DESCRIPTOR (repeated %d times)\n", num_warnings + 1); num_warnings++; } @@ -142,7 +139,7 @@ void ShuttleThread::key(unsigned short code, unsigned int value) return; kDebug() << "Button PRESSED: " << code; - QApplication::postEvent(m_parent, new QEvent((QEvent::Type)(20000 + code))); + QApplication::postEvent(m_parent, new QEvent((QEvent::Type)(KEY_EVENT_OFFSET + code))); } @@ -160,7 +157,7 @@ void ShuttleThread::shuttle(int value) } shuttlevalue = value; shuttlechange = true; - QApplication::postEvent(m_parent, new QEvent((QEvent::Type)(JOG_STOP + value))); + QApplication::postEvent(m_parent, new QEvent((QEvent::Type) (JOG_STOP + value))); } void ShuttleThread::jog(unsigned int value) @@ -228,37 +225,25 @@ void JogShuttle::customEvent(QEvent* e) { int code = e->type(); - // Handle the job events - if (code == JOG_BACK1) { - emit rewind1(); - return; - } - if (code == JOG_FWD1) { - emit forward1(); + // Handle simple job events + switch (code) { + case JOG_BACK1: + emit jogBack(); return; - } - - //handle the shuttle events - if (code == JOG_STOP) { - // TODO(fleury): to make sure stop() has an effect, as it doesn't when in rewind mode, we set it to forward with - // a value that will for sure not move to the next frame. - if (m_shuttleProcess.shuttlevalue < 0) - emit forward(0.01); - emit stop(); + case JOG_FWD1: + emit jogForward(); return; } - int shuttle = code - JOG_STOP; - if (shuttle >= -MAX_SHUTTLE_RANGE && shuttle <= MAX_SHUTTLE_RANGE) { - if (shuttle < 0) - emit rewind(-SPEEDS[abs(shuttle)]); - else - emit forward(SPEEDS[abs(shuttle)]); + int shuttle_pos = code - JOG_STOP; + if (shuttle_pos >= -MAX_SHUTTLE_RANGE && shuttle_pos <= MAX_SHUTTLE_RANGE) { + emit shuttlePos(shuttle_pos); return; } // we've got a key event. - emit button(e->type() - 20000); + //fprintf(stderr, "Firing button event for #%d\n", e->type() - KEY_EVENT_OFFSET); // DBG + emit button(e->type() - KEY_EVENT_OFFSET); } diff --git a/src/jogshuttle.h b/src/jogshuttle.h index 7503bcfb..2c28d88f 100644 --- a/src/jogshuttle.h +++ b/src/jogshuttle.h @@ -67,11 +67,9 @@ private: ShuttleThread m_shuttleProcess; signals: - void rewind1(); - void forward1(); - void rewind(double); - void forward(double); - void stop(); + void jogBack(); + void jogForward(); + void shuttlePos(int); void button(int); }; diff --git a/src/jogshuttleconfig.cpp b/src/jogshuttleconfig.cpp new file mode 100644 index 00000000..ddbaa85a --- /dev/null +++ b/src/jogshuttleconfig.cpp @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2010 by Pascal Fleury (fleury@users.sourceforge.net) * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "jogshuttleconfig.h" + +#include +#include +#include +#include + +#include + +using std::string; +using std::vector; +using std::stringstream; + +// these 2 functions will convert the action maps to and from a string representation not unlike this: +// button1=rewind_one_frame;button2=forward_one_frame;button15=play + +static const QChar DELIMITER = ';'; +static const QChar KEY_VALUE_SEP = '='; +static const QString BUTTON_PREFIX("button"); + +QStringList JogShuttleConfig::actionMap(const QString& actionsConfig) +{ + QStringList actionMap; + QStringList mappings = actionsConfig.split(DELIMITER); + + foreach (const QString& mapping, mappings) { + QStringList parts = mapping.split(KEY_VALUE_SEP); + if (parts.size() != 2) { + fprintf(stderr, "Invalid button configuration: %s", mapping.toAscii().constData()); + continue; + } + // skip the 'button' prefix + int button_id = parts[0].mid(BUTTON_PREFIX.length()).toInt(); + //fprintf(stderr, " - Handling map key='%s' (ID=%d), value='%s'\n", parts[0].data().toAscii(), button_id, parts[1].data().toAscii()); // DBG + while (actionMap.size() <= button_id) + actionMap << QString(); + actionMap[button_id] = parts[1]; + } + + //for (int i = 0; i < actionMap.size(); i++) fprintf(stderr, "button #%d -> action '%s'\n", i, actionMap[i].data().toAscii()); //DBG + return actionMap; +} + +QString JogShuttleConfig::actionMap(const QStringList& actionMap) +{ + QStringList mappings; + for (int i=0; i < actionMap.size(); ++i) { + if (actionMap[i] == "") + continue; + mappings << QString("%1%2%3%4").arg(BUTTON_PREFIX).arg(i).arg(KEY_VALUE_SEP).arg(actionMap[i]); + } + + return mappings.join(DELIMITER); +} diff --git a/src/jogshuttleconfig.h b/src/jogshuttleconfig.h new file mode 100644 index 00000000..489ce4e1 --- /dev/null +++ b/src/jogshuttleconfig.h @@ -0,0 +1,37 @@ +/* + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +*/ + +#ifndef JOGSHUTTLECONFIG_H +#define JOGSHUTTLECONFIG_H + +#include +#include +#include + +#include "jogaction.h" + +class JogShuttleConfig: public QObject +{ +public: + static QStringList actionMap(const QString& actionMap); + static QString actionMap(const QStringList& actionMap); +}; + +#endif // JOGSHUTTLECONFIG_H diff --git a/src/kdenlivesettings.kcfg b/src/kdenlivesettings.kcfg index 5ffaf0dc..ddcb1052 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -478,29 +478,9 @@ - - - 1 - - - - - 2 - - - - - 0 - - - - - 0 - - - - - 0 + + + diff --git a/src/kdenlivesettingsdialog.cpp b/src/kdenlivesettingsdialog.cpp index 3581e45e..1582c3c4 100644 --- a/src/kdenlivesettingsdialog.cpp +++ b/src/kdenlivesettingsdialog.cpp @@ -40,13 +40,17 @@ #include #include #ifndef NO_JOGSHUTTLE +#include "jogaction.h" +#include "jogshuttleconfig.h" #include #endif /* NO_JOGSHUTTLE */ -KdenliveSettingsDialog::KdenliveSettingsDialog(QWidget * parent) : +KdenliveSettingsDialog::KdenliveSettingsDialog(const QMap& mappable_actions, QWidget * parent) : KConfigDialog(parent, "settings", KdenliveSettings::self()), - m_modified(false) + m_modified(false), + m_shuttleModified(false), + m_mappable_actions(mappable_actions) { QWidget *p1 = new QWidget; @@ -108,14 +112,49 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(QWidget * parent) : QWidget *p5 = new QWidget; m_configShuttle.setupUi(p5); -#ifndef NO_JOGSHUTTLE +#ifdef NO_JOGSHUTTLE + m_configShuttle.kcfg_enableshuttle->hide(); + m_configShuttle.kcfg_enableshuttle->setDisabled(true); +#else connect(m_configShuttle.kcfg_enableshuttle, SIGNAL(stateChanged(int)), this, SLOT(slotCheckShuttle(int))); connect(m_configShuttle.shuttledevicelist, SIGNAL(activated(int)), this, SLOT(slotUpdateShuttleDevice(int))); slotCheckShuttle(KdenliveSettings::enableshuttle()); m_configShuttle.shuttledisabled->hide(); -#else - m_configShuttle.kcfg_enableshuttle->hide(); - m_configShuttle.kcfg_enableshuttle->setDisabled(true); + + // Store the button pointers into an array for easier handling them in the other functions. + m_shuttle_buttons.push_back(m_configShuttle.shuttle1); + m_shuttle_buttons.push_back(m_configShuttle.shuttle2); + m_shuttle_buttons.push_back(m_configShuttle.shuttle3); + m_shuttle_buttons.push_back(m_configShuttle.shuttle4); + m_shuttle_buttons.push_back(m_configShuttle.shuttle5); + + // populate the buttons with the current configuration. The items are sorted + // according to the user-selected language, so they do not appear in random order. + QList action_names = mappable_actions.keys(); + qSort(action_names); + + // Here we need to compute the action_id -> index-in-action_names. We iterate over the + // action_names, as the sorting may depend on the user-language. + QStringList actions_map = JogShuttleConfig::actionMap(KdenliveSettings::shuttlebuttons()); + QMap action_pos; + foreach (const QString& action_id, actions_map) { + // This loop find out at what index is the string that would map to the action_id. + for (int i = 0; i < action_names.size(); i++) { + if (mappable_actions[action_names[i]] == action_id) { + action_pos[action_id] = i; + break; + } + } + } + + int i = 0; + foreach (KComboBox* button, m_shuttle_buttons) { + button->addItems(action_names); + connect(button, SIGNAL(activated(int)), this, SLOT(slotShuttleModified())); + ++i; + if (i < actions_map.size()) + button->setCurrentIndex(action_pos[actions_map[i]]); + } #endif /* NO_JOGSHUTTLE */ m_page5 = addPage(p5, i18n("JogShuttle"), "input-mouse"); @@ -134,17 +173,7 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(QWidget * parent) : connect(m_configTranscode.button_add, SIGNAL(clicked()), this, SLOT(slotAddTranscode())); connect(m_configTranscode.button_delete, SIGNAL(clicked()), this, SLOT(slotDeleteTranscode())); connect(m_configTranscode.profiles_list, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDialogModified())); - - QStringList actions; - actions << i18n("Do nothing"); - actions << i18n("Play / Pause"); - actions << i18n("Cut"); - m_configShuttle.kcfg_shuttle1->addItems(actions); - m_configShuttle.kcfg_shuttle2->addItems(actions); - m_configShuttle.kcfg_shuttle3->addItems(actions); - m_configShuttle.kcfg_shuttle4->addItems(actions); - m_configShuttle.kcfg_shuttle5->addItems(actions); - + connect(m_configCapture.kcfg_video4vdevice, SIGNAL(editingFinished()), this, SLOT(rebuildVideo4Commands())); connect(m_configCapture.kcfg_video4adevice, SIGNAL(editingFinished()), this, SLOT(rebuildVideo4Commands())); connect(m_configCapture.kcfg_video4vcodec, SIGNAL(editingFinished()), this, SLOT(rebuildVideo4Commands())); @@ -449,6 +478,7 @@ void KdenliveSettingsDialog::slotUpdateShuttleDevice(int ix) //KdenliveSettings::setShuttledevice(device); m_configShuttle.kcfg_shuttledevice->setText(device); } + #endif /* NO_JOGSHUTTLE */ void KdenliveSettingsDialog::rebuildVideo4Commands() @@ -459,17 +489,56 @@ void KdenliveSettingsDialog::rebuildVideo4Commands() captureCommand += " -f " + m_configCapture.kcfg_video4vformat->text() + " -s " + m_configCapture.kcfg_video4size->text() + " -r " + QString::number(m_configCapture.kcfg_video4rate->value()) + " -i " + m_configCapture.kcfg_video4vdevice->text() + " -vcodec " + m_configCapture.kcfg_video4vcodec->text(); m_configCapture.kcfg_video4capture->setText(captureCommand); } +void KdenliveSettingsDialog::updateWidgets() +{ + // Revert widgets to last saved state (for example when user pressed "Cancel") + // kDebug() << "// // // KCONFIG Revert called"; + // revert jog shuttle device + if (m_configShuttle.shuttledevicelist->count() > 0) { + for (int i = 0; i < m_configShuttle.shuttledevicelist->count(); i++) { + if (m_configShuttle.shuttledevicelist->itemData(i) == KdenliveSettings::shuttledevice()) { + m_configShuttle.shuttledevicelist->setCurrentIndex(i); + break; + } + } + } + // Revert jog shuttle buttons + QList action_names = m_mappable_actions.keys(); + qSort(action_names); + QStringList actions_map = JogShuttleConfig::actionMap(KdenliveSettings::shuttlebuttons()); + QMap action_pos; + foreach (const QString& action_id, actions_map) { + // This loop find out at what index is the string that would map to the action_id. + for (int i = 0; i < action_names.size(); i++) { + if (m_mappable_actions[action_names[i]] == action_id) { + action_pos[action_id] = i; + break; + } + } + } + int i = 0; + foreach (KComboBox* button, m_shuttle_buttons) { + ++i; + if (i < actions_map.size()) + button->setCurrentIndex(action_pos[actions_map[i]]); + } +} void KdenliveSettingsDialog::updateSettings() { - //kDebug() << "// // // KCONFIG UPDATE called"; - + // Save changes to settings (for example when user pressed "Apply" or "Ok") + // kDebug() << "// // // KCONFIG UPDATE called"; m_defaultProfile = m_configProject.kcfg_profiles_list->currentText(); KdenliveSettings::setDefault_profile(m_defaultPath); bool resetProfile = false; bool updateCapturePath = false; + + /*if (m_configShuttle.shuttledevicelist->count() > 0) { + QString device = m_configShuttle.shuttledevicelist->itemData(m_configShuttle.shuttledevicelist->currentIndex()).toString(); + if (device != KdenliveSettings::shuttledevice()) KdenliveSettings::setShuttledevice(device); + }*/ if (m_configEnv.kcfg_capturetoprojectfolder->isChecked() != KdenliveSettings::capturetoprojectfolder()) { KdenliveSettings::setCapturetoprojectfolder(m_configEnv.kcfg_capturetoprojectfolder->isChecked()); @@ -550,6 +619,18 @@ void KdenliveSettingsDialog::updateSettings() saveTranscodeProfiles(); } + m_shuttleModified = false; + + QStringList actions; + actions << "monitor_pause"; // the Job rest position action. + foreach (KComboBox* button, m_shuttle_buttons) { + actions << m_mappable_actions[button->currentText()]; + } + QString maps = JogShuttleConfig::actionMap(actions); + //fprintf(stderr, "Shuttle config: %s\n", JogShuttleConfig::actionMap(actions).toAscii().constData()); + if (KdenliveSettings::shuttlebuttons() != maps) + KdenliveSettings::setShuttlebuttons(maps); + #if KDE_IS_VERSION(4,3,0) KConfigDialog::settingsChangedSlot(); #endif @@ -628,6 +709,20 @@ void KdenliveSettingsDialog::slotDeleteTranscode() slotDialogModified(); } +void KdenliveSettingsDialog::slotShuttleModified() +{ + QStringList actions; + actions << "monitor_pause"; // the Job rest position action. + foreach (KComboBox* button, m_shuttle_buttons) { + actions << m_mappable_actions[button->currentText()]; + } + QString maps = JogShuttleConfig::actionMap(actions); + m_shuttleModified = KdenliveSettings::shuttlebuttons() != maps; +#if KDE_IS_VERSION(4,3,0) + KConfigDialog::updateButtons(); +#endif +} + void KdenliveSettingsDialog::slotDialogModified() { m_modified = true; @@ -639,7 +734,7 @@ void KdenliveSettingsDialog::slotDialogModified() //virtual bool KdenliveSettingsDialog::hasChanged() { - if (m_modified) return true; + if (m_modified || m_shuttleModified) return true; return KConfigDialog::hasChanged(); } diff --git a/src/kdenlivesettingsdialog.h b/src/kdenlivesettingsdialog.h index 3eb3804f..1f06efc7 100644 --- a/src/kdenlivesettingsdialog.h +++ b/src/kdenlivesettingsdialog.h @@ -23,6 +23,7 @@ #include +#include #include #include @@ -40,13 +41,14 @@ class KdenliveSettingsDialog : public KConfigDialog Q_OBJECT public: - KdenliveSettingsDialog(QWidget * parent = 0); + KdenliveSettingsDialog(const QMap& mappable_actions, QWidget * parent = 0); ~KdenliveSettingsDialog(); void showPage(int page, int option); void checkProfile(); protected slots: void updateSettings(); + void updateWidgets(); virtual bool hasChanged(); private slots: @@ -64,6 +66,7 @@ private slots: void slotCheckAlsaDriver(); void slotAddTranscode(); void slotDeleteTranscode(); + void slotShuttleModified(); void slotDialogModified(); void slotEnableCaptureFolder(); void slotUpdateHDMIModes(); @@ -90,6 +93,9 @@ private: QString m_defaultPath; KProcess m_readProcess; bool m_modified; + bool m_shuttleModified; + QMap m_mappable_actions; + QVector m_shuttle_buttons; void initDevices(); void loadTranscodeProfiles(); void saveTranscodeProfiles(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 517acdc3..fe5a3dc9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -42,6 +42,8 @@ #include "audiosignal.h" #ifndef NO_JOGSHUTTLE #include "jogshuttle.h" +#include "jogaction.h" +#include "jogshuttleconfig.h" #endif /* NO_JOGSHUTTLE */ #include "clipproperties.h" #include "wizard.h" @@ -132,6 +134,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_renderWidget(NULL), #ifndef NO_JOGSHUTTLE m_jogProcess(NULL), + m_jogShuttle(NULL), #endif /* NO_JOGSHUTTLE */ m_findActivated(false), m_stopmotion(NULL) @@ -781,52 +784,32 @@ void MainWindow::slotReloadEffects() #ifndef NO_JOGSHUTTLE void MainWindow::activateShuttleDevice() { + delete m_jogShuttle; + m_jogShuttle = NULL; delete m_jogProcess; m_jogProcess = NULL; if (KdenliveSettings::enableshuttle() == false) return; + m_jogProcess = new JogShuttle(KdenliveSettings::shuttledevice()); - connect(m_jogProcess, SIGNAL(rewind1()), m_monitorManager, SLOT(slotRewindOneFrame())); - connect(m_jogProcess, SIGNAL(forward1()), m_monitorManager, SLOT(slotForwardOneFrame())); - connect(m_jogProcess, SIGNAL(rewind(double)), m_monitorManager, SLOT(slotRewind(double))); - connect(m_jogProcess, SIGNAL(forward(double)), m_monitorManager, SLOT(slotForward(double))); - connect(m_jogProcess, SIGNAL(button(int)), this, SLOT(slotShuttleButton(int))); -} - -void MainWindow::slotShuttleButton(int code) -{ - switch (code) { - case 5: - slotShuttleAction(KdenliveSettings::shuttle1()); - break; - case 6: - slotShuttleAction(KdenliveSettings::shuttle2()); - break; - case 7: - slotShuttleAction(KdenliveSettings::shuttle3()); - break; - case 8: - slotShuttleAction(KdenliveSettings::shuttle4()); - break; - case 9: - slotShuttleAction(KdenliveSettings::shuttle5()); - break; - } -} - -void MainWindow::slotShuttleAction(int code) -{ - switch (code) { - case 0: + m_jogShuttle = new JogShuttleAction(m_jogProcess, JogShuttleConfig::actionMap(KdenliveSettings::shuttlebuttons())); + + connect(m_jogShuttle, SIGNAL(rewindOneFrame()), m_monitorManager, SLOT(slotRewindOneFrame())); + connect(m_jogShuttle, SIGNAL(forwardOneFrame()), m_monitorManager, SLOT(slotForwardOneFrame())); + connect(m_jogShuttle, SIGNAL(rewind(double)), m_monitorManager, SLOT(slotRewind(double))); + connect(m_jogShuttle, SIGNAL(forward(double)), m_monitorManager, SLOT(slotForward(double))); + connect(m_jogShuttle, SIGNAL(action(const QString&)), this, SLOT(slotDoAction(const QString&))); +} +#endif /* NO_JOGSHUTTLE */ + +void MainWindow::slotDoAction(const QString& action_name) +{ + QAction* action = actionCollection()->action(action_name); + if (!action) { + fprintf(stderr, "%s", QString("shuttle action '%1' unknown\n").arg(action_name).toAscii().constData()); return; - case 1: - m_monitorManager->slotPlay(); - break; - default: - m_monitorManager->slotPlay(); - break; } + action->trigger(); } -#endif /* NO_JOGSHUTTLE */ void MainWindow::configureNotifications() { @@ -902,10 +885,32 @@ void MainWindow::slotAdjustProjectMonitor() m_projectMonitor->resetSize(); } + +class NameGrabbingKActionCollection { +public: + NameGrabbingKActionCollection(KActionCollection* collection, QStringList& action_names) + : m_collection(collection), m_action_names(action_names) { + m_action_names.clear(); + } + KAction* addAction(const QString& action_name) { + m_action_names << action_name; + return m_collection->addAction(action_name); + } + void addAction(const QString& action_name, QAction* action) { + m_action_names << action_name; + m_collection->addAction(action_name, action); + } + operator KActionCollection*() { return m_collection; } + const QStringList& actionNames() const { return m_action_names; } +private: + KActionCollection* m_collection; + QStringList& m_action_names; +}; + void MainWindow::setupActions() { - KActionCollection* collection = actionCollection(); + NameGrabbingKActionCollection collection(actionCollection(), m_action_names); m_timecodeFormat = new KComboBox(this); m_timecodeFormat->addItem(i18n("hh:mm:ss:ff")); m_timecodeFormat->addItem(i18n("Frames")); @@ -1120,35 +1125,35 @@ void MainWindow::setupActions() statusBar()->addPermanentWidget(m_timecodeFormat); //statusBar()->setMaximumHeight(statusBar()->font().pointSize() * 3); - collection->addAction("normal_mode", m_normalEditTool); - collection->addAction("overwrite_mode", m_overwriteEditTool); - collection->addAction("insert_mode", m_insertEditTool); - collection->addAction("select_tool", m_buttonSelectTool); - collection->addAction("razor_tool", m_buttonRazorTool); - collection->addAction("spacer_tool", m_buttonSpacerTool); - - collection->addAction("automatic_split_audio", m_buttonAutomaticSplitAudio); - collection->addAction("show_video_thumbs", m_buttonVideoThumbs); - collection->addAction("show_audio_thumbs", m_buttonAudioThumbs); - collection->addAction("show_markers", m_buttonShowMarkers); - collection->addAction("snap", m_buttonSnap); - collection->addAction("zoom_fit", m_buttonFitZoom); - collection->addAction("zoom_in", m_zoomIn); - collection->addAction("zoom_out", m_zoomOut); + collection.addAction("normal_mode", m_normalEditTool); + collection.addAction("overwrite_mode", m_overwriteEditTool); + collection.addAction("insert_mode", m_insertEditTool); + collection.addAction("select_tool", m_buttonSelectTool); + collection.addAction("razor_tool", m_buttonRazorTool); + collection.addAction("spacer_tool", m_buttonSpacerTool); + + collection.addAction("automatic_split_audio", m_buttonAutomaticSplitAudio); + collection.addAction("show_video_thumbs", m_buttonVideoThumbs); + collection.addAction("show_audio_thumbs", m_buttonAudioThumbs); + collection.addAction("show_markers", m_buttonShowMarkers); + collection.addAction("snap", m_buttonSnap); + collection.addAction("zoom_fit", m_buttonFitZoom); + collection.addAction("zoom_in", m_zoomIn); + collection.addAction("zoom_out", m_zoomOut); m_projectSearch = new KAction(KIcon("edit-find"), i18n("Find"), this); - collection->addAction("project_find", m_projectSearch); + collection.addAction("project_find", m_projectSearch); connect(m_projectSearch, SIGNAL(triggered(bool)), this, SLOT(slotFind())); m_projectSearch->setShortcut(Qt::Key_Slash); m_projectSearchNext = new KAction(KIcon("go-down-search"), i18n("Find Next"), this); - collection->addAction("project_find_next", m_projectSearchNext); + collection.addAction("project_find_next", m_projectSearchNext); connect(m_projectSearchNext, SIGNAL(triggered(bool)), this, SLOT(slotFindNext())); m_projectSearchNext->setShortcut(Qt::Key_F3); m_projectSearchNext->setEnabled(false); KAction* profilesAction = new KAction(KIcon("document-new"), i18n("Manage Project Profiles"), this); - collection->addAction("manage_profiles", profilesAction); + collection.addAction("manage_profiles", profilesAction); connect(profilesAction, SIGNAL(triggered(bool)), this, SLOT(slotEditProfiles())); KNS3::standardAction(i18n("Download New Wipes..."), this, SLOT(slotGetNewLumaStuff()), actionCollection(), "get_new_lumas"); @@ -1157,24 +1162,24 @@ void MainWindow::setupActions() KNS3::standardAction(i18n("Download New Title Templates..."), this, SLOT(slotGetNewTitleStuff()), actionCollection(), "get_new_titles"); KAction* wizAction = new KAction(KIcon("configure"), i18n("Run Config Wizard"), this); - collection->addAction("run_wizard", wizAction); + collection.addAction("run_wizard", wizAction); connect(wizAction, SIGNAL(triggered(bool)), this, SLOT(slotRunWizard())); KAction* projectAction = new KAction(KIcon("configure"), i18n("Project Settings"), this); - collection->addAction("project_settings", projectAction); + collection.addAction("project_settings", projectAction); connect(projectAction, SIGNAL(triggered(bool)), this, SLOT(slotEditProjectSettings())); KAction* projectRender = new KAction(KIcon("media-record"), i18n("Render"), this); - collection->addAction("project_render", projectRender); + collection.addAction("project_render", projectRender); projectRender->setShortcut(Qt::CTRL + Qt::Key_Return); connect(projectRender, SIGNAL(triggered(bool)), this, SLOT(slotRenderProject())); KAction* projectClean = new KAction(KIcon("edit-clear"), i18n("Clean Project"), this); - collection->addAction("project_clean", projectClean); + collection.addAction("project_clean", projectClean); connect(projectClean, SIGNAL(triggered(bool)), this, SLOT(slotCleanProject())); KAction* projectAdjust = new KAction(KIcon(), i18n("Adjust Profile to Current Clip"), this); - collection->addAction("project_adjust_profile", projectAdjust); + collection.addAction("project_adjust_profile", projectAdjust); connect(projectAdjust, SIGNAL(triggered(bool)), m_projectList, SLOT(adjustProjectProfileToItem())); KAction* monitorPlay = new KAction(KIcon("media-playback-start"), i18n("Play"), this); @@ -1182,153 +1187,157 @@ void MainWindow::setupActions() playShortcut.setPrimary(Qt::Key_Space); playShortcut.setAlternate(Qt::Key_K); monitorPlay->setShortcut(playShortcut); - collection->addAction("monitor_play", monitorPlay); + collection.addAction("monitor_play", monitorPlay); connect(monitorPlay, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotPlay())); + KAction* monitorPause = new KAction(KIcon("media-playback-stop"), i18n("Pause"), this); + collection.addAction("monitor_pause", monitorPause); + connect(monitorPause, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotPause())); + m_playZone = new KAction(KIcon("media-playback-start"), i18n("Play Zone"), this); m_playZone->setShortcut(Qt::CTRL + Qt::Key_Space); - collection->addAction("monitor_play_zone", m_playZone); + collection.addAction("monitor_play_zone", m_playZone); connect(m_playZone, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotPlayZone())); m_loopZone = new KAction(KIcon("media-playback-start"), i18n("Loop Zone"), this); m_loopZone->setShortcut(Qt::ALT + Qt::Key_Space); - collection->addAction("monitor_loop_zone", m_loopZone); + collection.addAction("monitor_loop_zone", m_loopZone); connect(m_loopZone, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotLoopZone())); m_loopClip = new KAction(KIcon("media-playback-start"), i18n("Loop selected clip"), this); m_loopClip->setEnabled(false); - collection->addAction("monitor_loop_clip", m_loopClip); + collection.addAction("monitor_loop_clip", m_loopClip); connect(m_loopClip, SIGNAL(triggered(bool)), m_projectMonitor, SLOT(slotLoopClip())); KAction *dvdWizard = new KAction(KIcon("media-optical"), i18n("DVD Wizard"), this); - collection->addAction("dvd_wizard", dvdWizard); + collection.addAction("dvd_wizard", dvdWizard); connect(dvdWizard, SIGNAL(triggered(bool)), this, SLOT(slotDvdWizard())); KAction *transcodeClip = new KAction(KIcon("edit-copy"), i18n("Transcode Clips"), this); - collection->addAction("transcode_clip", transcodeClip); + collection.addAction("transcode_clip", transcodeClip); connect(transcodeClip, SIGNAL(triggered(bool)), this, SLOT(slotTranscodeClip())); - KAction *markIn = collection->addAction("mark_in"); + KAction *markIn = collection.addAction("mark_in"); markIn->setText(i18n("Set Zone In")); markIn->setShortcut(Qt::Key_I); connect(markIn, SIGNAL(triggered(bool)), this, SLOT(slotSetInPoint())); - KAction *markOut = collection->addAction("mark_out"); + KAction *markOut = collection.addAction("mark_out"); markOut->setText(i18n("Set Zone Out")); markOut->setShortcut(Qt::Key_O); connect(markOut, SIGNAL(triggered(bool)), this, SLOT(slotSetOutPoint())); - KAction *switchMon = collection->addAction("switch_monitor"); + KAction *switchMon = collection.addAction("switch_monitor"); switchMon->setText(i18n("Switch monitor")); switchMon->setShortcut(Qt::Key_T); connect(switchMon, SIGNAL(triggered(bool)), this, SLOT(slotSwitchMonitors())); - KAction *fullMon = collection->addAction("monitor_fullscreen"); + KAction *fullMon = collection.addAction("monitor_fullscreen"); fullMon->setText(i18n("Switch monitor fullscreen")); fullMon->setIcon(KIcon("view-fullscreen")); connect(fullMon, SIGNAL(triggered(bool)), this, SLOT(slotSwitchFullscreen())); - KAction *insertTree = collection->addAction("insert_project_tree"); + KAction *insertTree = collection.addAction("insert_project_tree"); insertTree->setText(i18n("Insert zone in project tree")); insertTree->setShortcut(Qt::CTRL + Qt::Key_I); connect(insertTree, SIGNAL(triggered(bool)), this, SLOT(slotInsertZoneToTree())); - KAction *insertTimeline = collection->addAction("insert_timeline"); + KAction *insertTimeline = collection.addAction("insert_timeline"); insertTimeline->setText(i18n("Insert zone in timeline")); insertTimeline->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_I); connect(insertTimeline, SIGNAL(triggered(bool)), this, SLOT(slotInsertZoneToTimeline())); KAction *resizeStart = new KAction(KIcon(), i18n("Resize Item Start"), this); - collection->addAction("resize_timeline_clip_start", resizeStart); + collection.addAction("resize_timeline_clip_start", resizeStart); resizeStart->setShortcut(Qt::Key_1); connect(resizeStart, SIGNAL(triggered(bool)), this, SLOT(slotResizeItemStart())); KAction *resizeEnd = new KAction(KIcon(), i18n("Resize Item End"), this); - collection->addAction("resize_timeline_clip_end", resizeEnd); + collection.addAction("resize_timeline_clip_end", resizeEnd); resizeEnd->setShortcut(Qt::Key_2); connect(resizeEnd, SIGNAL(triggered(bool)), this, SLOT(slotResizeItemEnd())); KAction* monitorSeekBackward = new KAction(KIcon("media-seek-backward"), i18n("Rewind"), this); monitorSeekBackward->setShortcut(Qt::Key_J); - collection->addAction("monitor_seek_backward", monitorSeekBackward); + collection.addAction("monitor_seek_backward", monitorSeekBackward); connect(monitorSeekBackward, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotRewind())); KAction* monitorSeekBackwardOneFrame = new KAction(KIcon("media-skip-backward"), i18n("Rewind 1 Frame"), this); monitorSeekBackwardOneFrame->setShortcut(Qt::Key_Left); - collection->addAction("monitor_seek_backward-one-frame", monitorSeekBackwardOneFrame); + collection.addAction("monitor_seek_backward-one-frame", monitorSeekBackwardOneFrame); connect(monitorSeekBackwardOneFrame, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotRewindOneFrame())); KAction* monitorSeekBackwardOneSecond = new KAction(KIcon("media-skip-backward"), i18n("Rewind 1 Second"), this); monitorSeekBackwardOneSecond->setShortcut(Qt::SHIFT + Qt::Key_Left); - collection->addAction("monitor_seek_backward-one-second", monitorSeekBackwardOneSecond); + collection.addAction("monitor_seek_backward-one-second", monitorSeekBackwardOneSecond); connect(monitorSeekBackwardOneSecond, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotRewindOneSecond())); KAction* monitorSeekSnapBackward = new KAction(KIcon("media-seek-backward"), i18n("Go to Previous Snap Point"), this); monitorSeekSnapBackward->setShortcut(Qt::ALT + Qt::Key_Left); - collection->addAction("monitor_seek_snap_backward", monitorSeekSnapBackward); + collection.addAction("monitor_seek_snap_backward", monitorSeekSnapBackward); connect(monitorSeekSnapBackward, SIGNAL(triggered(bool)), this, SLOT(slotSnapRewind())); KAction* monitorSeekForward = new KAction(KIcon("media-seek-forward"), i18n("Forward"), this); monitorSeekForward->setShortcut(Qt::Key_L); - collection->addAction("monitor_seek_forward", monitorSeekForward); + collection.addAction("monitor_seek_forward", monitorSeekForward); connect(monitorSeekForward, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotForward())); KAction* clipStart = new KAction(KIcon("media-seek-backward"), i18n("Go to Clip Start"), this); clipStart->setShortcut(Qt::Key_Home); - collection->addAction("seek_clip_start", clipStart); + collection.addAction("seek_clip_start", clipStart); connect(clipStart, SIGNAL(triggered(bool)), this, SLOT(slotClipStart())); KAction* clipEnd = new KAction(KIcon("media-seek-forward"), i18n("Go to Clip End"), this); clipEnd->setShortcut(Qt::Key_End); - collection->addAction("seek_clip_end", clipEnd); + collection.addAction("seek_clip_end", clipEnd); connect(clipEnd, SIGNAL(triggered(bool)), this, SLOT(slotClipEnd())); KAction* zoneStart = new KAction(KIcon("media-seek-backward"), i18n("Go to Zone Start"), this); zoneStart->setShortcut(Qt::SHIFT + Qt::Key_I); - collection->addAction("seek_zone_start", zoneStart); + collection.addAction("seek_zone_start", zoneStart); connect(zoneStart, SIGNAL(triggered(bool)), this, SLOT(slotZoneStart())); KAction* zoneEnd = new KAction(KIcon("media-seek-forward"), i18n("Go to Zone End"), this); zoneEnd->setShortcut(Qt::SHIFT + Qt::Key_O); - collection->addAction("seek_zone_end", zoneEnd); + collection.addAction("seek_zone_end", zoneEnd); connect(zoneEnd, SIGNAL(triggered(bool)), this, SLOT(slotZoneEnd())); KAction* projectStart = new KAction(KIcon("go-first"), i18n("Go to Project Start"), this); projectStart->setShortcut(Qt::CTRL + Qt::Key_Home); - collection->addAction("seek_start", projectStart); + collection.addAction("seek_start", projectStart); connect(projectStart, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotStart())); KAction* projectEnd = new KAction(KIcon("go-last"), i18n("Go to Project End"), this); projectEnd->setShortcut(Qt::CTRL + Qt::Key_End); - collection->addAction("seek_end", projectEnd); + collection.addAction("seek_end", projectEnd); connect(projectEnd, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotEnd())); KAction* monitorSeekForwardOneFrame = new KAction(KIcon("media-skip-forward"), i18n("Forward 1 Frame"), this); monitorSeekForwardOneFrame->setShortcut(Qt::Key_Right); - collection->addAction("monitor_seek_forward-one-frame", monitorSeekForwardOneFrame); + collection.addAction("monitor_seek_forward-one-frame", monitorSeekForwardOneFrame); connect(monitorSeekForwardOneFrame, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotForwardOneFrame())); KAction* monitorSeekForwardOneSecond = new KAction(KIcon("media-skip-forward"), i18n("Forward 1 Second"), this); monitorSeekForwardOneSecond->setShortcut(Qt::SHIFT + Qt::Key_Right); - collection->addAction("monitor_seek_forward-one-second", monitorSeekForwardOneSecond); + collection.addAction("monitor_seek_forward-one-second", monitorSeekForwardOneSecond); connect(monitorSeekForwardOneSecond, SIGNAL(triggered(bool)), m_monitorManager, SLOT(slotForwardOneSecond())); KAction* monitorSeekSnapForward = new KAction(KIcon("media-seek-forward"), i18n("Go to Next Snap Point"), this); monitorSeekSnapForward->setShortcut(Qt::ALT + Qt::Key_Right); - collection->addAction("monitor_seek_snap_forward", monitorSeekSnapForward); + collection.addAction("monitor_seek_snap_forward", monitorSeekSnapForward); connect(monitorSeekSnapForward, SIGNAL(triggered(bool)), this, SLOT(slotSnapForward())); KAction* deleteItem = new KAction(KIcon("edit-delete"), i18n("Delete Selected Item"), this); deleteItem->setShortcut(Qt::Key_Delete); - collection->addAction("delete_timeline_clip", deleteItem); + collection.addAction("delete_timeline_clip", deleteItem); connect(deleteItem, SIGNAL(triggered(bool)), this, SLOT(slotDeleteItem())); /*KAction* editTimelineClipSpeed = new KAction(i18n("Change Clip Speed"), this); - collection->addAction("change_clip_speed", editTimelineClipSpeed); + collection.addAction("change_clip_speed", editTimelineClipSpeed); editTimelineClipSpeed->setData("change_speed"); connect(editTimelineClipSpeed, SIGNAL(triggered(bool)), this, SLOT(slotChangeClipSpeed()));*/ - KAction *stickTransition = collection->addAction("auto_transition"); + KAction *stickTransition = collection.addAction("auto_transition"); stickTransition->setData(QString("auto")); stickTransition->setCheckable(true); stickTransition->setEnabled(false); @@ -1337,104 +1346,104 @@ void MainWindow::setupActions() KAction* groupClip = new KAction(KIcon("object-group"), i18n("Group Clips"), this); groupClip->setShortcut(Qt::CTRL + Qt::Key_G); - collection->addAction("group_clip", groupClip); + collection.addAction("group_clip", groupClip); connect(groupClip, SIGNAL(triggered(bool)), this, SLOT(slotGroupClips())); KAction* ungroupClip = new KAction(KIcon("object-ungroup"), i18n("Ungroup Clips"), this); - collection->addAction("ungroup_clip", ungroupClip); + collection.addAction("ungroup_clip", ungroupClip); ungroupClip->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_G); ungroupClip->setData("ungroup_clip"); connect(ungroupClip, SIGNAL(triggered(bool)), this, SLOT(slotUnGroupClips())); KAction* editItemDuration = new KAction(KIcon("measure"), i18n("Edit Duration"), this); - collection->addAction("edit_item_duration", editItemDuration); + collection.addAction("edit_item_duration", editItemDuration); connect(editItemDuration, SIGNAL(triggered(bool)), this, SLOT(slotEditItemDuration())); KAction* clipInProjectTree = new KAction(KIcon("go-jump-definition"), i18n("Clip in Project Tree"), this); - collection->addAction("clip_in_project_tree", clipInProjectTree); + collection.addAction("clip_in_project_tree", clipInProjectTree); connect(clipInProjectTree, SIGNAL(triggered(bool)), this, SLOT(slotClipInProjectTree())); /*KAction* clipToProjectTree = new KAction(KIcon("go-jump-definition"), i18n("Add Clip to Project Tree"), this); - collection->addAction("clip_to_project_tree", clipToProjectTree); + collection.addAction("clip_to_project_tree", clipToProjectTree); connect(clipToProjectTree, SIGNAL(triggered(bool)), this, SLOT(slotClipToProjectTree()));*/ KAction* insertOvertwrite = new KAction(KIcon(), i18n("Insert Clip Zone in Timeline (Overwrite)"), this); insertOvertwrite->setShortcut(Qt::Key_V); - collection->addAction("overwrite_to_in_point", insertOvertwrite); + collection.addAction("overwrite_to_in_point", insertOvertwrite); connect(insertOvertwrite, SIGNAL(triggered(bool)), this, SLOT(slotInsertClipOverwrite())); KAction* selectTimelineClip = new KAction(KIcon("edit-select"), i18n("Select Clip"), this); selectTimelineClip->setShortcut(Qt::Key_Plus); - collection->addAction("select_timeline_clip", selectTimelineClip); + collection.addAction("select_timeline_clip", selectTimelineClip); connect(selectTimelineClip, SIGNAL(triggered(bool)), this, SLOT(slotSelectTimelineClip())); KAction* deselectTimelineClip = new KAction(KIcon("edit-select"), i18n("Deselect Clip"), this); deselectTimelineClip->setShortcut(Qt::Key_Minus); - collection->addAction("deselect_timeline_clip", deselectTimelineClip); + collection.addAction("deselect_timeline_clip", deselectTimelineClip); connect(deselectTimelineClip, SIGNAL(triggered(bool)), this, SLOT(slotDeselectTimelineClip())); KAction* selectAddTimelineClip = new KAction(KIcon("edit-select"), i18n("Add Clip To Selection"), this); selectAddTimelineClip->setShortcut(Qt::ALT + Qt::Key_Plus); - collection->addAction("select_add_timeline_clip", selectAddTimelineClip); + collection.addAction("select_add_timeline_clip", selectAddTimelineClip); connect(selectAddTimelineClip, SIGNAL(triggered(bool)), this, SLOT(slotSelectAddTimelineClip())); KAction* selectTimelineTransition = new KAction(KIcon("edit-select"), i18n("Select Transition"), this); selectTimelineTransition->setShortcut(Qt::SHIFT + Qt::Key_Plus); - collection->addAction("select_timeline_transition", selectTimelineTransition); + collection.addAction("select_timeline_transition", selectTimelineTransition); connect(selectTimelineTransition, SIGNAL(triggered(bool)), this, SLOT(slotSelectTimelineTransition())); KAction* deselectTimelineTransition = new KAction(KIcon("edit-select"), i18n("Deselect Transition"), this); deselectTimelineTransition->setShortcut(Qt::SHIFT + Qt::Key_Minus); - collection->addAction("deselect_timeline_transition", deselectTimelineTransition); + collection.addAction("deselect_timeline_transition", deselectTimelineTransition); connect(deselectTimelineTransition, SIGNAL(triggered(bool)), this, SLOT(slotDeselectTimelineTransition())); KAction* selectAddTimelineTransition = new KAction(KIcon("edit-select"), i18n("Add Transition To Selection"), this); selectAddTimelineTransition->setShortcut(Qt::ALT + Qt::SHIFT + Qt::Key_Plus); - collection->addAction("select_add_timeline_transition", selectAddTimelineTransition); + collection.addAction("select_add_timeline_transition", selectAddTimelineTransition); connect(selectAddTimelineTransition, SIGNAL(triggered(bool)), this, SLOT(slotSelectAddTimelineTransition())); KAction* cutTimelineClip = new KAction(KIcon("edit-cut"), i18n("Cut Clip"), this); cutTimelineClip->setShortcut(Qt::SHIFT + Qt::Key_R); - collection->addAction("cut_timeline_clip", cutTimelineClip); + collection.addAction("cut_timeline_clip", cutTimelineClip); connect(cutTimelineClip, SIGNAL(triggered(bool)), this, SLOT(slotCutTimelineClip())); KAction* addClipMarker = new KAction(KIcon("bookmark-new"), i18n("Add Marker"), this); - collection->addAction("add_clip_marker", addClipMarker); + collection.addAction("add_clip_marker", addClipMarker); connect(addClipMarker, SIGNAL(triggered(bool)), this, SLOT(slotAddClipMarker())); KAction* deleteClipMarker = new KAction(KIcon("edit-delete"), i18n("Delete Marker"), this); - collection->addAction("delete_clip_marker", deleteClipMarker); + collection.addAction("delete_clip_marker", deleteClipMarker); connect(deleteClipMarker, SIGNAL(triggered(bool)), this, SLOT(slotDeleteClipMarker())); KAction* deleteAllClipMarkers = new KAction(KIcon("edit-delete"), i18n("Delete All Markers"), this); - collection->addAction("delete_all_clip_markers", deleteAllClipMarkers); + collection.addAction("delete_all_clip_markers", deleteAllClipMarkers); connect(deleteAllClipMarkers, SIGNAL(triggered(bool)), this, SLOT(slotDeleteAllClipMarkers())); KAction* editClipMarker = new KAction(KIcon("document-properties"), i18n("Edit Marker"), this); - collection->addAction("edit_clip_marker", editClipMarker); + collection.addAction("edit_clip_marker", editClipMarker); connect(editClipMarker, SIGNAL(triggered(bool)), this, SLOT(slotEditClipMarker())); KAction *addMarkerGuideQuickly = new KAction(KIcon("bookmark-new"), i18n("Add Marker/Guide quickly"), this); addMarkerGuideQuickly->setShortcut(Qt::Key_Asterisk); - collection->addAction("add_marker_guide_quickly", addMarkerGuideQuickly); + collection.addAction("add_marker_guide_quickly", addMarkerGuideQuickly); connect(addMarkerGuideQuickly, SIGNAL(triggered(bool)), this, SLOT(slotAddMarkerGuideQuickly())); KAction* splitAudio = new KAction(KIcon("document-new"), i18n("Split Audio"), this); - collection->addAction("split_audio", splitAudio); + collection.addAction("split_audio", splitAudio); connect(splitAudio, SIGNAL(triggered(bool)), this, SLOT(slotSplitAudio())); KAction* audioOnly = new KAction(KIcon("document-new"), i18n("Audio Only"), this); - collection->addAction("clip_audio_only", audioOnly); + collection.addAction("clip_audio_only", audioOnly); audioOnly->setData("clip_audio_only"); audioOnly->setCheckable(true); KAction* videoOnly = new KAction(KIcon("document-new"), i18n("Video Only"), this); - collection->addAction("clip_video_only", videoOnly); + collection.addAction("clip_video_only", videoOnly); videoOnly->setData("clip_video_only"); videoOnly->setCheckable(true); KAction* audioAndVideo = new KAction(KIcon("document-new"), i18n("Audio and Video"), this); - collection->addAction("clip_audio_and_video", audioAndVideo); + collection.addAction("clip_audio_and_video", audioAndVideo); audioAndVideo->setData("clip_audio_and_video"); audioAndVideo->setCheckable(true); @@ -1446,54 +1455,54 @@ void MainWindow::setupActions() m_clipTypeGroup->setEnabled(false); KAction *insertSpace = new KAction(KIcon(), i18n("Insert Space"), this); - collection->addAction("insert_space", insertSpace); + collection.addAction("insert_space", insertSpace); connect(insertSpace, SIGNAL(triggered()), this, SLOT(slotInsertSpace())); KAction *removeSpace = new KAction(KIcon(), i18n("Remove Space"), this); - collection->addAction("delete_space", removeSpace); + collection.addAction("delete_space", removeSpace); connect(removeSpace, SIGNAL(triggered()), this, SLOT(slotRemoveSpace())); KAction *insertTrack = new KAction(KIcon(), i18n("Insert Track"), this); - collection->addAction("insert_track", insertTrack); + collection.addAction("insert_track", insertTrack); connect(insertTrack, SIGNAL(triggered()), this, SLOT(slotInsertTrack())); KAction *deleteTrack = new KAction(KIcon(), i18n("Delete Track"), this); - collection->addAction("delete_track", deleteTrack); + collection.addAction("delete_track", deleteTrack); connect(deleteTrack, SIGNAL(triggered()), this, SLOT(slotDeleteTrack())); KAction *configTracks = new KAction(KIcon("configure"), i18n("Configure Tracks"), this); - collection->addAction("config_tracks", configTracks); + collection.addAction("config_tracks", configTracks); connect(configTracks, SIGNAL(triggered()), this, SLOT(slotConfigTrack())); KAction *addGuide = new KAction(KIcon("document-new"), i18n("Add Guide"), this); - collection->addAction("add_guide", addGuide); + collection.addAction("add_guide", addGuide); connect(addGuide, SIGNAL(triggered()), this, SLOT(slotAddGuide())); QAction *delGuide = new KAction(KIcon("edit-delete"), i18n("Delete Guide"), this); - collection->addAction("delete_guide", delGuide); + collection.addAction("delete_guide", delGuide); connect(delGuide, SIGNAL(triggered()), this, SLOT(slotDeleteGuide())); QAction *editGuide = new KAction(KIcon("document-properties"), i18n("Edit Guide"), this); - collection->addAction("edit_guide", editGuide); + collection.addAction("edit_guide", editGuide); connect(editGuide, SIGNAL(triggered()), this, SLOT(slotEditGuide())); QAction *delAllGuides = new KAction(KIcon("edit-delete"), i18n("Delete All Guides"), this); - collection->addAction("delete_all_guides", delAllGuides); + collection.addAction("delete_all_guides", delAllGuides); connect(delAllGuides, SIGNAL(triggered()), this, SLOT(slotDeleteAllGuides())); QAction *pasteEffects = new KAction(KIcon("edit-paste"), i18n("Paste Effects"), this); - collection->addAction("paste_effects", pasteEffects); + collection.addAction("paste_effects", pasteEffects); pasteEffects->setData("paste_effects"); connect(pasteEffects , SIGNAL(triggered()), this, SLOT(slotPasteEffects())); QAction *showTimeline = new KAction(i18n("Show Timeline"), this); - collection->addAction("show_timeline", showTimeline); + collection.addAction("show_timeline", showTimeline); showTimeline->setCheckable(true); showTimeline->setChecked(true); connect(showTimeline, SIGNAL(triggered(bool)), this, SLOT(slotShowTimeline(bool))); QAction *showTitleBar = new KAction(i18n("Show Title Bars"), this); - collection->addAction("show_titlebars", showTitleBar); + collection.addAction("show_titlebars", showTitleBar); showTitleBar->setCheckable(true); connect(showTitleBar, SIGNAL(triggered(bool)), this, SLOT(slotShowTitleBars(bool))); showTitleBar->setChecked(KdenliveSettings::showtitlebars()); @@ -1503,7 +1512,7 @@ void MainWindow::setupActions() //const QByteArray state = layoutGroup.readEntry("layout1", QByteArray()); /*QAction *maxCurrent = new KAction(i18n("Maximize Current Widget"), this); - collection->addAction("maximize_current", maxCurrent); + collection.addAction("maximize_current", maxCurrent); maxCurrent->setCheckable(true); maxCurrent->setChecked(false); connect(maxCurrent, SIGNAL(triggered(bool)), this, SLOT(slotMaximizeCurrent(bool)));*/ @@ -1537,55 +1546,55 @@ void MainWindow::setupActions() QAction *addClip = new KAction(KIcon("kdenlive-add-clip"), i18n("Add Clip"), this); - collection->addAction("add_clip", addClip); + collection.addAction("add_clip", addClip); connect(addClip , SIGNAL(triggered()), m_projectList, SLOT(slotAddClip())); QAction *addColorClip = new KAction(KIcon("kdenlive-add-color-clip"), i18n("Add Color Clip"), this); - collection->addAction("add_color_clip", addColorClip); + collection.addAction("add_color_clip", addColorClip); connect(addColorClip , SIGNAL(triggered()), m_projectList, SLOT(slotAddColorClip())); QAction *addSlideClip = new KAction(KIcon("kdenlive-add-slide-clip"), i18n("Add Slideshow Clip"), this); - collection->addAction("add_slide_clip", addSlideClip); + collection.addAction("add_slide_clip", addSlideClip); connect(addSlideClip , SIGNAL(triggered()), m_projectList, SLOT(slotAddSlideshowClip())); QAction *addTitleClip = new KAction(KIcon("kdenlive-add-text-clip"), i18n("Add Title Clip"), this); - collection->addAction("add_text_clip", addTitleClip); + collection.addAction("add_text_clip", addTitleClip); connect(addTitleClip , SIGNAL(triggered()), m_projectList, SLOT(slotAddTitleClip())); QAction *addTitleTemplateClip = new KAction(KIcon("kdenlive-add-text-clip"), i18n("Add Template Title"), this); - collection->addAction("add_text_template_clip", addTitleTemplateClip); + collection.addAction("add_text_template_clip", addTitleTemplateClip); connect(addTitleTemplateClip , SIGNAL(triggered()), m_projectList, SLOT(slotAddTitleTemplateClip())); QAction *addFolderButton = new KAction(KIcon("folder-new"), i18n("Create Folder"), this); - collection->addAction("add_folder", addFolderButton); + collection.addAction("add_folder", addFolderButton); connect(addFolderButton , SIGNAL(triggered()), m_projectList, SLOT(slotAddFolder())); QAction *clipProperties = new KAction(KIcon("document-edit"), i18n("Clip Properties"), this); - collection->addAction("clip_properties", clipProperties); + collection.addAction("clip_properties", clipProperties); clipProperties->setData("clip_properties"); connect(clipProperties , SIGNAL(triggered()), m_projectList, SLOT(slotEditClip())); clipProperties->setEnabled(false); QAction *openClip = new KAction(KIcon("document-open"), i18n("Edit Clip"), this); - collection->addAction("edit_clip", openClip); + collection.addAction("edit_clip", openClip); openClip->setData("edit_clip"); connect(openClip , SIGNAL(triggered()), m_projectList, SLOT(slotOpenClip())); openClip->setEnabled(false); QAction *deleteClip = new KAction(KIcon("edit-delete"), i18n("Delete Clip"), this); - collection->addAction("delete_clip", deleteClip); + collection.addAction("delete_clip", deleteClip); deleteClip->setData("delete_clip"); connect(deleteClip , SIGNAL(triggered()), m_projectList, SLOT(slotRemoveClip())); deleteClip->setEnabled(false); QAction *reloadClip = new KAction(KIcon("view-refresh"), i18n("Reload Clip"), this); - collection->addAction("reload_clip", reloadClip); + collection.addAction("reload_clip", reloadClip); reloadClip->setData("reload_clip"); connect(reloadClip , SIGNAL(triggered()), m_projectList, SLOT(slotReloadClip())); reloadClip->setEnabled(false); QAction *stopMotion = new KAction(KIcon("image-x-generic"), i18n("Stop Motion Capture"), this); - collection->addAction("stopmotion", stopMotion); + collection.addAction("stopmotion", stopMotion); connect(stopMotion , SIGNAL(triggered()), this, SLOT(slotOpenStopmotion())); QMenu *addClips = new QMenu(); @@ -2545,7 +2554,15 @@ void MainWindow::slotPreferences(int page, int option) // KConfigDialog didn't find an instance of this dialog, so lets // create it : - KdenliveSettingsDialog* dialog = new KdenliveSettingsDialog(this); + + // Get the mappable actions in localized form + QMap actions; + KActionCollection* collection = actionCollection(); + foreach (const QString& action_name, m_action_names) { + actions[collection->action(action_name)->text()] = action_name; + } + + KdenliveSettingsDialog* dialog = new KdenliveSettingsDialog(actions, this); connect(dialog, SIGNAL(settingsChanged(const QString&)), this, SLOT(updateConfiguration())); //connect(dialog, SIGNAL(doResetProfile()), this, SLOT(slotDetectAudioDriver())); connect(dialog, SIGNAL(doResetProfile()), m_monitorManager, SLOT(slotResetProfiles())); diff --git a/src/mainwindow.h b/src/mainwindow.h index 4101558f..602441b8 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -59,6 +59,7 @@ class CustomTrackView; class RenderWidget; #ifndef NO_JOGSHUTTLE class JogShuttle; +class JogShuttleAction; #endif /* NO_JOGSHUTTLE */ class DocClipBase; class Render; @@ -205,6 +206,10 @@ private: /** Actions used in the stopmotion widget */ KActionCategory *m_stopmotion_actions; + + /** Action names that can be used in the slotDoAction() slot, with their i18n() names */ + QStringList m_action_names; + /** @brief Shortcut to remove the focus from any element. * @@ -216,6 +221,7 @@ private: #ifndef NO_JOGSHUTTLE JogShuttle *m_jogProcess; + JogShuttleAction* m_jogShuttle; #endif /* NO_JOGSHUTTLE */ KRecentFilesAction *m_fileOpenRecent; @@ -259,7 +265,6 @@ private: void saveOptions(); #ifndef NO_JOGSHUTTLE void activateShuttleDevice(); - void slotShuttleAction(int code); #endif /* NO_JOGSHUTTLE */ void connectDocumentInfo(KdenliveDoc *doc); void findAhead(); @@ -404,9 +409,6 @@ private slots: void slotAddCustomEffect(QAction *result); void slotAddTransition(QAction *result); void slotAddProjectClip(KUrl url); -#ifndef NO_JOGSHUTTLE - void slotShuttleButton(int code); -#endif /* NO_JOGSHUTTLE */ void slotShowClipProperties(DocClipBase *clip); void slotShowClipProperties(QList cliplist, QMap commonproperties); void slotActivateEffectStackView(); @@ -525,7 +527,9 @@ private slots: void slotSwitchFullscreen(); /** @brief Open the stopmotion dialog. */ void slotOpenStopmotion(); - + /** @brief Implements all the actions that are int he ActionsCollection. */ + void slotDoAction(const QString& action_name); + signals: Q_SCRIPTABLE void abortRenderJob(const QString &url); }; diff --git a/src/monitormanager.cpp b/src/monitormanager.cpp index 97c813f7..738a8084 100644 --- a/src/monitormanager.cpp +++ b/src/monitormanager.cpp @@ -87,6 +87,11 @@ void MonitorManager::slotPlay() else m_projectMonitor->slotPlay(); } +void MonitorManager::slotPause() +{ + stopActiveMonitor(); +} + void MonitorManager::slotPlayZone() { if (m_clipMonitor->isActive()) m_clipMonitor->slotPlayZone(); diff --git a/src/monitormanager.h b/src/monitormanager.h index 5f3050d4..aafcd12d 100644 --- a/src/monitormanager.h +++ b/src/monitormanager.h @@ -43,6 +43,7 @@ public slots: * @param name name of the monitor to activate */ void activateMonitor(QString name = QString()); void slotPlay(); + void slotPause(); void slotPlayZone(); void slotLoopZone(); void slotRewind(double speed = 0); diff --git a/src/widgets/configjogshuttle_ui.ui b/src/widgets/configjogshuttle_ui.ui index d3f6c111..1cfe77d0 100644 --- a/src/widgets/configjogshuttle_ui.ui +++ b/src/widgets/configjogshuttle_ui.ui @@ -58,7 +58,7 @@ - + @@ -68,7 +68,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -88,7 +88,7 @@ - + @@ -98,7 +98,7 @@ - +