[kde-doc-english] [calligra] krita: Make the canvas input configurable

Arjen Hiemstra ahiemstra at heimr.nl
Fri Jul 5 17:32:01 UTC 2013


Git commit 122d35ffb499f89429efb96f38a03961132bb7d4 by Arjen Hiemstra.
Committed on 05/07/2013 at 14:41.
Pushed by ahiemstra into branch 'master'.

Make the canvas input configurable

This adds a page to the preferences dialog that allows you to select a
profile and configure the input for that profile.

BUG: 298714
BUG: 298462
BUG: 302478
BUG: 317201
FIXED-IN: 2.8
REVIEW: 111391
GUI: Added a new "Canvas Input Settings" page.
DIGEST: Krita's canva input is now configurable.

M  +1    -0    krita/data/CMakeLists.txt
A  +4    -0    krita/data/input/CMakeLists.txt
A  +45   -0    krita/data/input/kritadefault.profile
M  +21   -0    krita/ui/CMakeLists.txt
M  +10   -0    krita/ui/dialogs/kis_dlg_preferences.cc
M  +2    -0    krita/ui/dialogs/kis_dlg_preferences.h
A  +334  -0    krita/ui/input/config/kis_action_shortcuts_model.cpp     [License: GPL (v2+)]
A  +122  -0    krita/ui/input/config/kis_action_shortcuts_model.h     [License: GPL (v2+)]
A  +88   -0    krita/ui/input/config/kis_edit_profiles_dialog.cpp     [License: GPL (v2+)]
A  +48   -0    krita/ui/input/config/kis_edit_profiles_dialog.h     [License: GPL (v2+)]
A  +88   -0    krita/ui/input/config/kis_edit_profiles_dialog.ui
A  +230  -0    krita/ui/input/config/kis_input_button.cpp     [License: GPL (v2+)]
A  +143  -0    krita/ui/input/config/kis_input_button.h     [License: GPL (v2+)]
A  +92   -0    krita/ui/input/config/kis_input_configuration_page.cpp     [License: GPL (v2+)]
A  +54   -0    krita/ui/input/config/kis_input_configuration_page.h     [License: GPL (v2+)]
A  +100  -0    krita/ui/input/config/kis_input_configuration_page.ui
A  +86   -0    krita/ui/input/config/kis_input_configuration_page_item.cpp     [License: GPL (v2+)]
A  +60   -0    krita/ui/input/config/kis_input_configuration_page_item.h     [License: GPL (v2+)]
A  +94   -0    krita/ui/input/config/kis_input_configuration_page_item.ui
A  +146  -0    krita/ui/input/config/kis_input_editor_delegate.cpp     [License: GPL (v2+)]
A  +46   -0    krita/ui/input/config/kis_input_editor_delegate.h     [License: GPL (v2+)]
A  +80   -0    krita/ui/input/config/kis_input_mode_delegate.cpp     [License: GPL (v2+)]
A  +48   -0    krita/ui/input/config/kis_input_mode_delegate.h     [License: GPL (v2+)]
A  +64   -0    krita/ui/input/config/kis_input_profile_model.cpp     [License: GPL (v2+)]
A  +44   -0    krita/ui/input/config/kis_input_profile_model.h     [License: GPL (v2+)]
A  +75   -0    krita/ui/input/config/kis_input_type_delegate.cpp     [License: GPL (v2+)]
A  +45   -0    krita/ui/input/config/kis_input_type_delegate.h     [License: GPL (v2+)]
A  +77   -0    krita/ui/input/config/kis_key_input_editor.cpp     [License: GPL (v2+)]
A  +54   -0    krita/ui/input/config/kis_key_input_editor.h     [License: GPL (v2+)]
A  +95   -0    krita/ui/input/config/kis_key_input_editor.ui
A  +100  -0    krita/ui/input/config/kis_mouse_input_editor.cpp     [License: GPL (v2+)]
A  +54   -0    krita/ui/input/config/kis_mouse_input_editor.h     [License: GPL (v2+)]
A  +138  -0    krita/ui/input/config/kis_mouse_input_editor.ui
A  +99   -0    krita/ui/input/config/kis_wheel_input_editor.cpp     [License: GPL (v2+)]
A  +56   -0    krita/ui/input/config/kis_wheel_input_editor.h     [License: GPL (v2+)]
A  +138  -0    krita/ui/input/config/kis_wheel_input_editor.ui
M  +11   -5    krita/ui/input/kis_abstract_input_action.cpp
M  +4    -1    krita/ui/input/kis_abstract_input_action.h
M  +2    -3    krita/ui/input/kis_alternate_invocation_action.cpp
M  +1    -1    krita/ui/input/kis_alternate_invocation_action.h
M  +3    -4    krita/ui/input/kis_change_primary_setting_action.cpp
M  +1    -1    krita/ui/input/kis_change_primary_setting_action.h
M  +104  -89   krita/ui/input/kis_input_manager.cpp
M  +1    -0    krita/ui/input/kis_input_manager.h
A  +86   -0    krita/ui/input/kis_input_profile.cpp     [License: GPL (v2+)]
A  +95   -0    krita/ui/input/kis_input_profile.h     [License: GPL (v2+)]
A  +287  -0    krita/ui/input/kis_input_profile_manager.cpp     [License: GPL (v2+)]
A  +141  -0    krita/ui/input/kis_input_profile_manager.h     [License: GPL (v2+)]
M  +3    -2    krita/ui/input/kis_pan_action.cpp
M  +1    -1    krita/ui/input/kis_pan_action.h
M  +4    -2    krita/ui/input/kis_rotate_canvas_action.cpp
M  +1    -1    krita/ui/input/kis_rotate_canvas_action.h
A  +349  -0    krita/ui/input/kis_shortcut_configuration.cpp     [License: GPL (v2+)]
A  +261  -0    krita/ui/input/kis_shortcut_configuration.h     [License: GPL (v2+)]
M  +8    -0    krita/ui/input/kis_shortcut_matcher.cpp
M  +5    -0    krita/ui/input/kis_shortcut_matcher.h
M  +2    -2    krita/ui/input/kis_show_palette_action.cpp
M  +1    -1    krita/ui/input/kis_show_palette_action.h
M  +3    -1    krita/ui/input/kis_single_action_shortcut.h
M  +10   -4    krita/ui/input/kis_tool_invocation_action.cpp
M  +1    -1    krita/ui/input/kis_tool_invocation_action.h
M  +3    -2    krita/ui/input/kis_zoom_action.cpp
M  +1    -1    krita/ui/input/kis_zoom_action.h
M  +9    -0    krita/ui/kis_config.cc
M  +3    -0    krita/ui/kis_config.h
M  +3    -0    krita/ui/kis_view2.cpp
M  +1    -1    krita/ui/tests/kis_input_manager_test.cpp

http://commits.kde.org/calligra/122d35ffb499f89429efb96f38a03961132bb7d4

diff --git a/krita/data/CMakeLists.txt b/krita/data/CMakeLists.txt
index 7b73e52..2b85ff4 100644
--- a/krita/data/CMakeLists.txt
+++ b/krita/data/CMakeLists.txt
@@ -9,6 +9,7 @@ add_subdirectory( cursors )
 add_subdirectory( workspaces )
 add_subdirectory( themes )
 add_subdirectory( predefined_image_sizes )
+add_subdirectory( input )
 ########### install files ###############
 
 install( FILES  
diff --git a/krita/data/input/CMakeLists.txt b/krita/data/input/CMakeLists.txt
new file mode 100644
index 0000000..65bbaad
--- /dev/null
+++ b/krita/data/input/CMakeLists.txt
@@ -0,0 +1,4 @@
+install(FILES
+    kritadefault.profile
+    DESTINATION  ${DATA_INSTALL_DIR}/krita/input
+)
diff --git a/krita/data/input/kritadefault.profile b/krita/data/input/kritadefault.profile
new file mode 100644
index 0000000..e81013c
--- /dev/null
+++ b/krita/data/input/kritadefault.profile
@@ -0,0 +1,45 @@
+[Alternate Invocation]
+0={1;2;[1000021,1000023];1;0;0}
+1={0;2;[1000021];1;0;0}
+
+[Change Primary Setting]
+0={0;2;[1000020];1;0;0}
+
+[General]
+name=Krita Default
+
+[Pan Canvas]
+0={4;1;[1000015];0;0;0}
+1={3;1;[1000013];0;0;0}
+2={2;1;[1000014];0;0;0}
+3={1;1;[1000012];0;0;0}
+4={0;2;[];4;0;0}
+5={0;2;[20];1;0;0}
+
+[Rotate Canvas]
+0={3;1;[36];0;0;0}
+1={4;1;[35];0;0;0}
+2={2;1;[34];0;0;0}
+3={0;2;[1000020];4;0;0}
+4={0;2;[1000020,1000023,20];1;0;0}
+5={0;2;[1000020,20];1;0;0}
+
+[Show Popup Palette]
+0={0;2;[];2;0;0}
+
+[Tool Invocation]
+0={0;2;[];1;0;0}
+1={1;1;[1000004];0;0;0}
+2={2;1;[1000000];0;0;0}
+
+[Zoom Canvas]
+0={6;1;[33];0;0;0}
+1={5;1;[32];0;0;0}
+2={4;1;[31];0;0;0}
+3={3;1;[2d];0;0;0}
+4={2;1;[3d];0;0;0}
+5={3;3;[];0;2;0}
+6={2;3;[];0;1;0}
+7={0;2;[1000021];4;0;0}
+8={1;2;[1000021,1000023,20];1;0;0}
+9={0;2;[1000021,20];1;0;0}
diff --git a/krita/ui/CMakeLists.txt b/krita/ui/CMakeLists.txt
index 6040839..f1a1bf3 100644
--- a/krita/ui/CMakeLists.txt
+++ b/krita/ui/CMakeLists.txt
@@ -222,6 +222,21 @@ set(kritaui_LIB_SRCS
     actions/kis_selection_action_factories.cpp
     kis_document_undo_store.cpp
     kis_transaction_based_command.cpp
+    input/kis_input_profile_manager.cpp
+    input/kis_input_profile.cpp
+    input/kis_shortcut_configuration.cpp
+    input/config/kis_input_configuration_page.cpp
+    input/config/kis_edit_profiles_dialog.cpp
+    input/config/kis_input_profile_model.cpp
+    input/config/kis_input_configuration_page_item.cpp
+    input/config/kis_action_shortcuts_model.cpp
+    input/config/kis_input_type_delegate.cpp
+    input/config/kis_input_mode_delegate.cpp
+    input/config/kis_input_button.cpp
+    input/config/kis_input_editor_delegate.cpp
+    input/config/kis_mouse_input_editor.cpp
+    input/config/kis_wheel_input_editor.cpp
+    input/config/kis_key_input_editor.cpp
 )
 
 if(HAVE_OPENGL)
@@ -282,6 +297,12 @@ kde4_add_ui_files(kritaui_LIB_SRCS
     forms/wdgpresetselectorstrip.ui
     forms/wdgdlgblacklistcleanup.ui
     forms/wdgflipbookselector.ui
+    input/config/kis_input_configuration_page.ui
+    input/config/kis_edit_profiles_dialog.ui
+    input/config/kis_input_configuration_page_item.ui
+    input/config/kis_mouse_input_editor.ui
+    input/config/kis_wheel_input_editor.ui
+    input/config/kis_key_input_editor.ui
 )
 
 kde4_add_library(kritaui SHARED ${kritaui_LIB_SRCS} )
diff --git a/krita/ui/dialogs/kis_dlg_preferences.cc b/krita/ui/dialogs/kis_dlg_preferences.cc
index a0bb001..ffa46dd 100644
--- a/krita/ui/dialogs/kis_dlg_preferences.cc
+++ b/krita/ui/dialogs/kis_dlg_preferences.cc
@@ -87,6 +87,8 @@
 #include <kis_cubic_curve.h>
 #include <config-ocio.h>
 
+#include "input/config/kis_input_configuration_page.h"
+
 
 GeneralTab::GeneralTab(QWidget *_parent, const char *_name)
     : WdgGeneralSettings(_parent, _name)
@@ -677,6 +679,14 @@ KisDlgPreferences::KisDlgPreferences(QWidget* parent, const char* name)
     page->setHeader(i18n("Author"));
     page->setIcon(koIcon("user-identity"));
 
+    m_inputConfiguration = new KisInputConfigurationPage();
+    page = addPage(m_inputConfiguration, i18n("Canvas Input Settings"));
+    page->setHeader(i18n("Canvas Input"));
+    page->setIcon(koIcon("input-tablet"));
+    connect(this, SIGNAL(okClicked()), m_inputConfiguration, SLOT(saveChanges()));
+    connect(this, SIGNAL(applyClicked()), m_inputConfiguration, SLOT(saveChanges()));
+    connect(this, SIGNAL(cancelClicked()), m_inputConfiguration, SLOT(revertChanges()));
+    connect(this, SIGNAL(defaultClicked()), m_inputConfiguration, SLOT(setDefaults()));
 
     KisPreferenceSetRegistry *preferenceSetRegistry = KisPreferenceSetRegistry::instance();
     foreach (KisAbstractPreferenceSetFactory *preferenceSetFactory, preferenceSetRegistry->values()) {
diff --git a/krita/ui/dialogs/kis_dlg_preferences.h b/krita/ui/dialogs/kis_dlg_preferences.h
index ade1912..7a85260 100644
--- a/krita/ui/dialogs/kis_dlg_preferences.h
+++ b/krita/ui/dialogs/kis_dlg_preferences.h
@@ -38,6 +38,7 @@
 
 class KoID;
 class KoConfigAuthorPage;
+class KisInputConfigurationPage;
 
 /**
  *  "General"-tab for preferences dialog
@@ -278,6 +279,7 @@ protected:
     TabletSettingsTab *m_tabletSettings;
     FullscreenSettingsTab *m_fullscreenSettings;
     KoConfigAuthorPage *m_authorSettings;
+    KisInputConfigurationPage *m_inputConfiguration;
 
 protected slots:
 
diff --git a/krita/ui/input/config/kis_action_shortcuts_model.cpp b/krita/ui/input/config/kis_action_shortcuts_model.cpp
new file mode 100644
index 0000000..8de11e8
--- /dev/null
+++ b/krita/ui/input/config/kis_action_shortcuts_model.cpp
@@ -0,0 +1,334 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_action_shortcuts_model.h"
+
+#include <KLocalizedString>
+#include <QMetaClassInfo>
+#include <QKeySequence>
+
+#include "KoIcon.h"
+
+#include "input/kis_abstract_input_action.h"
+#include "input/kis_input_profile.h"
+#include "input/kis_input_profile_manager.h"
+#include "input/kis_shortcut_configuration.h"
+
+class KisActionShortcutsModel::Private
+{
+public:
+    Private() : action(0), profile(0), temporaryShortcut(0) { }
+
+    KisAbstractInputAction *action;
+    KisInputProfile *profile;
+    QList<KisShortcutConfiguration *> shortcuts;
+
+    KisShortcutConfiguration *temporaryShortcut;
+};
+
+KisActionShortcutsModel::KisActionShortcutsModel(QObject *parent)
+    : QAbstractListModel(parent), d(new Private)
+{
+    connect(KisInputProfileManager::instance(), SIGNAL(currentProfileChanged()), SLOT(currentProfileChanged()));
+}
+
+KisActionShortcutsModel::~KisActionShortcutsModel()
+{
+}
+
+QVariant KisActionShortcutsModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid()) {
+        return QVariant();
+    }
+
+    if (index.row() == d->shortcuts.count() && role == Qt::DisplayRole) {
+        if (index.column() == 0) {
+            return i18n("Add shortcut...");
+        }
+        else {
+            return QVariant();
+        }
+    }
+
+    if (role == Qt::DisplayRole) {
+        switch (index.column()) {
+        case 0:
+            switch (d->shortcuts.at(index.row())->type()) {
+            case KisShortcutConfiguration::KeyCombinationType:
+                return i18nc("Shortcut type", "Key Combination");
+
+            case KisShortcutConfiguration::MouseButtonType:
+                return i18nc("Shortcut type", "Mouse Button");
+
+            case KisShortcutConfiguration::MouseWheelType:
+                return i18nc("Shortcut type", "Mouse Wheel");
+
+            case KisShortcutConfiguration::GestureType:
+                return i18nc("Shortcut type", "Gesture");
+
+            default:
+                return i18n("Unknown Input");
+            }
+
+            break;
+
+        case 1: {
+            KisShortcutConfiguration *s = d->shortcuts.at(index.row());
+            QString output;
+
+            switch (s->type()) {
+            case KisShortcutConfiguration::KeyCombinationType:
+                output = KisShortcutConfiguration::keysToText(s->keys());
+                break;
+
+            case KisShortcutConfiguration::MouseButtonType:
+                if (s->keys().size() > 0) {
+                    output.append(KisShortcutConfiguration::keysToText(s->keys()));
+                    output.append(" + ");
+                }
+
+                output.append(KisShortcutConfiguration::buttonsToText(s->buttons()));
+                break;
+
+            case KisShortcutConfiguration::MouseWheelType:
+                if (s->keys().size() > 0) {
+                    output.append(KisShortcutConfiguration::keysToText(s->keys()));
+                    output.append(" + ");
+                }
+
+                output.append(KisShortcutConfiguration::wheelToText(s->wheel()));
+                break;
+
+            default:
+                break;
+            }
+
+            return output;
+        }
+
+        case 2:
+            return d->action->shortcutIndexes().key(d->shortcuts.at(index.row())->mode());
+
+        case 3:
+            return koIcon("edit-delete");
+
+        default:
+            break;
+        }
+    }
+    else if (role == Qt::EditRole) {
+        KisShortcutConfiguration *s;
+
+        if (index.row() == d->shortcuts.count()) {
+            if (!d->temporaryShortcut) {
+                d->temporaryShortcut = new KisShortcutConfiguration;
+            }
+
+            s = d->temporaryShortcut;
+        }
+        else {
+            s = d->shortcuts.at(index.row());
+        }
+
+        switch (index.column()) {
+        case 0:
+            return s->type();
+
+        case 1:
+            return QVariant::fromValue(s);
+
+        case 2:
+            return s->mode();
+
+        default:
+            break;
+        }
+    }
+
+    return QVariant();
+}
+
+int KisActionShortcutsModel::rowCount(const QModelIndex &parent) const
+{
+    if (parent.isValid()) {
+        return 0;
+    }
+
+    return d->shortcuts.count() + 1;
+}
+
+int KisActionShortcutsModel::columnCount(const QModelIndex & /*parent*/) const
+{
+    return 3;
+}
+
+QVariant KisActionShortcutsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+    if (orientation != Qt::Horizontal || role != Qt::DisplayRole) {
+        return QVariant();
+    }
+
+    switch (section) {
+    case 0:
+        return i18nc("Type of shortcut", "Type");
+
+    case 1:
+        return i18nc("Input for shortcut", "Input");
+
+    case 2:
+        return i18nc("Action to trigger with shortcut", "Action");
+
+    default:
+        break;
+    }
+
+    return QVariant();
+}
+
+Qt::ItemFlags KisActionShortcutsModel::flags(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return Qt::ItemIsEnabled;
+    }
+
+    if (index.row() == d->shortcuts.count() && index.column() != 0) {
+        return Qt::ItemIsEnabled;
+    }
+
+    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+}
+
+bool KisActionShortcutsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+    if (!index.isValid() || role != Qt::EditRole) {
+        return false;
+    }
+
+    if (index.row() == d->shortcuts.count()) {
+        if (!d->temporaryShortcut || (index.column() == 0 && value.toUInt() == 0)) {
+            return false;
+        }
+
+        beginInsertRows(QModelIndex(), d->shortcuts.count(), d->shortcuts.count());
+        d->temporaryShortcut->setAction(d->action);
+        d->profile->addShortcut(d->temporaryShortcut);
+        d->shortcuts.append(d->temporaryShortcut);
+        d->temporaryShortcut = 0;
+        endInsertRows();
+    }
+
+    switch (index.column()) {
+    case 0:
+        d->shortcuts.at(index.row())->setType(static_cast<KisShortcutConfiguration::ShortcutType>(value.toUInt()));
+        break;
+
+    case 1: {
+        KisShortcutConfiguration *newData = value.value<KisShortcutConfiguration *>();
+        KisShortcutConfiguration *oldData = d->shortcuts.at(index.row());
+
+        if (newData == oldData)
+            return true;
+
+        oldData->setKeys(newData->keys());
+        oldData->setButtons(newData->buttons());
+        oldData->setWheel(newData->wheel());
+        oldData->setGesture(newData->gesture());
+
+        break;
+    }
+
+    case 2:
+        d->shortcuts.at(index.row())->setMode(value.toUInt());
+        break;
+    }
+
+    return true;
+}
+
+KisAbstractInputAction *KisActionShortcutsModel::action() const
+{
+    return d->action;
+}
+
+void KisActionShortcutsModel::setAction(KisAbstractInputAction *action)
+{
+    if (action != d->action) {
+        if (d->action) {
+            beginRemoveRows(QModelIndex(), 0, d->shortcuts.count() - 1);
+            endRemoveRows();
+        }
+
+        d->action = action;
+
+        if (d->action && d->profile) {
+            d->shortcuts = d->profile->shortcutsForAction(d->action);
+            beginInsertRows(QModelIndex(), 0, d->shortcuts.count() - 1);
+            endInsertRows();
+        }
+    }
+}
+
+KisInputProfile *KisActionShortcutsModel::profile() const
+{
+    return d->profile;
+}
+
+void KisActionShortcutsModel::setProfile(KisInputProfile *profile)
+{
+    if (profile != d->profile) {
+        if (d->profile) {
+            beginRemoveRows(QModelIndex(), 0, d->shortcuts.count() - 1);
+            endRemoveRows();
+        }
+
+        d->profile = profile;
+
+        if (d->action && d->profile) {
+            d->shortcuts = d->profile->shortcutsForAction(d->action);
+            beginInsertRows(QModelIndex(), 0, d->shortcuts.count() - 1);
+            endInsertRows();
+        }
+    }
+}
+
+void KisActionShortcutsModel::currentProfileChanged()
+{
+    setProfile(KisInputProfileManager::instance()->currentProfile());
+}
+
+bool KisActionShortcutsModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+    if (row < 0 || row >= d->shortcuts.count() || count == 0) {
+        return false;
+    }
+
+    beginRemoveRows(parent, row, row + count - 1);
+
+    for (int i = row; i < d->shortcuts.count() && count > 0; ++i, count--) {
+        KisShortcutConfiguration *s = d->shortcuts.at(i);
+        d->profile->removeShortcut(s);
+        d->shortcuts.removeOne(s);
+        delete s;
+    }
+
+    endRemoveRows();
+
+    return true;
+}
diff --git a/krita/ui/input/config/kis_action_shortcuts_model.h b/krita/ui/input/config/kis_action_shortcuts_model.h
new file mode 100644
index 0000000..546cd3b
--- /dev/null
+++ b/krita/ui/input/config/kis_action_shortcuts_model.h
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISACTIONSHORTCUTSMODEL_H
+#define KISACTIONSHORTCUTSMODEL_H
+
+#include <QAbstractListModel>
+
+class KisAbstractInputAction;
+class KisInputProfile;
+
+/**
+ * \brief A QAbstractListModel subclass that lists shortcuts associated with an action from a profile.
+ *
+ * This class lists all shortcuts from the set profile that correspond to a specific action. This is
+ * used to allow editing of shortcuts from the ui.
+ *
+ * It defines the following columns:
+ * - Type:      The type of shortcut, can be one of Key Combination, Mouse Button, Mouse Wheel, Gesture
+ * - Input:     What input is used to activate the shortcut. Depends on the type.
+ * - Action:    What mode of the action will be activated by the shortcut.
+ *
+ * \note Before this model will provide any data you should call setAction and setProfile.
+ * \note This model is editable and provides an implementation of removeRows.
+ */
+class KisActionShortcutsModel : public QAbstractListModel
+{
+    Q_OBJECT
+public:
+    /**
+     * Constructor.
+     */
+    explicit KisActionShortcutsModel(QObject *parent = 0);
+    /**
+     * Destructor.
+     */
+    ~KisActionShortcutsModel();
+
+    /**
+     * Reimplemented from QAbstractItemModel::data()
+     */
+    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+    /**
+     * Reimplemented from QAbstractItemModel::rowCount()
+     */
+    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    /**
+     * Reimplemented from QAbstractItemModel::columnCount()
+     */
+    virtual int columnCount(const QModelIndex &) const;
+    /**
+     * Reimplemented from QAbstractItemModel::headerData()
+     */
+    virtual QVariant headerData(int section, Qt::Orientation orientation, int role =
+                                    Qt::DisplayRole) const;
+    /**
+     * Reimplemented from QAbstractItemModel::flags()
+     */
+    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+    /**
+     * Reimplemented from QAbstractItemModel::setData()
+     */
+    virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+    /**
+     * Reimplemented from QAbstractItemModel::removeRows.
+     *
+     * Removes `count` rows starting at `row`.
+     *
+     * \note The associated shortcuts will also be removed from the profile and completely
+     * deleted.
+     */
+    virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+    /**
+     * \return The action used as data constraint for this model.
+     */
+    KisAbstractInputAction *action() const;
+    /**
+     * \return The profile used as data source for this model.
+     */
+    KisInputProfile *profile() const;
+
+public Q_SLOTS:
+    /**
+     * Set the action used as data constraint for this model.
+     *
+     * \param action The action to use.
+     */
+    void setAction(KisAbstractInputAction *action);
+    /**
+     * Set the profile used as data source for this model.
+     *
+     * \param profile The profile to get the data from.
+     */
+    void setProfile(KisInputProfile *profile);
+
+private Q_SLOTS:
+    void currentProfileChanged();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISACTIONSHORTCUTSMODEL_H
diff --git a/krita/ui/input/config/kis_edit_profiles_dialog.cpp b/krita/ui/input/config/kis_edit_profiles_dialog.cpp
new file mode 100644
index 0000000..4982185
--- /dev/null
+++ b/krita/ui/input/config/kis_edit_profiles_dialog.cpp
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_edit_profiles_dialog.h"
+
+#include <QPushButton>
+#include <QStringListModel>
+#include <KLocalizedString>
+
+#include "KoIcon.h"
+#include "input/kis_input_profile_manager.h"
+#include "kis_input_profile_model.h"
+
+#include "ui_kis_edit_profiles_dialog.h"
+
+class KisEditProfilesDialog::Private
+{
+public:
+    Private() { }
+
+    Ui::KisEditProfilesDialog *ui;
+    KisInputProfileModel *profileModel;
+};
+
+KisEditProfilesDialog::KisEditProfilesDialog(QWidget *parent, Qt::WindowFlags flags)
+    : KDialog(parent, flags), d(new Private())
+{
+    QWidget *mainWidget = new QWidget(this);
+    d->ui = new Ui::KisEditProfilesDialog();
+    d->ui->setupUi(mainWidget);
+    setMainWidget(mainWidget);
+
+    d->profileModel = new KisInputProfileModel(this);
+    d->ui->profileList->setModel(d->profileModel);
+
+    connect(d->ui->addButton, SIGNAL(clicked(bool)), SLOT(addButtonClicked()));
+    connect(d->ui->removeButton, SIGNAL(clicked(bool)), SLOT(removeButtonClicked()));
+    connect(d->ui->duplicateButton, SIGNAL(clicked(bool)), SLOT(duplicateButtonClicked()));
+    connect(d->ui->renameButton, SIGNAL(clicked(bool)), SLOT(renameButtonClicked()));
+
+    setButtons(Close | Default);
+    setWindowTitle(i18n("Edit Profiles"));
+}
+
+KisEditProfilesDialog::~KisEditProfilesDialog()
+{
+    delete d;
+}
+
+void KisEditProfilesDialog::addButtonClicked()
+{
+    QString newProfileName = i18n("New Profile");
+    KisInputProfileManager::instance()->addProfile(newProfileName);
+    d->ui->profileList->edit(d->profileModel->find(newProfileName));
+}
+
+void KisEditProfilesDialog::removeButtonClicked()
+{
+    KisInputProfileManager::instance()->removeProfile(d->profileModel->profileName(d->ui->profileList->currentIndex()));
+}
+
+void KisEditProfilesDialog::duplicateButtonClicked()
+{
+    QString currentName = d->profileModel->profileName(d->ui->profileList->currentIndex());
+    QString newName = i18n("Copy of %1").arg(currentName);
+    KisInputProfileManager::instance()->duplicateProfile(currentName, newName);
+}
+
+void KisEditProfilesDialog::renameButtonClicked()
+{
+    d->ui->profileList->edit(d->ui->profileList->currentIndex());
+}
diff --git a/krita/ui/input/config/kis_edit_profiles_dialog.h b/krita/ui/input/config/kis_edit_profiles_dialog.h
new file mode 100644
index 0000000..a11f0d5
--- /dev/null
+++ b/krita/ui/input/config/kis_edit_profiles_dialog.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISEDITPROFILESDIALOG_H
+#define KISEDITPROFILESDIALOG_H
+
+#include <KDialog>
+
+class QListWidgetItem;
+/**
+ * \brief A dialog that provides facilities to edit all the available profiles.
+ *
+ */
+class KisEditProfilesDialog : public KDialog
+{
+    Q_OBJECT
+public:
+    KisEditProfilesDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+    ~KisEditProfilesDialog();
+
+private Q_SLOTS:
+    void addButtonClicked();
+    void removeButtonClicked();
+    void duplicateButtonClicked();
+    void renameButtonClicked();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISEDITPROFILESDIALOG_H
diff --git a/krita/ui/input/config/kis_edit_profiles_dialog.ui b/krita/ui/input/config/kis_edit_profiles_dialog.ui
new file mode 100644
index 0000000..a831bf9
--- /dev/null
+++ b/krita/ui/input/config/kis_edit_profiles_dialog.ui
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KisEditProfilesDialog</class>
+ <widget class="QWidget" name="KisEditProfilesDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>667</width>
+    <height>682</height>
+   </rect>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="1">
+    <widget class="KPushButton" name="removeButton">
+     <property name="text">
+      <string>Remove</string>
+     </property>
+     <property name="icon">
+      <iconset theme="list-remove">
+       <normaloff/>
+      </iconset>
+     </property>
+     <property name="flat">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="3">
+    <widget class="KPushButton" name="renameButton">
+     <property name="text">
+      <string>Rename</string>
+     </property>
+     <property name="icon">
+      <iconset theme="edit-rename">
+       <normaloff/>
+      </iconset>
+     </property>
+     <property name="flat">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0">
+    <widget class="KPushButton" name="addButton">
+     <property name="text">
+      <string>Add</string>
+     </property>
+     <property name="icon">
+      <iconset theme="list-add">
+       <normaloff/>
+      </iconset>
+     </property>
+     <property name="flat">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <widget class="KPushButton" name="duplicateButton">
+     <property name="text">
+      <string>Duplicate</string>
+     </property>
+     <property name="icon">
+      <iconset theme="edit-copy">
+       <normaloff/>
+      </iconset>
+     </property>
+     <property name="flat">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="4">
+    <widget class="QListView" name="profileList"/>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KPushButton</class>
+   <extends>QPushButton</extends>
+   <header>kpushbutton.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/krita/ui/input/config/kis_input_button.cpp b/krita/ui/input/config/kis_input_button.cpp
new file mode 100644
index 0000000..a31b04a
--- /dev/null
+++ b/krita/ui/input/config/kis_input_button.cpp
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_button.h"
+
+#include <QTimer>
+#include <QMouseEvent>
+#include <QKeyEvent>
+#include <KLocalizedString>
+
+#include "KoIcon.h"
+
+#include "input/kis_shortcut_configuration.h"
+
+class KisInputButton::Private
+{
+public:
+    Private(KisInputButton *qq) : q(qq), type(KeyType), newInput(false), resetTimer(0) { }
+    void updateLabel();
+
+    KisInputButton *q;
+
+    ButtonType type;
+
+    QList<Qt::Key> keys;
+    Qt::MouseButtons buttons;
+    KisShortcutConfiguration::MouseWheelMovement wheel;
+    bool newInput;
+
+    QTimer *resetTimer;
+};
+
+KisInputButton::KisInputButton(QWidget *parent)
+    : KPushButton(parent), d(new Private(this))
+{
+    setIcon(koIcon("configure-shortcuts"));
+    setText(i18nc("No input for this button", "None"));
+    setCheckable(true);
+
+    d->resetTimer = new QTimer(this);
+    d->resetTimer->setInterval(5000);
+    d->resetTimer->setSingleShot(true);
+    connect(d->resetTimer, SIGNAL(timeout()), SLOT(reset()));
+}
+
+KisInputButton::~KisInputButton()
+{
+    delete d;
+}
+
+KisInputButton::ButtonType KisInputButton::type() const
+{
+    return d->type;
+}
+
+void KisInputButton::setType(KisInputButton::ButtonType newType)
+{
+    d->type = newType;
+}
+
+void KisInputButton::clear()
+{
+    d->keys.clear();
+    d->buttons = 0;
+    d->wheel = KisShortcutConfiguration::NoMovement;
+    d->updateLabel();
+}
+
+QList< Qt::Key > KisInputButton::keys() const
+{
+    return d->keys;
+}
+
+void KisInputButton::setKeys(const QList< Qt::Key > &newKeys)
+{
+    if (newKeys != d->keys) {
+        d->keys = newKeys;
+        d->updateLabel();
+    }
+}
+
+Qt::MouseButtons KisInputButton::buttons() const
+{
+    return d->buttons;
+}
+
+void KisInputButton::setButtons(Qt::MouseButtons newButtons)
+{
+    if (newButtons != d->buttons) {
+        d->buttons = newButtons;
+        d->updateLabel();
+    }
+}
+
+KisShortcutConfiguration::MouseWheelMovement KisInputButton::wheel() const
+{
+    return d->wheel;
+}
+
+void KisInputButton::setWheel(KisShortcutConfiguration::MouseWheelMovement newWheel)
+{
+    if (newWheel != d->wheel) {
+        d->wheel = newWheel;
+        d->updateLabel();
+    }
+}
+
+void KisInputButton::mousePressEvent(QMouseEvent *event)
+{
+    if (isChecked()  && d->type == KisInputButton::MouseType) {
+        d->buttons = event->buttons();
+        d->updateLabel();
+        d->resetTimer->start();
+    }
+}
+
+void KisInputButton::mouseReleaseEvent(QMouseEvent *)
+{
+    if (isChecked()) {
+        reset();
+    }
+    else {
+        setChecked(true);
+        setText(i18nc("Waiting for user input", "Input ..."));
+        d->resetTimer->start();
+        d->newInput = true;
+    }
+}
+
+void KisInputButton::wheelEvent(QWheelEvent *event)
+{
+    if (isChecked() && event->delta() != 0) {
+        switch (event->orientation()) {
+        case Qt::Horizontal:
+            if (event->delta() < 0) {
+                d->wheel = KisShortcutConfiguration::WheelRight;
+            }
+            else {
+                d->wheel = KisShortcutConfiguration::WheelLeft;
+            }
+
+            break;
+
+        case Qt::Vertical:
+            if (event->delta() > 0) {
+                d->wheel = KisShortcutConfiguration::WheelUp;
+            }
+            else {
+                d->wheel = KisShortcutConfiguration::WheelDown;
+            }
+
+            break;
+        }
+
+        d->updateLabel();
+    }
+}
+
+void KisInputButton::keyPressEvent(QKeyEvent *event)
+{
+    if (isChecked()) {
+        if (d->newInput) {
+            d->keys.clear();
+            d->newInput = false;
+        }
+
+        Qt::Key key = static_cast<Qt::Key>(event->key());
+
+        if (key == Qt::Key_Meta && event->modifiers().testFlag(Qt::ShiftModifier)) {
+            key = Qt::Key_Alt;
+        }
+
+        d->keys.append(key);
+        d->updateLabel();
+        d->resetTimer->start();
+    }
+}
+
+void KisInputButton::keyReleaseEvent(QKeyEvent *event)
+{
+    if (isChecked()) {
+        reset();
+    }
+    else if (event->key() == Qt::Key_Space || event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
+        setChecked(true);
+        setText(i18nc("Waiting for user input", "Input ..."));
+        d->resetTimer->start();
+        d->newInput = true;
+    }
+}
+
+void KisInputButton::reset()
+{
+    setChecked(false);
+    d->updateLabel();
+    emit dataChanged();
+}
+
+void KisInputButton::Private::updateLabel()
+{
+    switch (type) {
+    case MouseType:
+        q->setText(KisShortcutConfiguration::buttonsToText(buttons));
+        break;
+
+    case KeyType:
+        q->setText(KisShortcutConfiguration::keysToText(keys));
+        break;
+
+    case WheelType:
+        q->setText(KisShortcutConfiguration::wheelToText(wheel));
+        break;
+    }
+}
diff --git a/krita/ui/input/config/kis_input_button.h b/krita/ui/input/config/kis_input_button.h
new file mode 100644
index 0000000..19db3a5
--- /dev/null
+++ b/krita/ui/input/config/kis_input_button.h
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTBUTTON_H
+#define KISINPUTBUTTON_H
+
+#include <KPushButton>
+
+#include "input/kis_shortcut_configuration.h"
+
+/**
+ * \brief A button that can detect input and will store its value.
+ *
+ * This button, when pressed, will detect input based on what type has been set.
+ * It is mainly intended for shortcut configuration, that is, picking some input that is
+ * later reused for shortcuts or similar.
+ *
+ */
+class KisInputButton : public KPushButton
+{
+    Q_OBJECT
+public:
+    /**
+     * The type of button.
+     */
+    enum ButtonType {
+        MouseType, ///< Detect and store any combination of pressed mouse buttons.
+        KeyType, ///< Detect and store any combination of key presses.
+        WheelType, ///< Detect and store mouse wheel movement.
+    };
+
+    /**
+     * Constructor.
+     */
+    explicit KisInputButton(QWidget *parent = 0);
+    /**
+     * Destructor.
+     */
+    virtual ~KisInputButton();
+
+    /**
+     * \return The type of input this button detects.
+     */
+    ButtonType type() const;
+    /**
+     * Set the type of input this button should detect.
+     *
+     * \param newType The type of input to detect.
+     */
+    void setType(ButtonType newType);
+
+    /**
+     * \return The list of keys that was detected. Only applicable when type is `KeyType`.
+     */
+    QList<Qt::Key> keys() const;
+    /**
+     * Set the list of keys to display.
+     *
+     * This is mostly intended to make sure the button displays the right keys when viewed
+     * in a dialog or similar UI.
+     *
+     * Only applicable when type is `KeyType`.
+     *
+     * \param newKeys The list of keys to display.
+     */
+    void setKeys(const QList<Qt::Key> &newKeys);
+
+    /**
+     * \return The mouse buttons that were detected. Only applicable when type is `MouseType`.
+     */
+    Qt::MouseButtons buttons() const;
+    /**
+     * Set the mouse buttons to display.
+     *
+     * This is mostly intended to make sure the button displays the right buttons when viewed
+     * in a dialog or similar UI.
+     *
+     * Only applicable when type is `MouseType`.
+     *
+     * \param newButtons The mouse buttons to display.
+     */
+    void setButtons(Qt::MouseButtons newButtons);
+
+    /**
+     * \return The mouse wheel movement that was detected. Only applicable when type is `WheelType`.
+     */
+    KisShortcutConfiguration::MouseWheelMovement wheel() const;
+    /**
+     * Set the mouse wheel movement to display.
+     *
+     * This is mostly intended to make sure the button displays the right wheel movement when
+     * viewed in a dialog or similar UI.
+     *
+     * Only applicable when type is `WheelType`.
+     *
+     * \param newButtons The wheel movement to display.
+     */
+    void setWheel(KisShortcutConfiguration::MouseWheelMovement wheel);
+
+public Q_SLOTS:
+    /**
+     * Clear all detected input and reset the button to an empty state.
+     */
+    void clear();
+
+Q_SIGNALS:
+    /**
+     * Emitted whenever one of the values (keys, buttons, wheel) changes.
+     */
+    void dataChanged();
+
+protected:
+    virtual void mousePressEvent(QMouseEvent *event);
+    virtual void mouseReleaseEvent(QMouseEvent *);
+    virtual void wheelEvent(QWheelEvent *event);
+    virtual void keyPressEvent(QKeyEvent *event);
+    virtual void keyReleaseEvent(QKeyEvent *event);
+
+private Q_SLOTS:
+    void reset();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISINPUTBUTTON_H
diff --git a/krita/ui/input/config/kis_input_configuration_page.cpp b/krita/ui/input/config/kis_input_configuration_page.cpp
new file mode 100644
index 0000000..b440056
--- /dev/null
+++ b/krita/ui/input/config/kis_input_configuration_page.cpp
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_configuration_page.h"
+#include "ui_kis_input_configuration_page.h"
+
+#include "input/kis_input_profile_manager.h"
+#include "input/kis_input_profile.h"
+#include "kis_edit_profiles_dialog.h"
+#include "kis_input_profile_model.h"
+#include "kis_input_configuration_page_item.h"
+#include <QDir>
+#include <KStandardDirs>
+
+KisInputConfigurationPage::KisInputConfigurationPage(QWidget *parent, Qt::WindowFlags f)
+    : QWidget(parent, f)
+{
+    ui = new Ui::KisInputConfigurationPage;
+    ui->setupUi(this);
+
+    ui->profileComboBox->setModel(new KisInputProfileModel(ui->profileComboBox));
+    updateSelectedProfile();
+    connect(ui->profileComboBox, SIGNAL(currentIndexChanged(QString)), SLOT(changeCurrentProfile(QString)));
+
+    connect(ui->editProfilesButton, SIGNAL(clicked(bool)), SLOT(editProfilesButtonClicked()));
+    connect(KisInputProfileManager::instance(), SIGNAL(profilesChanged()), SLOT(updateSelectedProfile()));
+
+    QList<KisAbstractInputAction *> actions = KisInputProfileManager::instance()->actions();
+    Q_FOREACH(KisAbstractInputAction * action, actions) {
+        KisInputConfigurationPageItem *item = new KisInputConfigurationPageItem(this);
+        item->setAction(action);
+        ui->configurationItemsArea->addWidget(item);
+    }
+}
+
+void KisInputConfigurationPage::saveChanges()
+{
+    KisInputProfileManager::instance()->saveProfiles();
+}
+
+void KisInputConfigurationPage::revertChanges()
+{
+    KisInputProfileManager::instance()->loadProfiles();
+}
+
+void KisInputConfigurationPage::setDefaults()
+{
+    QDir profileDir(KGlobal::dirs()->saveLocation("appdata", "input/", false));
+
+    if (profileDir.exists()) {
+        QStringList entries = profileDir.entryList(QStringList() << "*.profile", QDir::NoDot | QDir::NoDotDot);
+        Q_FOREACH(const QString & file, entries) {
+            profileDir.remove(file);
+        }
+
+        KisInputProfileManager::instance()->loadProfiles();
+    }
+}
+
+void KisInputConfigurationPage::editProfilesButtonClicked()
+{
+    KisEditProfilesDialog dialog;
+    dialog.exec();
+}
+
+void KisInputConfigurationPage::updateSelectedProfile()
+{
+    if (KisInputProfileManager::instance()->currentProfile()) {
+        ui->profileComboBox->setCurrentItem(KisInputProfileManager::instance()->currentProfile()->name());
+    }
+}
+
+void KisInputConfigurationPage::changeCurrentProfile(const QString &newProfile)
+{
+    KisInputProfileManager::instance()->setCurrentProfile(KisInputProfileManager::instance()->profile(newProfile));
+}
diff --git a/krita/ui/input/config/kis_input_configuration_page.h b/krita/ui/input/config/kis_input_configuration_page.h
new file mode 100644
index 0000000..45339fd
--- /dev/null
+++ b/krita/ui/input/config/kis_input_configuration_page.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTCONFIGURATIONPAGE_H
+#define KISINPUTCONFIGURATIONPAGE_H
+
+#include <QWidget>
+
+namespace Ui
+{
+class KisInputConfigurationPage;
+}
+
+/**
+ * \brief A Configuration Dialog Page to configure the canvas input.
+ */
+class KisInputConfigurationPage : public QWidget
+{
+    Q_OBJECT
+public:
+    KisInputConfigurationPage(QWidget *parent = 0, Qt::WindowFlags f = 0);
+
+public Q_SLOTS:
+    void saveChanges();
+    void revertChanges();
+    void setDefaults();
+
+private Q_SLOTS:
+    void editProfilesButtonClicked();
+    void updateSelectedProfile();
+    void changeCurrentProfile(const QString &newProfile);
+
+private:
+    Ui::KisInputConfigurationPage *ui;
+
+};
+
+#endif // KISINPUTCONFIGURATIONPAGE_H
diff --git a/krita/ui/input/config/kis_input_configuration_page.ui b/krita/ui/input/config/kis_input_configuration_page.ui
new file mode 100644
index 0000000..d5a9cb3
--- /dev/null
+++ b/krita/ui/input/config/kis_input_configuration_page.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KisInputConfigurationPage</class>
+ <widget class="QWidget" name="KisInputConfigurationPage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1016</width>
+    <height>979</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Profile</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="KComboBox" name="profileComboBox">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="editable">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="KPushButton" name="editProfilesButton">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="toolTip">
+        <string>Duplicate current profile</string>
+       </property>
+       <property name="text">
+        <string>Edit Profiles</string>
+       </property>
+       <property name="icon">
+        <iconset theme="document-edit">
+         <normaloff/>
+        </iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>18</width>
+         <height>20</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QVBoxLayout" name="configurationItemsArea"/>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KComboBox</class>
+   <extends>QComboBox</extends>
+   <header>kcombobox.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KPushButton</class>
+   <extends>QPushButton</extends>
+   <header>kpushbutton.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/krita/ui/input/config/kis_input_configuration_page_item.cpp b/krita/ui/input/config/kis_input_configuration_page_item.cpp
new file mode 100644
index 0000000..e3c03e3
--- /dev/null
+++ b/krita/ui/input/config/kis_input_configuration_page_item.cpp
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_configuration_page_item.h"
+
+#include "KoIcon.h"
+
+#include "input/kis_abstract_input_action.h"
+#include "input/kis_input_profile_manager.h"
+#include "kis_action_shortcuts_model.h"
+#include "kis_input_type_delegate.h"
+#include "kis_input_mode_delegate.h"
+#include "kis_input_editor_delegate.h"
+#include "ui_kis_input_configuration_page_item.h"
+
+KisInputConfigurationPageItem::KisInputConfigurationPageItem(QWidget *parent, Qt::WindowFlags f)
+    : QWidget(parent, f)
+{
+    ui = new Ui::KisInputConfigurationPageItem;
+    ui->setupUi(this);
+
+    m_shortcutsModel = new KisActionShortcutsModel(this);
+    ui->shortcutsView->setModel(m_shortcutsModel);
+    ui->shortcutsView->setItemDelegateForColumn(0, new KisInputTypeDelegate(ui->shortcutsView));
+    ui->shortcutsView->setItemDelegateForColumn(1, new KisInputEditorDelegate(ui->shortcutsView));
+    ui->shortcutsView->setItemDelegateForColumn(2, new KisInputModeDelegate(ui->shortcutsView));
+    ui->shortcutsView->header()->setResizeMode(QHeaderView::Stretch);
+    setExpanded(false);
+
+    QAction *deleteAction = new QAction(koIcon("edit-delete"), i18n("Delete Shortcut"), ui->shortcutsView);
+    connect(deleteAction, SIGNAL(triggered(bool)), SLOT(deleteShortcut()));
+    ui->shortcutsView->addAction(deleteAction);
+    ui->shortcutsView->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+    connect(ui->collapseButton, SIGNAL(clicked(bool)), SLOT(setExpanded(bool)));
+}
+
+KisInputConfigurationPageItem::~KisInputConfigurationPageItem()
+{
+    delete ui;
+}
+
+void KisInputConfigurationPageItem::setAction(KisAbstractInputAction *action)
+{
+    m_action = action;
+    ui->collapseButton->setText(action->name());
+    ui->descriptionLabel->setText(action->description());
+    m_shortcutsModel->setProfile(KisInputProfileManager::instance()->currentProfile());
+    m_shortcutsModel->setAction(action);
+    qobject_cast<KisInputModeDelegate *>(ui->shortcutsView->itemDelegateForColumn(2))->setAction(action);
+}
+
+void KisInputConfigurationPageItem::setExpanded(bool expand)
+{
+    if (expand) {
+        ui->descriptionLabel->setVisible(true);
+        ui->shortcutsView->setVisible(true);
+        ui->collapseButton->setArrowType(Qt::DownArrow);
+    }
+    else {
+        ui->descriptionLabel->setVisible(false);
+        ui->shortcutsView->setVisible(false);
+        ui->collapseButton->setArrowType(Qt::RightArrow);
+    }
+}
+
+void KisInputConfigurationPageItem::deleteShortcut()
+{
+    m_shortcutsModel->removeRow(ui->shortcutsView->selectionModel()->currentIndex().row(), QModelIndex());
+}
diff --git a/krita/ui/input/config/kis_input_configuration_page_item.h b/krita/ui/input/config/kis_input_configuration_page_item.h
new file mode 100644
index 0000000..25f2f1e
--- /dev/null
+++ b/krita/ui/input/config/kis_input_configuration_page_item.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTCONFIGURATIONPAGEITEM_H
+#define KISINPUTCONFIGURATIONPAGEITEM_H
+
+#include <QWidget>
+
+namespace Ui
+{
+class KisInputConfigurationPageItem;
+}
+
+class KisActionShortcutsModel;
+class QModelIndex;
+class KisAbstractInputAction;
+/**
+ * \brief A collapsible widget displaying an action, its description and associated shortcuts.
+ *
+ * This is used in KisInputConfigurationPage to display a list of actions and the associated
+ * shortcuts, depending on the current profile.
+ */
+class KisInputConfigurationPageItem : public QWidget
+{
+    Q_OBJECT
+public:
+    KisInputConfigurationPageItem(QWidget *parent = 0, Qt::WindowFlags f = 0);
+    ~KisInputConfigurationPageItem();
+
+    void setAction(KisAbstractInputAction *action);
+
+public Q_SLOTS:
+    void setExpanded(bool expand);
+
+private Q_SLOTS:
+    void deleteShortcut();
+
+private:
+    Ui::KisInputConfigurationPageItem *ui;
+    KisAbstractInputAction *m_action;
+    KisActionShortcutsModel *m_shortcutsModel;
+};
+
+#endif // KISINPUTCONFIGURATIONPAGEITEM_H
diff --git a/krita/ui/input/config/kis_input_configuration_page_item.ui b/krita/ui/input/config/kis_input_configuration_page_item.ui
new file mode 100644
index 0000000..e9a41fb
--- /dev/null
+++ b/krita/ui/input/config/kis_input_configuration_page_item.ui
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KisInputConfigurationPageItem</class>
+ <widget class="QWidget" name="KisInputConfigurationPageItem">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>605</width>
+    <height>330</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="1" column="1" colspan="2">
+    <widget class="QLabel" name="descriptionLabel">
+     <property name="text">
+      <string><html><head/><body><p>Action Description</p></body></html></string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="0" column="0" colspan="3">
+    <widget class="QToolButton" name="collapseButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="font">
+      <font>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>Action Name</string>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+     <property name="toolButtonStyle">
+      <enum>Qt::ToolButtonTextBesideIcon</enum>
+     </property>
+     <property name="autoRaise">
+      <bool>true</bool>
+     </property>
+     <property name="arrowType">
+      <enum>Qt::RightArrow</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1" colspan="2">
+    <widget class="QTreeView" name="shortcutsView">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="itemsExpandable">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/krita/ui/input/config/kis_input_editor_delegate.cpp b/krita/ui/input/config/kis_input_editor_delegate.cpp
new file mode 100644
index 0000000..b5bd3df
--- /dev/null
+++ b/krita/ui/input/config/kis_input_editor_delegate.cpp
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_editor_delegate.h"
+
+#include <QApplication>
+
+#include <KLocalizedString>
+
+#include "input/kis_input_profile.h"
+#include "input/kis_shortcut_configuration.h"
+#include "kis_input_button.h"
+#include "kis_mouse_input_editor.h"
+#include "kis_wheel_input_editor.h"
+#include "kis_key_input_editor.h"
+
+class KisInputEditorDelegate::Private
+{
+public:
+    Private() { }
+};
+
+KisInputEditorDelegate::KisInputEditorDelegate(QObject *parent)
+    : QStyledItemDelegate(parent), d(new Private())
+{
+}
+
+KisInputEditorDelegate::~KisInputEditorDelegate()
+{
+    delete d;
+
+}
+
+QWidget *KisInputEditorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
+{
+    KPushButton *editor = 0;
+    KisShortcutConfiguration *s = index.data(Qt::EditRole).value<KisShortcutConfiguration *>();
+
+    switch (s->type()) {
+    case KisShortcutConfiguration::KeyCombinationType:
+        editor = new KisKeyInputEditor(parent);
+        break;
+
+    case KisShortcutConfiguration::MouseButtonType:
+        editor = new KisMouseInputEditor(parent);
+        break;
+
+    case KisShortcutConfiguration::MouseWheelType:
+        editor = new KisWheelInputEditor(parent);
+        break;
+
+    default:
+        break;
+    }
+
+    return editor;
+}
+
+void KisInputEditorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+    KisShortcutConfiguration *s = index.model()->data(index, Qt::EditRole).value<KisShortcutConfiguration *>();
+
+    switch (s->type()) {
+    case KisShortcutConfiguration::KeyCombinationType: {
+        KisKeyInputEditor *e = qobject_cast<KisKeyInputEditor *>(editor);
+        e->setKeys(s->keys());
+        break;
+    }
+
+    case KisShortcutConfiguration::MouseButtonType: {
+        KisMouseInputEditor *e = qobject_cast<KisMouseInputEditor *>(editor);
+        e->setKeys(s->keys());
+        e->setButtons(s->buttons());
+        break;
+    }
+
+    case KisShortcutConfiguration::MouseWheelType: {
+        KisWheelInputEditor *e = qobject_cast<KisWheelInputEditor *>(editor);
+        e->setKeys(s->keys());
+        e->setWheel(s->wheel());
+        break;
+    }
+
+    default:
+        break;
+    }
+}
+
+void KisInputEditorDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+    KisShortcutConfiguration *s = model->data(index, Qt::EditRole).value<KisShortcutConfiguration *>();
+
+    switch (s->type()) {
+    case KisShortcutConfiguration::KeyCombinationType: {
+        KisKeyInputEditor *e = qobject_cast<KisKeyInputEditor *>(editor);
+        s->setKeys(e->keys());
+        break;
+    }
+
+    case KisShortcutConfiguration::MouseButtonType: {
+        KisMouseInputEditor *e = qobject_cast<KisMouseInputEditor *>(editor);
+        s->setKeys(e->keys());
+        s->setButtons(e->buttons());
+        break;
+    }
+
+    case KisShortcutConfiguration::MouseWheelType: {
+        KisWheelInputEditor *e = qobject_cast<KisWheelInputEditor *>(editor);
+        s->setKeys(e->keys());
+        s->setWheel(e->wheel());
+        break;
+    }
+    break;
+
+    default:
+        break;
+    }
+
+    model->setData(index, QVariant::fromValue(s), Qt::EditRole);
+}
+
+void KisInputEditorDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
+{
+    editor->setGeometry(option.rect);
+}
+
+QSize KisInputEditorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    return QStyledItemDelegate::sizeHint(option, index) + QSize(6, 6);
+}
diff --git a/krita/ui/input/config/kis_input_editor_delegate.h b/krita/ui/input/config/kis_input_editor_delegate.h
new file mode 100644
index 0000000..fbc38a8
--- /dev/null
+++ b/krita/ui/input/config/kis_input_editor_delegate.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTEDITORDELEGATE_H
+#define KISINPUTEDITORDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+/**
+ * \brief A delegate providing editors for the keys/buttons/etc. of KisShortcutConfiguration.
+ */
+class KisInputEditorDelegate : public QStyledItemDelegate
+{
+    Q_OBJECT
+public:
+    KisInputEditorDelegate(QObject *parent = 0);
+    ~KisInputEditorDelegate();
+
+    virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const;
+    virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
+    virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
+    virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const;
+    virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISINPUTEDITORDELEGATE_H
diff --git a/krita/ui/input/config/kis_input_mode_delegate.cpp b/krita/ui/input/config/kis_input_mode_delegate.cpp
new file mode 100644
index 0000000..2e161f1
--- /dev/null
+++ b/krita/ui/input/config/kis_input_mode_delegate.cpp
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_mode_delegate.h"
+#include "../kis_abstract_input_action.h"
+
+#include <KComboBox>
+#include <KLocalizedString>
+
+class KisInputModeDelegate::Private
+{
+public:
+    Private() { }
+
+    KisAbstractInputAction *action;
+};
+
+KisInputModeDelegate::KisInputModeDelegate(QObject *parent)
+    : QStyledItemDelegate(parent), d(new Private)
+{
+}
+
+KisInputModeDelegate::~KisInputModeDelegate()
+{
+    delete d;
+
+}
+
+QWidget *KisInputModeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
+{
+    KComboBox *combo = new KComboBox(parent);
+    QStringList sorted = d->action->shortcutIndexes().keys();
+    qSort(sorted);
+    combo->addItems(sorted);
+    return combo;
+}
+
+void KisInputModeDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+    KComboBox *combo = qobject_cast<KComboBox *>(editor);
+    Q_ASSERT(combo);
+
+    int i = combo->findText(d->action->shortcutIndexes().key(index.data(Qt::EditRole).toUInt()));
+    combo->setCurrentIndex(i);
+}
+
+void KisInputModeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+    KComboBox *combo = qobject_cast<KComboBox *>(editor);
+    Q_ASSERT(combo);
+
+    int i = d->action->shortcutIndexes().value(combo->currentText());
+    model->setData(index, i, Qt::EditRole);
+}
+
+void KisInputModeDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
+{
+    editor->setGeometry(option.rect);
+}
+
+void KisInputModeDelegate::setAction(KisAbstractInputAction *action)
+{
+    d->action = action;
+}
diff --git a/krita/ui/input/config/kis_input_mode_delegate.h b/krita/ui/input/config/kis_input_mode_delegate.h
new file mode 100644
index 0000000..c25908d
--- /dev/null
+++ b/krita/ui/input/config/kis_input_mode_delegate.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTMODEDELEGATE_H
+#define KISINPUTMODEDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+class KisAbstractInputAction;
+/**
+ * \brief A delegate providing editors for the mode property of KisShortcutConfiguration.
+ */
+class KisInputModeDelegate : public QStyledItemDelegate
+{
+    Q_OBJECT
+public:
+    explicit KisInputModeDelegate(QObject *parent = 0);
+    ~KisInputModeDelegate();
+
+    virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const;
+    virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
+    virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
+    virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const;
+
+    void setAction(KisAbstractInputAction *action);
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISINPUTMODEDELEGATE_H
diff --git a/krita/ui/input/config/kis_input_profile_model.cpp b/krita/ui/input/config/kis_input_profile_model.cpp
new file mode 100644
index 0000000..d7ea00f
--- /dev/null
+++ b/krita/ui/input/config/kis_input_profile_model.cpp
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_profile_model.h"
+
+#include "input/kis_input_profile_manager.h"
+
+KisInputProfileModel::KisInputProfileModel(QObject *parent)
+    : QStringListModel(parent)
+{
+    setStringList(KisInputProfileManager::instance()->profileNames());
+    connect(KisInputProfileManager::instance(), SIGNAL(profilesChanged()), SLOT(profileNamesChanged()));
+}
+
+KisInputProfileModel::~KisInputProfileModel()
+{
+
+}
+
+void KisInputProfileModel::profileNamesChanged()
+{
+    setStringList(KisInputProfileManager::instance()->profileNames());
+}
+
+bool KisInputProfileModel::setData(const QModelIndex &index, const QVariant &value, int /*role*/)
+{
+    QString oldName = profileName(index);
+    return KisInputProfileManager::instance()->renameProfile(oldName, value.toString());
+}
+
+QString KisInputProfileModel::profileName(const QModelIndex &index)
+{
+    return data(index, Qt::DisplayRole).toString();
+}
+
+QModelIndex KisInputProfileModel::find(const QString &name)
+{
+    for (int i = 0; i < rowCount(); ++i) {
+        QModelIndex ind = index(i, 0);
+
+        if (profileName(ind) == name) {
+            return ind;
+        }
+    }
+
+    return QModelIndex();
+}
+
diff --git a/krita/ui/input/config/kis_input_profile_model.h b/krita/ui/input/config/kis_input_profile_model.h
new file mode 100644
index 0000000..58f208a
--- /dev/null
+++ b/krita/ui/input/config/kis_input_profile_model.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTPROFILEMODEL_H
+#define KISINPUTPROFILEMODEL_H
+
+#include <QStringListModel>
+
+/**
+ * \brief A model providing a list of profiles available.
+ */
+class KisInputProfileModel : public QStringListModel
+{
+    Q_OBJECT
+public:
+    KisInputProfileModel(QObject *parent = 0);
+    ~KisInputProfileModel();
+
+    virtual bool setData(const QModelIndex &index, const QVariant &value, int = Qt::EditRole);
+
+    QString profileName(const QModelIndex &index);
+    QModelIndex find(const QString &name);
+
+private Q_SLOTS:
+    void profileNamesChanged();
+};
+
+#endif // KISINPUTPROFILEMODEL_H
diff --git a/krita/ui/input/config/kis_input_type_delegate.cpp b/krita/ui/input/config/kis_input_type_delegate.cpp
new file mode 100644
index 0000000..15307e3
--- /dev/null
+++ b/krita/ui/input/config/kis_input_type_delegate.cpp
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_type_delegate.h"
+
+#include <KComboBox>
+#include <KLocalizedString>
+
+class KisInputTypeDelegate::Private
+{
+public:
+    Private() { }
+};
+
+KisInputTypeDelegate::KisInputTypeDelegate(QObject *parent)
+    : QStyledItemDelegate(parent), d(new Private)
+{
+
+}
+
+KisInputTypeDelegate::~KisInputTypeDelegate()
+{
+    delete d;
+
+}
+
+QWidget *KisInputTypeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
+{
+    KComboBox *combo = new KComboBox(parent);
+    combo->addItems(QStringList()
+                    << i18n("Key Combination")
+                    << i18n("Mouse Button")
+                    << i18n("Mouse Wheel")
+                    //<< i18n("Gesture")
+                   );
+    combo->setCurrentIndex(0);
+
+    return combo;
+}
+
+void KisInputTypeDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+    KComboBox *combo = qobject_cast<KComboBox *>(editor);
+    Q_ASSERT(combo);
+
+    combo->setCurrentIndex(index.data(Qt::EditRole).toUInt() - 1);
+}
+
+void KisInputTypeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+    KComboBox *combo = qobject_cast<KComboBox *>(editor);
+    Q_ASSERT(combo);
+    model->setData(index, combo->currentIndex() + 1, Qt::EditRole);
+}
+
+void KisInputTypeDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
+{
+    editor->setGeometry(option.rect);
+}
diff --git a/krita/ui/input/config/kis_input_type_delegate.h b/krita/ui/input/config/kis_input_type_delegate.h
new file mode 100644
index 0000000..d3594dd
--- /dev/null
+++ b/krita/ui/input/config/kis_input_type_delegate.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTTYPEDELEGATE_H
+#define KISINPUTTYPEDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+/**
+ * \brief A delegate providing editors for the type property of KisShortcutConfiguration.
+ */
+class KisInputTypeDelegate : public QStyledItemDelegate
+{
+    Q_OBJECT
+public:
+    explicit KisInputTypeDelegate(QObject *parent = 0);
+    ~KisInputTypeDelegate();
+
+    virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const;
+    virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
+    virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
+    virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const;
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISINPUTTYPEDELEGATE_H
diff --git a/krita/ui/input/config/kis_key_input_editor.cpp b/krita/ui/input/config/kis_key_input_editor.cpp
new file mode 100644
index 0000000..4179f94
--- /dev/null
+++ b/krita/ui/input/config/kis_key_input_editor.cpp
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_key_input_editor.h"
+
+#include <QWidgetAction>
+#include <QMenu>
+#include <QTimer>
+
+#include "ui_kis_key_input_editor.h"
+
+class KisKeyInputEditor::Private
+{
+public:
+    Private() { }
+
+    Ui::KisKeyInputEditor *ui;
+};
+
+KisKeyInputEditor::KisKeyInputEditor(QWidget *parent)
+    : KPushButton(parent), d(new Private)
+{
+    QWidget *popup = new QWidget();
+
+    d->ui = new Ui::KisKeyInputEditor;
+    d->ui->setupUi(popup);
+
+    QWidgetAction *action = new QWidgetAction(this);
+    action->setDefaultWidget(popup);
+
+    QMenu *menu = new QMenu(this);
+    menu->addAction(action);
+    setMenu(menu);
+
+    QTimer::singleShot(0, this, SLOT(showMenu()));
+
+    connect(d->ui->keysButton, SIGNAL(dataChanged()), SLOT(updateLabel()));
+    connect(d->ui->clearKeysButton, SIGNAL(clicked(bool)), d->ui->keysButton, SLOT(clear()));
+}
+
+KisKeyInputEditor::~KisKeyInputEditor()
+{
+    delete d->ui;
+    delete d;
+}
+
+QList< Qt::Key > KisKeyInputEditor::keys() const
+{
+    return d->ui->keysButton->keys();
+}
+
+void KisKeyInputEditor::setKeys(const QList< Qt::Key > &newKeys)
+{
+    d->ui->keysButton->setKeys(newKeys);
+    updateLabel();
+}
+
+void KisKeyInputEditor::updateLabel()
+{
+    setText(KisShortcutConfiguration::keysToText(d->ui->keysButton->keys()));
+}
diff --git a/krita/ui/input/config/kis_key_input_editor.h b/krita/ui/input/config/kis_key_input_editor.h
new file mode 100644
index 0000000..d37af9a
--- /dev/null
+++ b/krita/ui/input/config/kis_key_input_editor.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISKEYINPUTEDITOR_H
+#define KISKEYINPUTEDITOR_H
+
+#include <KPushButton>
+
+namespace Ui
+{
+class KisKeyInputEditor;
+}
+
+/**
+ * \brief An editor widget for a list of keys.
+ */
+class KisKeyInputEditor : public KPushButton
+{
+    Q_OBJECT
+public:
+    KisKeyInputEditor(QWidget *parent = 0);
+    ~KisKeyInputEditor();
+
+    QList<Qt::Key> keys() const;
+    void setKeys(const QList<Qt::Key> &newKeys);
+
+    Qt::MouseButtons buttons() const;
+    void setButtons(Qt::MouseButtons newButtons);
+
+private Q_SLOTS:
+    void updateLabel();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISKEYINPUTEDITOR_H
diff --git a/krita/ui/input/config/kis_key_input_editor.ui b/krita/ui/input/config/kis_key_input_editor.ui
new file mode 100644
index 0000000..efee21b
--- /dev/null
+++ b/krita/ui/input/config/kis_key_input_editor.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KisKeyInputEditor</class>
+ <widget class="QWidget" name="KisKeyInputEditor">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>350</width>
+    <height>65</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0" colspan="3">
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Edit Key Combination</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="2">
+    <widget class="KPushButton" name="clearKeysButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="edit-clear-locationbar-rtl">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="keysLabel">
+     <property name="styleSheet">
+      <string notr="true">background: none;</string>
+     </property>
+     <property name="text">
+      <string>Keys</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="KisInputButton" name="keysButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="configure">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KPushButton</class>
+   <extends>QPushButton</extends>
+   <header>kpushbutton.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KisInputButton</class>
+   <extends>QPushButton</extends>
+   <header>input/config/kis_input_button.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/krita/ui/input/config/kis_mouse_input_editor.cpp b/krita/ui/input/config/kis_mouse_input_editor.cpp
new file mode 100644
index 0000000..9e6bdcb
--- /dev/null
+++ b/krita/ui/input/config/kis_mouse_input_editor.cpp
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_mouse_input_editor.h"
+
+#include <QWidgetAction>
+#include <QMenu>
+#include <QTimer>
+
+#include "ui_kis_mouse_input_editor.h"
+
+class KisMouseInputEditor::Private
+{
+public:
+    Private() { }
+
+    Ui::KisMouseInputEditor *ui;
+};
+
+KisMouseInputEditor::KisMouseInputEditor(QWidget *parent)
+    : KPushButton(parent), d(new Private)
+{
+    QWidget *popup = new QWidget();
+
+    d->ui = new Ui::KisMouseInputEditor;
+    d->ui->setupUi(popup);
+    d->ui->mouseButton->setType(KisInputButton::MouseType);
+
+    QWidgetAction *action = new QWidgetAction(this);
+    action->setDefaultWidget(popup);
+
+    QMenu *menu = new QMenu(this);
+    menu->addAction(action);
+    setMenu(menu);
+
+    QTimer::singleShot(0, this, SLOT(showMenu()));
+
+    connect(d->ui->mouseButton, SIGNAL(dataChanged()), SLOT(updateLabel()));
+    connect(d->ui->modifiersButton, SIGNAL(dataChanged()), SLOT(updateLabel()));
+    connect(d->ui->clearMouseButton, SIGNAL(clicked(bool)), d->ui->mouseButton, SLOT(clear()));
+    connect(d->ui->clearModifiersButton, SIGNAL(clicked(bool)), d->ui->modifiersButton, SLOT(clear()));
+}
+
+KisMouseInputEditor::~KisMouseInputEditor()
+{
+    delete d->ui;
+    delete d;
+}
+
+QList< Qt::Key > KisMouseInputEditor::keys() const
+{
+    return d->ui->modifiersButton->keys();
+}
+
+void KisMouseInputEditor::setKeys(const QList< Qt::Key > &newKeys)
+{
+    d->ui->modifiersButton->setKeys(newKeys);
+    updateLabel();
+}
+
+Qt::MouseButtons KisMouseInputEditor::buttons() const
+{
+    return d->ui->mouseButton->buttons();
+}
+
+void KisMouseInputEditor::setButtons(Qt::MouseButtons newButtons)
+{
+    d->ui->mouseButton->setButtons(newButtons);
+    updateLabel();
+}
+
+void KisMouseInputEditor::updateLabel()
+{
+    QString text;
+
+    if (d->ui->modifiersButton->keys().size() > 0) {
+        text.append(KisShortcutConfiguration::keysToText(d->ui->modifiersButton->keys()));
+        text.append(" + ");
+    }
+
+    text.append(KisShortcutConfiguration::buttonsToText(d->ui->mouseButton->buttons()));
+
+    setText(text);
+}
diff --git a/krita/ui/input/config/kis_mouse_input_editor.h b/krita/ui/input/config/kis_mouse_input_editor.h
new file mode 100644
index 0000000..351ca2e
--- /dev/null
+++ b/krita/ui/input/config/kis_mouse_input_editor.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISMOUSEINPUTEDITOR_H
+#define KISMOUSEINPUTEDITOR_H
+
+#include <KPushButton>
+
+namespace Ui
+{
+class KisMouseInputEditor;
+}
+
+/**
+ * \brief An editor widget for mouse buttons with modifiers.
+ */
+class KisMouseInputEditor : public KPushButton
+{
+    Q_OBJECT
+public:
+    KisMouseInputEditor(QWidget *parent = 0);
+    ~KisMouseInputEditor();
+
+    QList<Qt::Key> keys() const;
+    void setKeys(const QList<Qt::Key> &newKeys);
+
+    Qt::MouseButtons buttons() const;
+    void setButtons(Qt::MouseButtons newButtons);
+
+private Q_SLOTS:
+    void updateLabel();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISMOUSEINPUTEDITOR_H
diff --git a/krita/ui/input/config/kis_mouse_input_editor.ui b/krita/ui/input/config/kis_mouse_input_editor.ui
new file mode 100644
index 0000000..3f1b20b
--- /dev/null
+++ b/krita/ui/input/config/kis_mouse_input_editor.ui
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KisMouseInputEditor</class>
+ <widget class="QWidget" name="KisMouseInputEditor">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>350</width>
+    <height>100</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="1" column="1">
+    <widget class="KisInputButton" name="mouseButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="configure">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="3">
+    <widget class="KPushButton" name="clearMouseButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="edit-clear-locationbar-rtl">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="KisInputButton" name="modifiersButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="configure">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="modifiersLabel">
+     <property name="styleSheet">
+      <string notr="true">background: none;</string>
+     </property>
+     <property name="text">
+      <string>Modifiers</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="mouseLabel">
+     <property name="styleSheet">
+      <string notr="true">background: none;</string>
+     </property>
+     <property name="text">
+      <string>Mouse Button</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="3">
+    <widget class="KPushButton" name="clearModifiersButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="edit-clear-locationbar-rtl">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0" colspan="4">
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Edit Mouse Input</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KPushButton</class>
+   <extends>QPushButton</extends>
+   <header>kpushbutton.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KisInputButton</class>
+   <extends>QPushButton</extends>
+   <header>input/config/kis_input_button.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/krita/ui/input/config/kis_wheel_input_editor.cpp b/krita/ui/input/config/kis_wheel_input_editor.cpp
new file mode 100644
index 0000000..f752fb6
--- /dev/null
+++ b/krita/ui/input/config/kis_wheel_input_editor.cpp
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_wheel_input_editor.h"
+
+#include "ui_kis_wheel_input_editor.h"
+#include <QMenu>
+#include <QWidgetAction>
+#include <QTimer>
+
+class KisWheelInputEditor::Private
+{
+public:
+    Private() { }
+
+    Ui::KisWheelInputEditor *ui;
+};
+
+KisWheelInputEditor::KisWheelInputEditor(QWidget *parent)
+    : KPushButton(parent), d(new Private)
+{
+    QWidget *popup = new QWidget();
+
+    d->ui = new Ui::KisWheelInputEditor;
+    d->ui->setupUi(popup);
+    d->ui->wheelButton->setType(KisInputButton::WheelType);
+
+    QWidgetAction *action = new QWidgetAction(this);
+    action->setDefaultWidget(popup);
+
+    QMenu *menu = new QMenu(this);
+    menu->addAction(action);
+    setMenu(menu);
+
+    QTimer::singleShot(0, this, SLOT(showMenu()));
+
+    connect(d->ui->wheelButton, SIGNAL(dataChanged()), SLOT(updateLabel()));
+    connect(d->ui->modifiersButton, SIGNAL(dataChanged()), SLOT(updateLabel()));
+    connect(d->ui->clearWheelButton, SIGNAL(clicked(bool)), d->ui->wheelButton, SLOT(clear()));
+    connect(d->ui->clearModifiersButton, SIGNAL(clicked(bool)), d->ui->modifiersButton, SLOT(clear()));
+}
+
+KisWheelInputEditor::~KisWheelInputEditor()
+{
+    delete d->ui;
+    delete d;
+}
+
+QList< Qt::Key > KisWheelInputEditor::keys() const
+{
+    return d->ui->modifiersButton->keys();
+}
+
+void KisWheelInputEditor::setKeys(const QList< Qt::Key > &newKeys)
+{
+    d->ui->modifiersButton->setKeys(newKeys);
+    updateLabel();
+}
+
+KisShortcutConfiguration::MouseWheelMovement KisWheelInputEditor::wheel() const
+{
+    return d->ui->wheelButton->wheel();
+}
+
+void KisWheelInputEditor::setWheel(KisShortcutConfiguration::MouseWheelMovement newWheel)
+{
+    d->ui->wheelButton->setWheel(newWheel);
+    updateLabel();
+}
+
+void KisWheelInputEditor::updateLabel()
+{
+    QString text;
+
+    if (d->ui->modifiersButton->keys().size() > 0) {
+        text.append(KisShortcutConfiguration::keysToText(d->ui->modifiersButton->keys()));
+        text.append(" + ");
+    }
+
+    text.append(KisShortcutConfiguration::wheelToText(d->ui->wheelButton->wheel()));
+
+    setText(text);
+}
diff --git a/krita/ui/input/config/kis_wheel_input_editor.h b/krita/ui/input/config/kis_wheel_input_editor.h
new file mode 100644
index 0000000..7425e57
--- /dev/null
+++ b/krita/ui/input/config/kis_wheel_input_editor.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISWHEELINPUTEDITOR_H
+#define KISWHEELINPUTEDITOR_H
+
+#include <KPushButton>
+
+#include "input/kis_shortcut_configuration.h"
+
+namespace Ui
+{
+class KisWheelInputEditor;
+}
+
+/**
+ * \brief An editor widget for mouse wheel input with modifiers.
+ */
+class KisWheelInputEditor : public KPushButton
+{
+    Q_OBJECT
+public:
+    KisWheelInputEditor(QWidget *parent = 0);
+    ~KisWheelInputEditor();
+
+    QList<Qt::Key> keys() const;
+    void setKeys(const QList<Qt::Key> &newKeys);
+
+    KisShortcutConfiguration::MouseWheelMovement wheel() const;
+    void setWheel(KisShortcutConfiguration::MouseWheelMovement newWheel);
+
+private Q_SLOTS:
+    void updateLabel();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISWHEELINPUTEDITOR_H
diff --git a/krita/ui/input/config/kis_wheel_input_editor.ui b/krita/ui/input/config/kis_wheel_input_editor.ui
new file mode 100644
index 0000000..5a813fc
--- /dev/null
+++ b/krita/ui/input/config/kis_wheel_input_editor.ui
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KisWheelInputEditor</class>
+ <widget class="QWidget" name="KisWheelInputEditor">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>350</width>
+    <height>100</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="2" column="1">
+    <widget class="KisInputButton" name="modifiersButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="configure">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="wheelLabel">
+     <property name="styleSheet">
+      <string notr="true">background: none;</string>
+     </property>
+     <property name="text">
+      <string>Mouse Wheel</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0" colspan="3">
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Edit Mouse Wheel Input</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="KisInputButton" name="wheelButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="configure">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="2">
+    <widget class="KPushButton" name="clearWheelButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="edit-clear-locationbar-rtl">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="modifiersLabel">
+     <property name="styleSheet">
+      <string notr="true">background: none;</string>
+     </property>
+     <property name="text">
+      <string>Modifiers</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="2">
+    <widget class="KPushButton" name="clearModifiersButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="icon">
+      <iconset theme="edit-clear-locationbar-rtl">
+       <normaloff/>
+      </iconset>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KPushButton</class>
+   <extends>QPushButton</extends>
+   <header>kpushbutton.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KisInputButton</class>
+   <extends>QPushButton</extends>
+   <header>input/config/kis_input_button.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/krita/ui/input/kis_abstract_input_action.cpp b/krita/ui/input/kis_abstract_input_action.cpp
index 093f872..ebb63ef 100644
--- a/krita/ui/input/kis_abstract_input_action.cpp
+++ b/krita/ui/input/kis_abstract_input_action.cpp
@@ -25,18 +25,19 @@
 class KisAbstractInputAction::Private
 {
 public:
-    KisInputManager* inputManager;
-
     QString name;
     QString description;
     QHash<QString, int> indexes;
 
     QPointF lastMousePosition;
+
+    static KisInputManager* inputManager;
 };
 
-KisAbstractInputAction::KisAbstractInputAction(KisInputManager* manager) : d(new Private)
+KisInputManager *KisAbstractInputAction::Private::inputManager = 0;
+
+KisAbstractInputAction::KisAbstractInputAction() : d(new Private)
 {
-    d->inputManager = manager;
     d->indexes.insert(i18n("Activate"), 0);
 }
 
@@ -92,7 +93,7 @@ bool KisAbstractInputAction::supportsHiResInputEvents() const
 
 KisInputManager* KisAbstractInputAction::inputManager() const
 {
-    return d->inputManager;
+    return Private::inputManager;
 }
 
 QString KisAbstractInputAction::name() const
@@ -124,3 +125,8 @@ void KisAbstractInputAction::setShortcutIndexes(const QHash< QString, int >& ind
 {
     d->indexes = indexes;
 }
+
+void KisAbstractInputAction::setInputManager(KisInputManager *manager)
+{
+    Private::inputManager = manager;
+}
diff --git a/krita/ui/input/kis_abstract_input_action.h b/krita/ui/input/kis_abstract_input_action.h
index 50afffa..ae5bb46 100644
--- a/krita/ui/input/kis_abstract_input_action.h
+++ b/krita/ui/input/kis_abstract_input_action.h
@@ -59,7 +59,7 @@ public:
      *
      * \param manager The InputManager this action belongs to.
      */
-    explicit KisAbstractInputAction(KisInputManager *manager);
+    explicit KisAbstractInputAction();
     /**
      * Destructor.
      */
@@ -160,6 +160,9 @@ protected:
     virtual void mouseMoved(const QPointF &lastPos, const QPointF &pos);
 
 private:
+    friend class KisInputManager;
+    static void setInputManager(KisInputManager *manager);
+
     class Private;
     Private * const d;
 };
diff --git a/krita/ui/input/kis_alternate_invocation_action.cpp b/krita/ui/input/kis_alternate_invocation_action.cpp
index c518215..e05799f 100644
--- a/krita/ui/input/kis_alternate_invocation_action.cpp
+++ b/krita/ui/input/kis_alternate_invocation_action.cpp
@@ -26,11 +26,10 @@
 
 #include "kis_input_manager.h"
 
-KisAlternateInvocationAction::KisAlternateInvocationAction(KisInputManager *manager)
-    : KisAbstractInputAction(manager)
+KisAlternateInvocationAction::KisAlternateInvocationAction()
 {
     setName(i18n("Alternate Invocation"));
-    setDescription(i18n("Alternate Invocation performs an alternate action with the current tool. For example, using the brush tool it picks a color from the canvas."));
+    setDescription(i18n("The <i>Alternate Invocation</i> action performs an alternate action with the current tool. For example, using the brush tool it picks a color from the canvas."));
     QHash<QString, int> shortcuts;
     shortcuts.insert(i18n("Toggle Primary Mode"), PrimaryAlternateToggleShortcut);
     shortcuts.insert(i18n("Toggle Secondary Mode"), SecondaryAlternateToggleShortcut);
diff --git a/krita/ui/input/kis_alternate_invocation_action.h b/krita/ui/input/kis_alternate_invocation_action.h
index 5255ea4..bdfc699 100644
--- a/krita/ui/input/kis_alternate_invocation_action.h
+++ b/krita/ui/input/kis_alternate_invocation_action.h
@@ -39,7 +39,7 @@ public:
         SecondaryAlternateToggleShortcut, ///< Toggle Secondary mode.
     };
 
-    explicit KisAlternateInvocationAction(KisInputManager *manager);
+    explicit KisAlternateInvocationAction();
     virtual ~KisAlternateInvocationAction();
 
     void begin(int shortcut, QEvent *event);
diff --git a/krita/ui/input/kis_change_primary_setting_action.cpp b/krita/ui/input/kis_change_primary_setting_action.cpp
index cd7ecd0..738b631 100644
--- a/krita/ui/input/kis_change_primary_setting_action.cpp
+++ b/krita/ui/input/kis_change_primary_setting_action.cpp
@@ -23,11 +23,10 @@
 #include "kis_input_manager.h"
 #include <KoToolProxy.h>
 
-KisChangePrimarySettingAction::KisChangePrimarySettingAction(KisInputManager* manager)
-    : KisAbstractInputAction(manager)
+KisChangePrimarySettingAction::KisChangePrimarySettingAction()
 {
-    setName(i18n("Change Tool Primary Setting"));
-    setDescription(i18n("Changes a tool's \"Primary Setting\", for example the brush size for the brush tool."));
+    setName(i18n("Change Primary Setting"));
+    setDescription(i18n("The <i>Change Primary Setting</i> action changes a tool's \"Primary Setting\", for example the brush size for the brush tool."));
 }
 
 KisChangePrimarySettingAction::~KisChangePrimarySettingAction()
diff --git a/krita/ui/input/kis_change_primary_setting_action.h b/krita/ui/input/kis_change_primary_setting_action.h
index 0efc167..3a1097d 100644
--- a/krita/ui/input/kis_change_primary_setting_action.h
+++ b/krita/ui/input/kis_change_primary_setting_action.h
@@ -30,7 +30,7 @@
 class KisChangePrimarySettingAction : public KisAbstractInputAction
 {
 public:
-    explicit KisChangePrimarySettingAction(KisInputManager* manager);
+    explicit KisChangePrimarySettingAction();
     virtual ~KisChangePrimarySettingAction();
 
     void begin(int shortcut, QEvent *event);
diff --git a/krita/ui/input/kis_input_manager.cpp b/krita/ui/input/kis_input_manager.cpp
index 667fdcf..6869b54 100644
--- a/krita/ui/input/kis_input_manager.cpp
+++ b/krita/ui/input/kis_input_manager.cpp
@@ -47,6 +47,10 @@
 #include "kis_stroke_shortcut.h"
 #include "kis_single_action_shortcut.h"
 
+#include "kis_input_profile.h"
+#include "kis_input_profile_manager.h"
+#include "kis_shortcut_configuration.h"
+
 class KisInputManager::Private
 {
 public:
@@ -65,15 +69,10 @@ public:
     bool trySetMirrorMode(const QPointF &mousePosition);
     void saveTabletEvent(const QTabletEvent *event);
     void resetSavedTabletEvent(QEvent::Type type);
-    void addStrokeShortcut(KisAbstractInputAction* action, int index,
-                           const QList<Qt::Key> &modifiers,
-                           const QList<Qt::MouseButton> &buttons);
+    void addStrokeShortcut(KisAbstractInputAction* action, int index, const QList< Qt::Key >& modifiers, Qt::MouseButtons buttons);
     void addKeyShortcut(KisAbstractInputAction* action, int index,
-                        const QList<Qt::Key> &modifiers,
-                        Qt::Key key);
-    void addWheelShortcut(KisAbstractInputAction* action, int index,
-                          const QList<Qt::Key> &modifiers,
-                          KisSingleActionShortcut::WheelAction wheelAction);
+                        const QList<Qt::Key> &modifiers);
+    void addWheelShortcut(KisAbstractInputAction* action, int index, const QList< Qt::Key >& modifiers, KisShortcutConfiguration::MouseWheelMovement wheelAction);
     bool processUnhandledEvent(QEvent *event);
     Qt::Key workaroundShiftAltMetaHell(const QKeyEvent *keyEvent);
     void setupActions();
@@ -117,108 +116,85 @@ static inline QList<Qt::MouseButton> BUTTONS(Qt::MouseButton button1, Qt::MouseB
 
 void KisInputManager::Private::addStrokeShortcut(KisAbstractInputAction* action, int index,
                                                  const QList<Qt::Key> &modifiers,
-                                                 const QList<Qt::MouseButton> &buttons)
+                                                 Qt::MouseButtons buttons)
 {
     KisStrokeShortcut *strokeShortcut =
         new KisStrokeShortcut(action, index);
-    strokeShortcut->setButtons(modifiers, buttons);
+
+    QList<Qt::MouseButton> buttonList;
+    if(buttons & Qt::LeftButton) {
+        buttonList << Qt::LeftButton;
+    }
+    if(buttons & Qt::RightButton) {
+        buttonList << Qt::RightButton;
+    }
+    if(buttons & Qt::MidButton) {
+        buttonList << Qt::MidButton;
+    }
+    if(buttons & Qt::XButton1) {
+        buttonList << Qt::XButton1;
+    }
+    if(buttons & Qt::XButton2) {
+        buttonList << Qt::XButton2;
+    }
+
+    strokeShortcut->setButtons(modifiers, buttonList);
     matcher.addShortcut(strokeShortcut);
 }
 
 void KisInputManager::Private::addKeyShortcut(KisAbstractInputAction* action, int index,
-                                              const QList<Qt::Key> &modifiers,
-                                              Qt::Key key)
+                                              const QList<Qt::Key> &keys)
 {
     KisSingleActionShortcut *keyShortcut =
         new KisSingleActionShortcut(action, index);
-    keyShortcut->setKey(modifiers, key);
+
+    QList<Qt::Key> modifiers = keys.mid(1);
+    keyShortcut->setKey(modifiers, keys.at(0));
     matcher.addShortcut(keyShortcut);
 }
 
 void KisInputManager::Private::addWheelShortcut(KisAbstractInputAction* action, int index,
                                                 const QList<Qt::Key> &modifiers,
-                                                KisSingleActionShortcut::WheelAction wheelAction)
+                                                KisShortcutConfiguration::MouseWheelMovement wheelAction)
 {
     KisSingleActionShortcut *keyShortcut =
         new KisSingleActionShortcut(action, index);
-    keyShortcut->setWheel(modifiers, wheelAction);
+
+    KisSingleActionShortcut::WheelAction a;
+    switch(wheelAction) {
+        case KisShortcutConfiguration::WheelUp:
+            a = KisSingleActionShortcut::WheelUp;
+            break;
+        case KisShortcutConfiguration::WheelDown:
+            a = KisSingleActionShortcut::WheelDown;
+            break;
+        case KisShortcutConfiguration::WheelLeft:
+            a = KisSingleActionShortcut::WheelLeft;
+            break;
+        case KisShortcutConfiguration::WheelRight:
+            a = KisSingleActionShortcut::WheelRight;
+            break;
+        default:
+            return;
+    }
+
+    keyShortcut->setWheel(modifiers, a);
     matcher.addShortcut(keyShortcut);
 }
 
 void KisInputManager::Private::setupActions()
 {
-#if QT_VERSION >= 0x040700
-    Qt::MouseButton middleButton = Qt::MiddleButton;
-#else
-    Qt::MouseButton middleButton = Qt::MidButton;
-#endif
-
-    //Create all the actions.
-    KisAbstractInputAction* action = new KisToolInvocationAction(q);
-    matcher.addAction(action);
-    addStrokeShortcut(action, KisToolInvocationAction::ActivateShortcut, KEYS(), BUTTONS(Qt::LeftButton));
-    addKeyShortcut(action, KisToolInvocationAction::ConfirmShortcut, KEYS(), Qt::Key_Return);
-    addKeyShortcut(action, KisToolInvocationAction::ConfirmShortcut, KEYS(), Qt::Key_Enter);
-    addKeyShortcut(action, KisToolInvocationAction::CancelShortcut, KEYS(), Qt::Key_Escape);
-    defaultInputAction = action;
-
-    action = new KisAlternateInvocationAction(q);
-    matcher.addAction(action);
-    addStrokeShortcut(action, KisAlternateInvocationAction::PrimaryAlternateToggleShortcut, KEYS(Qt::Key_Control), BUTTONS(Qt::LeftButton));
-    addStrokeShortcut(action, KisAlternateInvocationAction::SecondaryAlternateToggleShortcut, KEYS(Qt::Key_Control, Qt::Key_Alt), BUTTONS(Qt::LeftButton));
-
-    action = new KisChangePrimarySettingAction(q);
-    matcher.addAction(action);
-    addStrokeShortcut(action, 0, KEYS(Qt::Key_Shift), BUTTONS(Qt::LeftButton));
-
-
-    action = new KisPanAction(q);
-    matcher.addAction(action);
-
-    addStrokeShortcut(action, KisPanAction::PanToggleShortcut, KEYS(Qt::Key_Space), BUTTONS(Qt::LeftButton));
-    addStrokeShortcut(action, KisPanAction::PanToggleShortcut, KEYS(), BUTTONS(middleButton));
-
-    addKeyShortcut(action, KisPanAction::PanLeftShortcut, KEYS(), Qt::Key_Left);
-    addKeyShortcut(action, KisPanAction::PanRightShortcut, KEYS(), Qt::Key_Right);
-    addKeyShortcut(action, KisPanAction::PanUpShortcut, KEYS(), Qt::Key_Up);
-    addKeyShortcut(action, KisPanAction::PanDownShortcut, KEYS(), Qt::Key_Down);
-
-
-    action = new KisRotateCanvasAction(q);
-    matcher.addAction(action);
-
-    addStrokeShortcut(action, KisRotateCanvasAction::RotateToggleShortcut, KEYS(Qt::Key_Shift, Qt::Key_Space), BUTTONS(Qt::LeftButton));
-    addStrokeShortcut(action, KisRotateCanvasAction::DiscreteRotateToggleShortcut, KEYS(Qt::Key_Shift, Qt::Key_Alt, Qt::Key_Space), BUTTONS(Qt::LeftButton));
-    addStrokeShortcut(action, KisRotateCanvasAction::RotateToggleShortcut, KEYS(Qt::Key_Shift), BUTTONS(middleButton));
-
-    addKeyShortcut(action, KisRotateCanvasAction::RotateLeftShortcut, KEYS(), Qt::Key_4);
-    addKeyShortcut(action, KisRotateCanvasAction::RotateResetShortcut, KEYS(), Qt::Key_5);
-    addKeyShortcut(action, KisRotateCanvasAction::RotateRightShortcut, KEYS(), Qt::Key_6);
-
-
-    action = new KisZoomAction(q);
-    matcher.addAction(action);
-
-    addStrokeShortcut(action, KisZoomAction::ZoomToggleShortcut, KEYS(Qt::Key_Control), BUTTONS(middleButton));
-
-    addStrokeShortcut(action, KisZoomAction::ZoomToggleShortcut, KEYS(Qt::Key_Control, Qt::Key_Space), BUTTONS(Qt::LeftButton));
-    addStrokeShortcut(action, KisZoomAction::DiscreteZoomToggleShortcut, KEYS(Qt::Key_Control, Qt::Key_Alt, Qt::Key_Space), BUTTONS(Qt::LeftButton));
-
-    addWheelShortcut(action, KisZoomAction::ZoomInShortcut, KEYS(), KisSingleActionShortcut::WheelUp);
-    addWheelShortcut(action, KisZoomAction::ZoomOutShortcut, KEYS(), KisSingleActionShortcut::WheelDown);
-
-    addKeyShortcut(action, KisZoomAction::ZoomInShortcut, KEYS(), Qt::Key_Plus);
-    addKeyShortcut(action, KisZoomAction::ZoomOutShortcut, KEYS(), Qt::Key_Minus);
-
-    addKeyShortcut(action, KisZoomAction::ZoomResetShortcut, KEYS(), Qt::Key_1);
-    addKeyShortcut(action, KisZoomAction::ZoomToPageShortcut, KEYS(), Qt::Key_2);
-    addKeyShortcut(action, KisZoomAction::ZoomToWidthShortcut, KEYS(), Qt::Key_3);
-
-    action = new KisShowPaletteAction(q);
-    matcher.addAction(action);
+    QList<KisAbstractInputAction*> actions = KisInputProfileManager::instance()->actions();
+    foreach(KisAbstractInputAction *action, actions) {
+        if(dynamic_cast<KisToolInvocationAction*>(action)) {
+            defaultInputAction = action;
+        }
+    }
 
-    addStrokeShortcut(action, 0, KEYS(), BUTTONS(Qt::RightButton));
-    addKeyShortcut(action, 0, KEYS(), Qt::Key_F);
+    connect(KisInputProfileManager::instance(), SIGNAL(currentProfileChanged()), q, SLOT(profileChanged()));
+    if(KisInputProfileManager::instance()->currentProfile()) {
+        q->profileChanged();
+    }
 }
 
 bool KisInputManager::Private::processUnhandledEvent(QEvent *event)
@@ -452,9 +428,24 @@ bool KisInputManager::eventFilter(QObject* object, QEvent* event)
     }
     case QEvent::Wheel: {
         QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
-        KisSingleActionShortcut::WheelAction action =
-            wheelEvent->delta() > 0 ?
-            KisSingleActionShortcut::WheelUp : KisSingleActionShortcut::WheelDown;
+        KisSingleActionShortcut::WheelAction action;
+
+        if(wheelEvent->orientation() == Qt::Horizontal) {
+            if(wheelEvent->delta() < 0) {
+                action = KisSingleActionShortcut::WheelRight;
+            }
+            else {
+                action = KisSingleActionShortcut::WheelLeft;
+            }
+        }
+        else {
+            if(wheelEvent->delta() > 0) {
+                action = KisSingleActionShortcut::WheelUp;
+            }
+            else {
+                action = KisSingleActionShortcut::WheelDown;
+            }
+        }
 
         retval = d->matcher.wheelEvent(action, wheelEvent);
         break;
@@ -466,6 +457,8 @@ bool KisInputManager::eventFilter(QObject* object, QEvent* event)
     case QEvent::FocusIn:
         //Clear all state so we don't have half-matched shortcuts dangling around.
         d->matcher.reset();
+        //Make sure the input actions know we are active.
+        KisAbstractInputAction::setInputManager(this);
         break;
     case QEvent::TabletPress:
     case QEvent::TabletMove:
@@ -535,3 +528,25 @@ QPointF KisInputManager::widgetToPixel(const QPointF& position)
     return d->canvas->coordinatesConverter()->widgetToDocument(pixel);
 }
 
+void KisInputManager::profileChanged()
+{
+    d->matcher.reset();
+    d->matcher.clearShortcuts();
+
+    QList<KisShortcutConfiguration*> shortcuts = KisInputProfileManager::instance()->currentProfile()->allShortcuts();
+    foreach(KisShortcutConfiguration *shortcut, shortcuts) {
+        switch(shortcut->type()) {
+            case KisShortcutConfiguration::KeyCombinationType:
+                d->addKeyShortcut(shortcut->action(), shortcut->mode(), shortcut->keys());
+                break;
+            case KisShortcutConfiguration::MouseButtonType:
+                d->addStrokeShortcut(shortcut->action(), shortcut->mode(), shortcut->keys(), shortcut->buttons());
+                break;
+            case KisShortcutConfiguration::MouseWheelType:
+                d->addWheelShortcut(shortcut->action(), shortcut->mode(), shortcut->keys(), shortcut->wheel());
+                break;
+            default:
+                break;
+        }
+    }
+}
diff --git a/krita/ui/input/kis_input_manager.h b/krita/ui/input/kis_input_manager.h
index 1334e7f..9ca1e0a 100644
--- a/krita/ui/input/kis_input_manager.h
+++ b/krita/ui/input/kis_input_manager.h
@@ -90,6 +90,7 @@ public:
 private Q_SLOTS:
     void setMirrorAxis();
     void slotToolChanged();
+    void profileChanged();
 
 private:
     class Private;
diff --git a/krita/ui/input/kis_input_profile.cpp b/krita/ui/input/kis_input_profile.cpp
new file mode 100644
index 0000000..0377441
--- /dev/null
+++ b/krita/ui/input/kis_input_profile.cpp
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_profile.h"
+
+#include <QStringList>
+#include <QMultiHash>
+
+#include "kis_abstract_input_action.h"
+#include "kis_shortcut_configuration.h"
+
+class KisInputProfile::Private
+{
+public:
+    Private() { }
+
+    QString name;
+    QMultiHash<KisAbstractInputAction *, KisShortcutConfiguration *> shortcuts;
+};
+
+KisInputProfile::KisInputProfile(QObject *parent)
+    : QObject(parent), d(new Private())
+{
+
+}
+
+KisInputProfile::~KisInputProfile()
+{
+
+}
+
+QString KisInputProfile::name() const
+{
+    return d->name;
+}
+void KisInputProfile::setName(const QString &name)
+{
+    if (d->name != name) {
+        d->name = name;
+        emit nameChanged();
+    }
+}
+
+QList< KisShortcutConfiguration * > KisInputProfile::allShortcuts() const
+{
+    return d->shortcuts.values();
+}
+
+QList< KisShortcutConfiguration * > KisInputProfile::shortcutsForAction(KisAbstractInputAction *action) const
+{
+    if (d->shortcuts.contains(action)) {
+        return d->shortcuts.values(action);
+    }
+
+    return QList<KisShortcutConfiguration *>();
+}
+
+void KisInputProfile::addShortcut(KisShortcutConfiguration *shortcut)
+{
+    Q_ASSERT(shortcut);
+    Q_ASSERT(shortcut->action());
+    d->shortcuts.insert(shortcut->action(), shortcut);
+}
+
+void KisInputProfile::removeShortcut(KisShortcutConfiguration *shortcut)
+{
+    Q_ASSERT(shortcut);
+    Q_ASSERT(shortcut->action());
+    d->shortcuts.remove(shortcut->action(), shortcut);
+}
diff --git a/krita/ui/input/kis_input_profile.h b/krita/ui/input/kis_input_profile.h
new file mode 100644
index 0000000..675e709
--- /dev/null
+++ b/krita/ui/input/kis_input_profile.h
@@ -0,0 +1,95 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTPROFILE_H
+#define KISINPUTPROFILE_H
+
+#include <QObject>
+#include <QMetaType>
+
+class KisAbstractInputAction;
+class KisShortcutConfiguration;
+/**
+ * \brief A container class for sets of shortcuts associated with an action.
+ *
+ *
+ */
+class KisInputProfile : public QObject
+{
+    Q_OBJECT
+
+public:
+    /**
+     * Constructor.
+     */
+    KisInputProfile(QObject *parent = 0);
+    /**
+     * Destructor.
+     */
+    virtual ~KisInputProfile();
+
+    /**
+     * \return The name of the profile.
+     */
+    QString name() const;
+
+    /**
+     * \return A list of all shortcuts available.
+     */
+    QList<KisShortcutConfiguration *> allShortcuts() const;
+    /**
+     * \return A list of shortcuts associated with the given action.
+     *
+     * \param action The action for which to list the shortcuts.
+     */
+    QList<KisShortcutConfiguration *> shortcutsForAction(KisAbstractInputAction *action) const;
+
+    /**
+     * Add a shortcut to this profile.
+     *
+     * \param shortcut The shortcut to add.
+     */
+    void addShortcut(KisShortcutConfiguration *shortcut);
+    /**
+     * Remove a shortcut from this profile.
+     *
+     * \param shortcut The shortcut to remove.
+     */
+    void removeShortcut(KisShortcutConfiguration *shortcut);
+
+public Q_SLOTS:
+    /**
+     * Set the name of this profile.
+     *
+     * \param name The name to set.
+     */
+    void setName(const QString &name);
+
+Q_SIGNALS:
+    /**
+     * Emitted when the name of this profile changes.
+     */
+    void nameChanged();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISINPUTPROFILE_H
diff --git a/krita/ui/input/kis_input_profile_manager.cpp b/krita/ui/input/kis_input_profile_manager.cpp
new file mode 100644
index 0000000..7b77691
--- /dev/null
+++ b/krita/ui/input/kis_input_profile_manager.cpp
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_input_profile_manager.h"
+#include "kis_input_profile.h"
+
+#include <QMap>
+#include <QStringList>
+#include <QDir>
+
+#include <KGlobal>
+#include <KStandardDirs>
+#include <KConfig>
+#include <KConfigGroup>
+
+#include "kis_config.h"
+#include "kis_alternate_invocation_action.h"
+#include "kis_change_primary_setting_action.h"
+#include "kis_pan_action.h"
+#include "kis_rotate_canvas_action.h"
+#include "kis_show_palette_action.h"
+#include "kis_tool_invocation_action.h"
+#include "kis_zoom_action.h"
+#include "kis_shortcut_configuration.h"
+
+class KisInputProfileManager::Private
+{
+public:
+    Private() : currentProfile(0) { }
+
+    void createActions();
+    QString profileFileName(const QString &profileName);
+
+    KisInputProfile *currentProfile;
+
+    QMap<QString, KisInputProfile *> profiles;
+
+    QList<KisAbstractInputAction *> actions;
+};
+
+K_GLOBAL_STATIC(KisInputProfileManager, inputProfileManager)
+
+KisInputProfileManager *KisInputProfileManager::instance()
+{
+    return inputProfileManager;
+}
+
+QList< KisInputProfile * > KisInputProfileManager::profiles() const
+{
+    return d->profiles.values();
+}
+
+QStringList KisInputProfileManager::profileNames() const
+{
+    return d->profiles.keys();
+}
+
+KisInputProfile *KisInputProfileManager::profile(const QString &name) const
+{
+    if (d->profiles.contains(name)) {
+        return d->profiles.value(name);
+    }
+
+    return 0;
+}
+
+KisInputProfile *KisInputProfileManager::currentProfile() const
+{
+    return d->currentProfile;
+}
+
+void KisInputProfileManager::setCurrentProfile(KisInputProfile *profile)
+{
+    if (profile && profile != d->currentProfile) {
+        d->currentProfile = profile;
+        emit currentProfileChanged();
+    }
+}
+
+KisInputProfile *KisInputProfileManager::addProfile(const QString &name)
+{
+    if (d->profiles.contains(name)) {
+        return d->profiles.value(name);
+    }
+
+    KisInputProfile *profile = new KisInputProfile(this);
+    profile->setName(name);
+    d->profiles.insert(name, profile);
+
+    emit profilesChanged();
+
+    return profile;
+}
+
+void KisInputProfileManager::removeProfile(const QString &name)
+{
+    if (d->profiles.contains(name)) {
+        QString currentProfileName = d->currentProfile->name();
+
+        delete d->profiles.value(name);
+        d->profiles.remove(name);
+
+        //Delete the settings file for the removed profile, if it exists
+        QDir userDir(KGlobal::dirs()->saveLocation("appdata", "input/"));
+
+        if (userDir.exists(d->profileFileName(name))) {
+            userDir.remove(d->profileFileName(name));
+        }
+
+        if (currentProfileName == name) {
+            d->currentProfile = d->profiles.begin().value();
+            emit currentProfileChanged();
+        }
+
+        emit profilesChanged();
+    }
+}
+
+bool KisInputProfileManager::renameProfile(const QString &oldName, const QString &newName)
+{
+    if (!d->profiles.contains(oldName)) {
+        return false;
+    }
+
+    KisInputProfile *profile = d->profiles.value(oldName);
+    d->profiles.remove(oldName);
+    profile->setName(newName);
+    d->profiles.insert(newName, profile);
+
+    emit profilesChanged();
+
+    return true;
+}
+
+void KisInputProfileManager::duplicateProfile(const QString &name, const QString &newName)
+{
+    if (!d->profiles.contains(name) || d->profiles.contains(newName)) {
+        return;
+    }
+
+    KisInputProfile *newProfile = new KisInputProfile(this);
+    newProfile->setName(newName);
+    d->profiles.insert(newName, newProfile);
+
+    KisInputProfile *profile = d->profiles.value(name);
+    QList<KisShortcutConfiguration *> shortcuts = profile->allShortcuts();
+    Q_FOREACH(KisShortcutConfiguration * shortcut, shortcuts) {
+        newProfile->addShortcut(new KisShortcutConfiguration(*shortcut));
+    }
+
+    emit profilesChanged();
+}
+
+QList< KisAbstractInputAction * > KisInputProfileManager::actions()
+{
+    return d->actions;
+}
+
+void KisInputProfileManager::loadProfiles()
+{
+    //Remove any profiles that already exist
+    d->currentProfile = 0;
+    qDeleteAll(d->profiles);
+    d->profiles.clear();
+
+    //Look up all profiles (this includes those installed to $prefix as well as the user's local data dir)
+    QStringList profiles = KGlobal::dirs()->findAllResources("appdata", "input/*", KStandardDirs::NoDuplicates | KStandardDirs::Recursive);
+    Q_FOREACH(const QString & p, profiles) {
+        //Open the file
+        KConfig config(p, KConfig::SimpleConfig);
+
+        if (!config.hasGroup("General") || !config.group("General").hasKey("name")) {
+            //Skip if we don't have the proper settings.
+            continue;
+        }
+
+        KisInputProfile *newProfile = addProfile(config.group("General").readEntry("name"));
+        Q_FOREACH(KisAbstractInputAction * action, d->actions) {
+            if (!config.hasGroup(action->name())) {
+                continue;
+            }
+
+            KConfigGroup grp = config.group(action->name());
+            //Read the settings for the action and create the appropriate shortcuts.
+            Q_FOREACH(const QString & entry, grp.entryMap()) {
+                KisShortcutConfiguration *shortcut = new KisShortcutConfiguration;
+                shortcut->setAction(action);
+
+                if (shortcut->unserialize(entry)) {
+                    newProfile->addShortcut(shortcut);
+                }
+                else {
+                    delete shortcut;
+                }
+            }
+        }
+    }
+
+    KisConfig cfg;
+    QString currentProfile = cfg.currentInputProfile();
+
+    if (currentProfile.isEmpty() || !d->profiles.contains(currentProfile)) {
+        d->currentProfile = d->profiles.begin().value();
+    }
+    else {
+        d->currentProfile = d->profiles.value(currentProfile);
+    }
+
+    emit currentProfileChanged();
+}
+
+void KisInputProfileManager::saveProfiles()
+{
+    QString storagePath = KGlobal::dirs()->saveLocation("appdata", "input/");
+    Q_FOREACH(KisInputProfile * p, d->profiles) {
+        QString fileName = d->profileFileName(p->name());
+        KConfig config(storagePath + fileName, KConfig::SimpleConfig);
+
+        config.group("General").writeEntry("name", p->name());
+
+        Q_FOREACH(KisAbstractInputAction * action, d->actions) {
+            KConfigGroup grp = config.group(action->name());
+            grp.deleteGroup(); //Clear the group of any existing shortcuts.
+
+            int index = 0;
+            QList<KisShortcutConfiguration *> shortcuts = p->shortcutsForAction(action);
+            Q_FOREACH(KisShortcutConfiguration * shortcut, shortcuts) {
+                grp.writeEntry(QString("%1").arg(index++), shortcut->serialize());
+            }
+        }
+
+        config.sync();
+    }
+
+    KisConfig config;
+    config.setCurrentInputProfile(d->currentProfile->name());
+
+    //Force a reload of the current profile in input manager and whatever else uses the profile.
+    emit currentProfileChanged();
+}
+
+KisInputProfileManager::KisInputProfileManager(QObject *parent)
+    : QObject(parent), d(new Private())
+{
+    d->createActions();
+}
+
+KisInputProfileManager::~KisInputProfileManager()
+{
+    qDeleteAll(d->profiles);
+    qDeleteAll(d->actions);
+    delete d;
+}
+
+void KisInputProfileManager::Private::createActions()
+{
+    //TODO: Make this plugin based
+    //Note that the ordering here determines how things show up in the UI
+    actions.append(new KisToolInvocationAction());
+    actions.append(new KisAlternateInvocationAction());
+    actions.append(new KisChangePrimarySettingAction());
+    actions.append(new KisPanAction());
+    actions.append(new KisRotateCanvasAction());
+    actions.append(new KisZoomAction());
+    actions.append(new KisShowPaletteAction());
+}
+
+QString KisInputProfileManager::Private::profileFileName(const QString &profileName)
+{
+    return profileName.toLower().replace(QRegExp("[^a-z0-9]"), "").append(".profile");
+}
diff --git a/krita/ui/input/kis_input_profile_manager.h b/krita/ui/input/kis_input_profile_manager.h
new file mode 100644
index 0000000..5ecf112
--- /dev/null
+++ b/krita/ui/input/kis_input_profile_manager.h
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISINPUTPROFILEMANAGER_H
+#define KISINPUTPROFILEMANAGER_H
+
+#include <QObject>
+
+#include "krita_export.h"
+
+class KisAbstractInputAction;
+class KisInputProfile;
+
+/**
+ * \brief A class to manage a list of profiles and actions.
+ *
+ *
+ */
+class KRITAUI_EXPORT KisInputProfileManager : public QObject
+{
+    Q_OBJECT
+public:
+    KisInputProfileManager(QObject *parent = 0);
+    ~KisInputProfileManager();
+    Q_DISABLE_COPY(KisInputProfileManager);
+
+    /**
+     * Retrieve a profile by name.
+     *
+     * \param name The name of the profile to retrieve.
+     *
+     * \return The profile with the given name, or 0 if not found.
+     */
+    KisInputProfile *profile(const QString &name) const;
+    /**
+     * \return A list of all profiles.
+     */
+    QList<KisInputProfile *> profiles() const;
+    /**
+     * \return A list of the names of all profiles.
+     */
+    QStringList profileNames() const;
+
+    /**
+     * \return The current active profile.
+     */
+    KisInputProfile *currentProfile() const;
+    /**
+     * Set the current active profile.
+     *
+     * \param profile The profile to set as current.
+     */
+    void setCurrentProfile(KisInputProfile *profile);
+
+    /**
+     * Add a profile.
+     *
+     * \param name The name of the new profile.
+     *
+     * \return The new, empty profile or the non-empty profile if it already exists.
+     */
+    KisInputProfile *addProfile(const QString &name);
+    /**
+     * Remove a profile.
+     *
+     * This will remove the given profile from the list of profiles and delete it.
+     *
+     * \param name The profile to remove.
+     */
+    void removeProfile(const QString &name);
+    /**
+     * Rename a profile.
+     *
+     * \param oldName The current name of the profile.
+     * \param newName The new name of the profile.
+     *
+     * \return true if successful, false if not.
+     */
+    bool renameProfile(const QString &oldName, const QString &newName);
+    /**
+     * Duplicate a profile.
+     *
+     * This creates a new profile with the given name and copies all
+     * data from the old profile to the new profile.
+     *
+     * \param name The name of the profile to duplicate.
+     * \param newName The name of the new profile.
+     */
+    void duplicateProfile(const QString &name, const QString &newName);
+
+    /**
+     * \return The list of all available actions.
+     */
+    QList< KisAbstractInputAction * > actions();
+
+    /**
+     * Load all profiles from the configuration stored on disk.
+     */
+    void loadProfiles();
+    /**
+     * Save all profiles to configuration on disk.
+     */
+    void saveProfiles();
+
+    /**
+     * \return The singleton instance of this class.
+     */
+    static KisInputProfileManager *instance();
+
+Q_SIGNALS:
+    /**
+     * Emitted when the list of profiles changes.
+     */
+    void profilesChanged();
+    /**
+     * Emitted when the current active profile changes.
+     */
+    void currentProfileChanged();
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif // KISINPUTPROFILEMANAGER_H
diff --git a/krita/ui/input/kis_pan_action.cpp b/krita/ui/input/kis_pan_action.cpp
index a2ca296..7164dbe 100644
--- a/krita/ui/input/kis_pan_action.cpp
+++ b/krita/ui/input/kis_pan_action.cpp
@@ -38,10 +38,11 @@ public:
     const int panDistance;
 };
 
-KisPanAction::KisPanAction(KisInputManager *manager)
-    : KisAbstractInputAction(manager), d(new Private)
+KisPanAction::KisPanAction()
+    : d(new Private)
 {
     setName(i18n("Pan Canvas"));
+    setDescription(i18n("The <i>Pan Canvas</i> action pans the canvas."));
 
     QHash<QString, int> shortcuts;
     shortcuts.insert(i18n("Toggle Pan Mode"), PanToggleShortcut);
diff --git a/krita/ui/input/kis_pan_action.h b/krita/ui/input/kis_pan_action.h
index 9944271..656789a 100644
--- a/krita/ui/input/kis_pan_action.h
+++ b/krita/ui/input/kis_pan_action.h
@@ -40,7 +40,7 @@ public:
         PanDownShortcut ///< Pan down by a fixed amount.
     };
 
-    explicit KisPanAction(KisInputManager *manager);
+    explicit KisPanAction();
     virtual ~KisPanAction();
 
     void activate();
diff --git a/krita/ui/input/kis_rotate_canvas_action.cpp b/krita/ui/input/kis_rotate_canvas_action.cpp
index 2cc0810..578fda2 100644
--- a/krita/ui/input/kis_rotate_canvas_action.cpp
+++ b/krita/ui/input/kis_rotate_canvas_action.cpp
@@ -36,10 +36,12 @@ public:
 };
 
 
-KisRotateCanvasAction::KisRotateCanvasAction(KisInputManager* manager)
-    : KisAbstractInputAction(manager), d(new Private())
+KisRotateCanvasAction::KisRotateCanvasAction()
+    : d(new Private())
 {
     setName(i18n("Rotate Canvas"));
+    setDescription(i18n("The <i>Rotate Canvas</i> action rotates the canvas."));
+
     QHash<QString, int> shortcuts;
     shortcuts.insert(i18n("Toggle Rotate Mode"), RotateToggleShortcut);
     shortcuts.insert(i18n("Toggle Discrete Rotate Mode"), DiscreteRotateToggleShortcut);
diff --git a/krita/ui/input/kis_rotate_canvas_action.h b/krita/ui/input/kis_rotate_canvas_action.h
index 30a700f..e247933 100644
--- a/krita/ui/input/kis_rotate_canvas_action.h
+++ b/krita/ui/input/kis_rotate_canvas_action.h
@@ -41,7 +41,7 @@ public:
         RotateRightShortcut, ///< Rotate right by a fixed amount.
         RotateResetShortcut ///< Reset the rotation to 0.
     };
-    explicit KisRotateCanvasAction(KisInputManager* manager);
+    explicit KisRotateCanvasAction();
     virtual ~KisRotateCanvasAction();
 
     void activate();
diff --git a/krita/ui/input/kis_shortcut_configuration.cpp b/krita/ui/input/kis_shortcut_configuration.cpp
new file mode 100644
index 0000000..3eff2c5
--- /dev/null
+++ b/krita/ui/input/kis_shortcut_configuration.cpp
@@ -0,0 +1,349 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 "kis_shortcut_configuration.h"
+
+#include <QStringList>
+#include <QKeySequence>
+#include <KLocalizedString>
+
+class KisShortcutConfiguration::Private
+{
+public:
+    Private()
+        : action(0),
+          type(UnknownType),
+          mode(0),
+          wheel(NoMovement),
+          gesture(NoGesture)
+    { }
+
+    KisAbstractInputAction *action;
+    ShortcutType type;
+    uint mode;
+
+    QList<Qt::Key> keys;
+    Qt::MouseButtons buttons;
+    MouseWheelMovement wheel;
+    GestureAction gesture;
+};
+
+KisShortcutConfiguration::KisShortcutConfiguration()
+    : d(new Private)
+{
+
+}
+
+KisShortcutConfiguration::KisShortcutConfiguration(const KisShortcutConfiguration &other)
+    : d(new Private)
+{
+    d->action = other.action();
+    d->type = other.type();
+    d->mode = other.mode();
+    d->keys = other.keys();
+    d->buttons = other.buttons();
+    d->wheel = other.wheel();
+    d->gesture = other.gesture();
+}
+
+KisShortcutConfiguration::~KisShortcutConfiguration()
+{
+    delete d;
+}
+
+QString KisShortcutConfiguration::serialize()
+{
+    QString serialized("{");
+
+    serialized.append(QString::number(d->mode, 16));
+    serialized.append(';');
+    serialized.append(QString::number(d->type, 16));
+    serialized.append(";[");
+
+    for (QList<Qt::Key>::iterator itr = d->keys.begin(); itr != d->keys.end(); ++itr) {
+        serialized.append(QString::number(*itr, 16));
+
+        if (itr + 1 != d->keys.end()) {
+            serialized.append(',');
+        }
+    }
+
+    serialized.append("];");
+
+    serialized.append(QString::number(d->buttons, 16));
+    serialized.append(';');
+    serialized.append(QString::number(d->wheel, 16));
+    serialized.append(';');
+    serialized.append(QString::number(d->gesture, 16));
+    serialized.append('}');
+
+    return serialized;
+}
+
+bool KisShortcutConfiguration::unserialize(const QString &serialized)
+{
+    if (!serialized.startsWith('{'))
+        return false;
+
+    //Parse the serialized data and apply it to the current shortcut
+    QString remainder = serialized;
+
+    //Remove brackets
+    remainder.remove('{').remove('}');
+
+    //Split the remainder by ;
+    QStringList parts = remainder.split(';');
+
+    if (parts.size() < 6)
+        return false; //Invalid input, abort
+
+    //First entry in the list is the mode
+    d->mode = parts.at(0).toUInt();
+
+    //Second entry is the shortcut type
+    d->type = static_cast<ShortcutType>(parts.at(1).toInt());
+
+    if (d->type == UnknownType) {
+        //Reject input that would set this shortcut to "Unknown"
+        return false;
+    }
+
+    //Third entry is the list of keys
+    QString serializedKeys = parts.at(2);
+    //Remove brackets
+    serializedKeys.remove('[').remove(']');
+    //Split by , and add each entry as a key
+    QStringList keylist = serializedKeys.split(',');
+    Q_FOREACH(QString key, keylist) {
+        if (!key.isEmpty()) {
+            d->keys.append(static_cast<Qt::Key>(key.toUInt(0, 16)));
+        }
+    }
+
+    //Fourth entry is the button mask
+    d->buttons = static_cast<Qt::MouseButtons>(parts.at(3).toInt());
+    d->wheel = static_cast<MouseWheelMovement>(parts.at(4).toUInt());
+    d->gesture = static_cast<GestureAction>(parts.at(5).toUInt());
+
+    return true;
+}
+
+KisAbstractInputAction *KisShortcutConfiguration::action() const
+{
+    return d->action;
+}
+
+void KisShortcutConfiguration::setAction(KisAbstractInputAction *newAction)
+{
+    if (d->action != newAction) {
+        d->action = newAction;
+    }
+}
+
+KisShortcutConfiguration::ShortcutType KisShortcutConfiguration::type() const
+{
+    return d->type;
+}
+
+void KisShortcutConfiguration::setType(KisShortcutConfiguration::ShortcutType newType)
+{
+    if (d->type != newType) {
+        d->type = newType;
+    }
+}
+
+uint KisShortcutConfiguration::mode() const
+{
+    return d->mode;
+}
+
+void KisShortcutConfiguration::setMode(uint newMode)
+{
+    if (d->mode != newMode) {
+        d->mode = newMode;
+    }
+}
+
+QList< Qt::Key > KisShortcutConfiguration::keys() const
+{
+    return d->keys;
+}
+
+void KisShortcutConfiguration::setKeys(const QList< Qt::Key > &newKeys)
+{
+    if (d->keys != newKeys) {
+        d->keys = newKeys;
+    }
+}
+
+Qt::MouseButtons KisShortcutConfiguration::buttons() const
+{
+    return d->buttons;
+}
+
+void KisShortcutConfiguration::setButtons(Qt::MouseButtons newButtons)
+{
+    if (d->buttons != newButtons) {
+        d->buttons = newButtons;
+    }
+}
+
+KisShortcutConfiguration::MouseWheelMovement KisShortcutConfiguration::wheel() const
+{
+    return d->wheel;
+}
+
+void KisShortcutConfiguration::setWheel(KisShortcutConfiguration::MouseWheelMovement type)
+{
+    if (d->wheel != type) {
+        d->wheel = type;
+    }
+}
+
+KisShortcutConfiguration::GestureAction KisShortcutConfiguration::gesture() const
+{
+    return d->gesture;
+}
+
+void KisShortcutConfiguration::setGesture(KisShortcutConfiguration::GestureAction type)
+{
+    if (d->gesture != type) {
+        d->gesture = type;
+    }
+}
+
+QString KisShortcutConfiguration::buttonsToText(Qt::MouseButtons buttons)
+{
+    QString text;
+
+    int buttonCount = 0;
+
+    if (buttons & Qt::LeftButton) {
+        text.append(i18nc("Left Mouse Button", "Left"));
+        buttonCount++;
+    }
+
+    if (buttons & Qt::RightButton) {
+        if (buttonCount++ > 0) {
+            text.append(" + ");
+        }
+
+        text.append(i18nc("Right Mouse Button", "Right"));
+    }
+
+    if (buttons & Qt::MidButton) {
+        if (buttonCount++ > 0) {
+            text.append(" + ");
+        }
+
+        text.append(i18nc("Middle Mouse Button", "Middle"));
+    }
+
+    if (buttons & Qt::XButton1) {
+        if (buttonCount++ > 0) {
+            text.append(" + ");
+        }
+
+        text.append(i18nc("Mouse Back Button", "Back"));
+    }
+
+    if (buttons & Qt::XButton1) {
+        if (buttonCount++ > 0) {
+            text.append(" + ");
+        }
+
+        text.append(i18nc("Mouse Forward Button", "Forward"));
+    }
+
+    if (buttonCount == 0) {
+        text.append(i18nc("No input", "None"));
+    }
+    else {
+        text.append(' ');
+        text.append(i18ncp("Mouse Buttons", "Button", "Buttons", buttonCount));
+    }
+
+    return text;
+}
+
+QString KisShortcutConfiguration::keysToText(const QList<Qt::Key> &keys)
+{
+    QString output;
+
+    foreach (Qt::Key key, keys) {
+        if (output.size() > 0) {
+            output.append(" + ");
+        }
+
+        switch (key) { //Because QKeySequence fails for Ctrl, Alt, Shift and Meta
+        case Qt::Key_Control:
+            output.append(i18nc("Ctrl key", "Ctrl"));
+            break;
+
+        case Qt::Key_Meta:
+            output.append(i18nc("Meta key", "Meta"));
+            break;
+
+        case Qt::Key_Alt:
+            output.append(i18nc("Alt key", "Alt"));
+            break;
+
+        case Qt::Key_Shift:
+            output.append(i18nc("Shift key", "Shift"));
+            break;
+
+        default:
+            QKeySequence s(key);
+            output.append(s.toString(QKeySequence::NativeText));
+            break;
+        }
+
+    }
+
+    if (output.size() == 0) {
+        output = i18nc("No input", "None");
+    }
+
+    return output;
+}
+
+QString KisShortcutConfiguration::wheelToText(KisShortcutConfiguration::MouseWheelMovement wheel)
+{
+    switch (wheel) {
+    case KisShortcutConfiguration::WheelUp:
+        return i18n("Mouse Wheel Up");
+        break;
+
+    case KisShortcutConfiguration::WheelDown:
+        return i18n("Mouse Wheel Down");
+        break;
+
+    case KisShortcutConfiguration::WheelLeft:
+        return i18n("Mouse Wheel Left");
+        break;
+
+    case KisShortcutConfiguration::WheelRight:
+        return i18n("Mouse Wheel Right");
+        break;
+
+    default:
+        return i18nc("No input", "None");
+        break;
+    }
+}
diff --git a/krita/ui/input/kis_shortcut_configuration.h b/krita/ui/input/kis_shortcut_configuration.h
new file mode 100644
index 0000000..3e78d41
--- /dev/null
+++ b/krita/ui/input/kis_shortcut_configuration.h
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2013 Arjen Hiemstra <ahiemstra at heimr.nl>
+ *
+ * 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 KISSHORTCUTCONFIGURATION_H
+#define KISSHORTCUTCONFIGURATION_H
+
+#include <QList>
+#include <QMetaType>
+
+class QString;
+class KisAbstractInputAction;
+
+/**
+ * \brief A class encapsulating all settings for a single shortcut.
+ *
+ * This class encapsulates mouse buttons, keyboard keys and other settings
+ * related to a single shortcut for a single action.
+ *
+ * \note Each action can have several modes that activate it with usually
+ * different behaviour for each mode. Different shortcuts can activate
+ * different modes.
+ */
+class KisShortcutConfiguration
+{
+public:
+    /**
+     * The type of shortcut, i.e. what kind of input does it expect.
+     */
+    enum ShortcutType {
+        UnknownType, ///< Unknown, empty shortcut.
+        KeyCombinationType, ///< A list of keys that should be pressed.
+        MouseButtonType, ///< A mouse button, possibly with key modifiers.
+        MouseWheelType, ///< Mouse wheel movement, possibly with key modifiers.
+        GestureType, ///< A touch gesture.
+    };
+
+    /**
+     * The type of mouse wheel movement.
+     */
+    enum MouseWheelMovement {
+        NoMovement, ///< No movement.
+        WheelUp, ///< Upwards movement, away from the user.
+        WheelDown, ///< Downwards movement, toward the user.
+        WheelLeft, ///< Left movement.
+        WheelRight, ///< Right movement.
+    };
+
+    /**
+     * The type of gesture.
+     */
+    enum GestureAction {
+        NoGesture, ///< No gesture.
+        PinchGesture, ///< Pinch gesture, fingers moving towards or away from each other.
+        PanGesture, ///< Pan gesture, fingers staying together but moving across the screen.
+    };
+
+    /**
+     * Constructor.
+     */
+    KisShortcutConfiguration();
+    /**
+     * Copy constructor.
+     */
+    KisShortcutConfiguration(const KisShortcutConfiguration &other);
+    /**
+     * Destructor.
+     */
+    virtual ~KisShortcutConfiguration();
+
+    /**
+     * Serialize the data of this shortcut into a string that can be saved into
+     * a configuration file.
+     *
+     * The string will have the following format:
+     *
+     *     {mode;type;[key,key];buttons;wheel;gesture}
+     *
+     * with each property serialized into a base-16 integer.
+     *
+     * \return A serialized representation of this shortcut.
+     */
+    QString serialize();
+    /**
+     * Apply the data from a serialized shortcut to this shortcut.
+     *
+     * This method expects a string as described in serialize().
+     *
+     * \param serialized The serialized shortcut.
+     *
+     * \return true if successful, false if an error occurred.
+     *
+     * \sa serialize()
+     */
+    bool unserialize(const QString &serialized);
+
+    /**
+     * \return The action this shortcut is associated with.
+     */
+    KisAbstractInputAction *action() const;
+    /**
+     * Set the action this shortcut should be associated with.
+     *
+     * \param newAction The action to set.
+     */
+    void setAction(KisAbstractInputAction *newAction);
+
+    /**
+     * \return The type of shortcut.
+     */
+    ShortcutType type() const;
+    /**
+     * Set the type of shortcut.
+     *
+     * \param newType The type to set.
+     */
+    void setType(ShortcutType newType);
+
+    /**
+     * \return The mode of the action this shortcut will trigger.
+     */
+    uint mode() const;
+    /**
+     * Set the mode of the action this shortcut will trigger.
+     *
+     * \param newMode The mode to set.
+     */
+    void setMode(uint newMode);
+
+    /**
+     * \return The list of keys that will trigger this shortcut.
+     *
+     * \note Not applicable when type is GestureType.
+     */
+    QList<Qt::Key> keys() const;
+    /**
+     * Set the list of keys that will trigger this shortcut.
+     *
+     * \param newKeys The list of keys to use.
+     *
+     * \note Not applicable when type is GestureType.
+     */
+    void setKeys(const QList<Qt::Key> &newKeys);
+
+    /**
+     * \return The mouse buttons that will trigger this shortcut.
+     *
+     * \note Only applicable when type is MouseButtonType.
+     */
+    Qt::MouseButtons buttons() const;
+    /**
+     * Set the mouse buttons that will trigger this shortcut.
+     *
+     * \param newButtons The mouse buttons to use.
+     *
+     * \note Only applicable when type is MouseButtonType.
+     */
+    void setButtons(Qt::MouseButtons newButtons);
+
+    /**
+     * \return The mouse wheel movement that will trigger this shortcut.
+     *
+     * \note Only applicable when type is MouseWheelType.
+     */
+    MouseWheelMovement wheel() const;
+    /**
+     * Set the mouse wheel movement that will trigger this shortcut.
+     *
+     * \param type The wheel movement to use.
+     *
+     * \note Only applicable when type is MouseWheelType.
+     */
+    void setWheel(MouseWheelMovement type);
+
+    /**
+     * \return The gesture that will trigger this shortcut.
+     *
+     * \note Only applicable when type is GestureType.
+     */
+    GestureAction gesture() const;
+    /**
+     * Set the gesture that will trigger this shortcut.
+     *
+     * \param type The gesture to use.
+     *
+     * \note Only applicable when type is GestureType.
+     */
+    void setGesture(GestureAction type);
+
+    /**
+     * Convert a set of mouse buttons into a user-readable
+     * string.
+     *
+     * This will convert the given set of buttons into a
+     * string that can be shown to a user. For example, the
+     * combination Qt::LeftButton + Qt::RightButton will produce
+     * the string "Left + Right Button".
+     *
+     * \param buttons The buttons to convert.
+     *
+     * \return A string representing the buttons that can be shown
+     * to a user.
+     *
+     * \note An empty set will produce the string "No Input".
+     */
+    static QString buttonsToText(Qt::MouseButtons buttons);
+    /**
+     * Convert a list of keys to a user-readable string.
+     *
+     * This will convert the given list of keys into a string
+     * that can be shown to a user. For example, the list
+     * [Qt::Key_Shift, Qt::Key_Space] will produce the string
+     * "Shift + Space".
+     *
+     * \param keys The keys to convert.
+     *
+     * \return A string representing the keys that can be shown
+     * to a user.
+     *
+     * \note An empty list will produce the string "No Input".
+     */
+    static QString keysToText(const QList<Qt::Key> &keys);
+    /**
+     * Convert the given mouse wheel movement to a string.
+     *
+     * This will convert the given mouse wheel movement into a
+     * string that can be shown to a user. For example, WheelUp
+     * will produce the string "Mouse Wheel Up".
+     *
+     * \param wheel The mouse wheel movement to convert.
+     *
+     * \return A string representing the mouse wheel movement
+     * that can be shown to a user.
+     *
+     * \note NoMovement will produce the string "No Input".
+     */
+    static QString wheelToText(MouseWheelMovement wheel);
+
+private:
+    class Private;
+    Private *const d;
+};
+
+Q_DECLARE_METATYPE(KisShortcutConfiguration *);
+
+#endif // KISSHORTCUTCONFIGURATION_H
diff --git a/krita/ui/input/kis_shortcut_matcher.cpp b/krita/ui/input/kis_shortcut_matcher.cpp
index 0f21108..d2392b5 100644
--- a/krita/ui/input/kis_shortcut_matcher.cpp
+++ b/krita/ui/input/kis_shortcut_matcher.cpp
@@ -213,6 +213,14 @@ void KisShortcutMatcher::suppressAllActions(bool value)
     m_d->suppressAllActions = value;
 }
 
+void KisShortcutMatcher::clearShortcuts()
+{
+    qDeleteAll(m_d->singleActionShortcuts);
+    m_d->singleActionShortcuts.clear();
+    qDeleteAll(m_d->strokeShortcuts);
+    m_d->strokeShortcuts.clear();
+}
+
 bool KisShortcutMatcher::tryRunWheelShortcut(KisSingleActionShortcut::WheelAction wheelAction, QWheelEvent *event)
 {
     return tryRunSingleActionShortcutImpl(wheelAction, event, m_d->keys);
diff --git a/krita/ui/input/kis_shortcut_matcher.h b/krita/ui/input/kis_shortcut_matcher.h
index 3e3e7cc..f87dd68 100644
--- a/krita/ui/input/kis_shortcut_matcher.h
+++ b/krita/ui/input/kis_shortcut_matcher.h
@@ -183,6 +183,11 @@ public:
      */
     void suppressAllActions(bool value);
 
+    /**
+     * Remove all shortcuts that have been registered.
+     */
+    void clearShortcuts();
+
 private:
     friend class KisInputManagerTest;
 
diff --git a/krita/ui/input/kis_show_palette_action.cpp b/krita/ui/input/kis_show_palette_action.cpp
index 96cfd6b..b6fddaa 100644
--- a/krita/ui/input/kis_show_palette_action.cpp
+++ b/krita/ui/input/kis_show_palette_action.cpp
@@ -25,10 +25,10 @@
 
 #include "kis_input_manager.h"
 
-KisShowPaletteAction::KisShowPaletteAction(KisInputManager* manager)
-    : KisAbstractInputAction(manager)
+KisShowPaletteAction::KisShowPaletteAction()
 {
     setName(i18n("Show Popup Palette"));
+    setDescription(i18n("The <i>Show Popup Palette</i> displays the popup palette."));
 }
 
 KisShowPaletteAction::~KisShowPaletteAction()
diff --git a/krita/ui/input/kis_show_palette_action.h b/krita/ui/input/kis_show_palette_action.h
index ebafab3..5f16a9a 100644
--- a/krita/ui/input/kis_show_palette_action.h
+++ b/krita/ui/input/kis_show_palette_action.h
@@ -29,7 +29,7 @@
 class KisShowPaletteAction : public KisAbstractInputAction
 {
 public:
-    explicit KisShowPaletteAction(KisInputManager* manager);
+    explicit KisShowPaletteAction();
     virtual ~KisShowPaletteAction();
 
     virtual void begin(int, QEvent *);
diff --git a/krita/ui/input/kis_single_action_shortcut.h b/krita/ui/input/kis_single_action_shortcut.h
index 9660947..d90a9ab 100644
--- a/krita/ui/input/kis_single_action_shortcut.h
+++ b/krita/ui/input/kis_single_action_shortcut.h
@@ -32,7 +32,9 @@ class KRITAUI_EXPORT KisSingleActionShortcut : public KisAbstractShortcut
 public:
     enum WheelAction {
         WheelUp, ///< Mouse wheel moves up.
-        WheelDown ///< Mouse wheel moves down.
+        WheelDown, ///< Mouse wheel moves down.
+        WheelLeft, ///< Mouse wheel moves left.
+        WheelRight, ///< Mouse wheel moves right.
     };
 
     KisSingleActionShortcut(KisAbstractInputAction *action, int index);
diff --git a/krita/ui/input/kis_tool_invocation_action.cpp b/krita/ui/input/kis_tool_invocation_action.cpp
index 3159af1..0537ba6 100644
--- a/krita/ui/input/kis_tool_invocation_action.cpp
+++ b/krita/ui/input/kis_tool_invocation_action.cpp
@@ -39,11 +39,17 @@ public:
     bool active;
 };
 
-KisToolInvocationAction::KisToolInvocationAction(KisInputManager *manager)
-    : KisAbstractInputAction(manager), d(new Private(this))
+KisToolInvocationAction::KisToolInvocationAction()
+    : d(new Private(this))
 {
     setName(i18n("Tool Invocation"));
-    setDescription(i18n("Tool Invocation invokes the current tool, for example, using the brush tool, it will start painting."));
+    setDescription(i18n("The <i>Tool Invocation</i> action invokes the current tool, for example, using the brush tool, it will start painting."));
+
+    QHash<QString, int> indexes;
+    indexes.insert(i18n("Activate"), ActivateShortcut);
+    indexes.insert(i18n("Confirm"), ConfirmShortcut);
+    indexes.insert(i18n("Cancel"), CancelShortcut);
+    setShortcutIndexes(indexes);
 }
 
 KisToolInvocationAction::~KisToolInvocationAction()
@@ -95,7 +101,7 @@ void KisToolInvocationAction::end(QEvent *event)
 
         if (tabletEvent) {
             inputManager()->toolProxy()->tabletEvent(tabletEvent, d->tabletToPixel(tabletEvent->hiResGlobalPos()));
-        } else {
+        } else if (mouseEvent) {
             inputManager()->toolProxy()->mouseReleaseEvent(mouseEvent, inputManager()->widgetToPixel(mouseEvent->posF()));
         }
 
diff --git a/krita/ui/input/kis_tool_invocation_action.h b/krita/ui/input/kis_tool_invocation_action.h
index 0662c7d..0dc5c62 100644
--- a/krita/ui/input/kis_tool_invocation_action.h
+++ b/krita/ui/input/kis_tool_invocation_action.h
@@ -35,7 +35,7 @@ public:
         ConfirmShortcut,
         CancelShortcut
     };
-    explicit KisToolInvocationAction(KisInputManager *manager);
+    explicit KisToolInvocationAction();
     virtual ~KisToolInvocationAction();
 
     void begin(int shortcut, QEvent *event);
diff --git a/krita/ui/input/kis_zoom_action.cpp b/krita/ui/input/kis_zoom_action.cpp
index 3d0e96b..8b96a39 100644
--- a/krita/ui/input/kis_zoom_action.cpp
+++ b/krita/ui/input/kis_zoom_action.cpp
@@ -76,10 +76,11 @@ void KisZoomAction::Private::zoomTo(bool zoomIn, QEvent *event)
     }
 }
 
-KisZoomAction::KisZoomAction(KisInputManager* manager)
-    : KisAbstractInputAction(manager), d(new Private(this))
+KisZoomAction::KisZoomAction()
+    : d(new Private(this))
 {
     setName(i18n("Zoom Canvas"));
+    setDescription(i18n("The <i>Zoom Canvas</i> action zooms the canvas."));
 
     QHash< QString, int > shortcuts;
     shortcuts.insert(i18n("Toggle Zoom Mode"), ZoomToggleShortcut);
diff --git a/krita/ui/input/kis_zoom_action.h b/krita/ui/input/kis_zoom_action.h
index f49a3f4..ba85575 100644
--- a/krita/ui/input/kis_zoom_action.h
+++ b/krita/ui/input/kis_zoom_action.h
@@ -41,7 +41,7 @@ public:
         ZoomToPageShortcut, ///< Zoom fit to page.
         ZoomToWidthShortcut ///< Zoom fit to width.
     };
-    explicit KisZoomAction(KisInputManager* manager);
+    explicit KisZoomAction();
     virtual ~KisZoomAction();
 
     void activate();
diff --git a/krita/ui/kis_config.cc b/krita/ui/kis_config.cc
index c6e50da..8234289 100644
--- a/krita/ui/kis_config.cc
+++ b/krita/ui/kis_config.cc
@@ -933,6 +933,15 @@ void KisConfig::setToolbarSlider(int sliderNumber, const QString &slider)
     m_cfg.writeEntry(QString("toolbarslider_%1").arg(sliderNumber), slider);
 }
 
+QString KisConfig::currentInputProfile() const
+{
+    return m_cfg.readEntry("currentInputProfile", QString());
+}
+
+void KisConfig::setCurrentInputProfile(const QString& name)
+{
+    m_cfg.writeEntry("currentInputProfile", name);
+}
 
 bool KisConfig::useSystemMonitorProfile() const
 {
diff --git a/krita/ui/kis_config.h b/krita/ui/kis_config.h
index dace8b7..bed0a98 100644
--- a/krita/ui/kis_config.h
+++ b/krita/ui/kis_config.h
@@ -287,6 +287,9 @@ public:
     QString toolbarSlider(int sliderNumber);
     void setToolbarSlider(int sliderNumber, const QString &slider);
 
+    QString currentInputProfile() const;
+    void setCurrentInputProfile(const QString& name);
+
     template<class T>
     void writeEntry(const QString& name, const T& value) {
         m_cfg.writeEntry(name, value);
diff --git a/krita/ui/kis_view2.cpp b/krita/ui/kis_view2.cpp
index 0b9a254..c8b8d84 100644
--- a/krita/ui/kis_view2.cpp
+++ b/krita/ui/kis_view2.cpp
@@ -128,6 +128,7 @@
 #include <kis_paintop_preset.h>
 #include "ko_favorite_resource_manager.h"
 #include "kis_action_manager.h"
+#include "input/kis_input_profile_manager.h"
 #include "kis_paintop_box.h"
 
 
@@ -407,6 +408,8 @@ KisView2::KisView2(KoPart *part, KisDoc2 * doc, QWidget * parent)
         collection->readSettings(&group);
     }
 
+    KisInputProfileManager::instance()->loadProfiles();
+
 
 #if 0
     //check for colliding shortcuts
diff --git a/krita/ui/tests/kis_input_manager_test.cpp b/krita/ui/tests/kis_input_manager_test.cpp
index b973f1a..51bfcc8 100644
--- a/krita/ui/tests/kis_input_manager_test.cpp
+++ b/krita/ui/tests/kis_input_manager_test.cpp
@@ -72,7 +72,7 @@ void KisInputManagerTest::testStrokeShortcut()
 
 struct TestingAction : public KisAbstractInputAction
 {
-    TestingAction() : KisAbstractInputAction(0), m_isHighResolution(false) { reset(); }
+    TestingAction() : KisAbstractInputAction(), m_isHighResolution(false) { reset(); }
     ~TestingAction() {}
 
     void begin(int shortcut, QEvent *event) { m_beginIndex = shortcut; m_beginNonNull = event;}


More information about the kde-doc-english mailing list