Add KKeySequence QtQuick clone
This commit is contained in:
parent
6599c25087
commit
7e7fe6f972
@ -7,3 +7,4 @@ add_subdirectory(plasmacomponents)
|
|||||||
add_subdirectory(plasmaextracomponents)
|
add_subdirectory(plasmaextracomponents)
|
||||||
add_subdirectory(platformcomponents)
|
add_subdirectory(platformcomponents)
|
||||||
add_subdirectory(calendar)
|
add_subdirectory(calendar)
|
||||||
|
add_subdirectory(kquickcontrols)
|
||||||
|
7
src/declarativeimports/kquickcontrols/CMakeLists.txt
Normal file
7
src/declarativeimports/kquickcontrols/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
project(kquickcontrols)
|
||||||
|
|
||||||
|
install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/kquickcontrols)
|
||||||
|
install(FILES KeySequenceItem.qml DESTINATION ${QML_INSTALL_DIR}/org/kde/kquickcontrols)
|
||||||
|
|
||||||
|
add_subdirectory(private)
|
||||||
|
|
65
src/declarativeimports/kquickcontrols/KeySequenceItem.qml
Normal file
65
src/declarativeimports/kquickcontrols/KeySequenceItem.qml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 1.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
|
||||||
|
import org.kde.private.kquickcontrols 2.0 as KQuickControlsPrivate
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
property alias showClearButton: clearButton.visible
|
||||||
|
property alias modifierlessAllowed: _helper.modifierlessAllowed
|
||||||
|
property alias multiKeyShortcutsAllowed: _helper.multiKeyShortcutsAllowed
|
||||||
|
property alias keySequence: _helper.keySequence
|
||||||
|
|
||||||
|
|
||||||
|
KQuickControlsPrivate.KeySequenceHelper {
|
||||||
|
id: _helper
|
||||||
|
|
||||||
|
onCaptureFinished: {
|
||||||
|
mainButton.checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
id: mainButton
|
||||||
|
|
||||||
|
iconName: "configure"
|
||||||
|
|
||||||
|
property string shortcut
|
||||||
|
checkable: true
|
||||||
|
focus: checked
|
||||||
|
|
||||||
|
text: _helper.shortcutDisplay
|
||||||
|
tooltip: i18n("Click on the button, then enter the shortcut like you would in the program.\nExample for Ctrl+A: hold the Ctrl key and press A.")
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (checked) {
|
||||||
|
mainButton.forceActiveFocus()
|
||||||
|
_helper.captureKeySequence()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
if (!focus) {
|
||||||
|
mainButton.checked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
_helper.keyPressed(event.key, event.modifiers);
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
Keys.onReleased: {
|
||||||
|
_helper.keyReleased(event.key, event.modifiers);
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: clearButton
|
||||||
|
onClicked: _helper.clearKeySequence();
|
||||||
|
|
||||||
|
//icon name determines the direction of the arrow, NOT the direction of the app layout
|
||||||
|
iconName: Qt.application.layoutDirection == Qt.LeftToRight ? "edit-clear-locationbar-rtl" : "edit-clear-locationbar-ltr"
|
||||||
|
}
|
||||||
|
}
|
1
src/declarativeimports/kquickcontrols/README
Normal file
1
src/declarativeimports/kquickcontrols/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
This import contains KDE extras that are visually similar to Qt Quick Controls.
|
23
src/declarativeimports/kquickcontrols/private/CMakeLists.txt
Normal file
23
src/declarativeimports/kquickcontrols/private/CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
project(kquickcontrolsprivate)
|
||||||
|
|
||||||
|
set(kquickcontrolsprivate_SRCS
|
||||||
|
kquickcontrolsprivateplugin.cpp
|
||||||
|
keysequencehelper.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(kquickcontrolsprivateplugin SHARED ${kquickcontrolsprivate_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(kquickcontrolsprivateplugin
|
||||||
|
Qt5::Core
|
||||||
|
Qt5::Quick
|
||||||
|
Qt5::Qml
|
||||||
|
KF5::I18n
|
||||||
|
KF5::ConfigGui
|
||||||
|
KF5::WidgetsAddons
|
||||||
|
KF5::WindowSystem
|
||||||
|
KF5::GlobalAccel
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS kquickcontrolsprivateplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/private/kquickcontrols)
|
||||||
|
|
||||||
|
install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/private/kquickcontrols)
|
@ -0,0 +1,567 @@
|
|||||||
|
/*
|
||||||
|
* <one line to give the library's name and an idea of what it does.>
|
||||||
|
* Copyright (C) 2014 David Edmundson <davidedmundson@kde.org>
|
||||||
|
* Copyright (C) 1998 Mark Donohoe <donohoe@kde.org>
|
||||||
|
* Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
|
||||||
|
* Copyright (C) 2007 Andreas Hartmetz <ahartmetz@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "keysequencehelper.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QtCore/QHash>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <KStandardShortcut>
|
||||||
|
#include <KLocalizedString>
|
||||||
|
#include <KMessageBox>
|
||||||
|
#include <KKeyServer>
|
||||||
|
#include <KGlobalAccel/KGlobalShortcutInfo>
|
||||||
|
#include <KGlobalAccel/KGlobalAccel>
|
||||||
|
|
||||||
|
uint qHash(const QKeySequence &seq)
|
||||||
|
{
|
||||||
|
return qHash(seq.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
class KeySequenceHelperPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeySequenceHelperPrivate(KeySequenceHelper *q);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
static QKeySequence appendToSequence(const QKeySequence &seq, int keyQt);
|
||||||
|
static bool isOkWhenModifierless(int keyQt);
|
||||||
|
|
||||||
|
void updateShortcutDisplay();
|
||||||
|
void startRecording();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conflicts the key sequence @a seq with a current standard
|
||||||
|
* shortcut?
|
||||||
|
*/
|
||||||
|
bool conflictWithStandardShortcuts(const QKeySequence &seq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conflicts the key sequence @a seq with a current local
|
||||||
|
* shortcut?
|
||||||
|
*/
|
||||||
|
bool conflictWithLocalShortcuts(const QKeySequence &seq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conflicts the key sequence @a seq with a current global
|
||||||
|
* shortcut?
|
||||||
|
*/
|
||||||
|
bool conflictWithGlobalShortcuts(const QKeySequence &seq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get permission to steal the shortcut @seq from the standard shortcut @a std.
|
||||||
|
*/
|
||||||
|
bool stealStandardShortcut(KStandardShortcut::StandardShortcut std, const QKeySequence &seq);
|
||||||
|
|
||||||
|
bool checkAgainstStandardShortcuts() const
|
||||||
|
{
|
||||||
|
return checkAgainstShortcutTypes & KeySequenceHelper::StandardShortcuts;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkAgainstGlobalShortcuts() const
|
||||||
|
{
|
||||||
|
return checkAgainstShortcutTypes & KeySequenceHelper::GlobalShortcuts;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkAgainstLocalShortcuts() const
|
||||||
|
{
|
||||||
|
return checkAgainstShortcutTypes & KeySequenceHelper::LocalShortcuts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void controlModifierlessTimout()
|
||||||
|
{
|
||||||
|
if (nKey != 0 && !modifierKeys) {
|
||||||
|
// No modifier key pressed currently. Start the timout
|
||||||
|
modifierlessTimeout.start(600);
|
||||||
|
} else {
|
||||||
|
// A modifier is pressed. Stop the timeout
|
||||||
|
modifierlessTimeout.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancelRecording()
|
||||||
|
{
|
||||||
|
keySequence = oldKeySequence;
|
||||||
|
q->doneRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool promptStealShortcutSystemwide(
|
||||||
|
QWidget *parent,
|
||||||
|
const QHash<QKeySequence, QList<KGlobalShortcutInfo> > &shortcuts,
|
||||||
|
const QKeySequence &sequence)
|
||||||
|
{
|
||||||
|
if (shortcuts.isEmpty()) {
|
||||||
|
// Usage error. Just say no
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString clashingKeys;
|
||||||
|
Q_FOREACH (const QKeySequence &seq, shortcuts.keys()) {
|
||||||
|
Q_FOREACH (const KGlobalShortcutInfo &info, shortcuts[seq]) {
|
||||||
|
clashingKeys += i18n("Shortcut '%1' in Application %2 for action %3\n",
|
||||||
|
seq.toString(),
|
||||||
|
info.componentFriendlyName(),
|
||||||
|
info.friendlyName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int hashSize = shortcuts.size();
|
||||||
|
|
||||||
|
QString message = i18ncp("%1 is the number of conflicts (hidden), %2 is the key sequence of the shortcut that is problematic",
|
||||||
|
"The shortcut '%2' conflicts with the following key combination:\n",
|
||||||
|
"The shortcut '%2' conflicts with the following key combinations:\n",
|
||||||
|
hashSize, sequence.toString());
|
||||||
|
message += clashingKeys;
|
||||||
|
|
||||||
|
QString title = i18ncp("%1 is the number of shortcuts with which there is a conflict",
|
||||||
|
"Conflict with Registered Global Shortcut", "Conflict with Registered Global Shortcuts", hashSize);
|
||||||
|
|
||||||
|
return KMessageBox::warningContinueCancel(parent, message, title, KGuiItem(i18n("Reassign")))
|
||||||
|
== KMessageBox::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//members
|
||||||
|
KeySequenceHelper *const q;
|
||||||
|
QToolButton *clearButton;
|
||||||
|
|
||||||
|
QKeySequence keySequence;
|
||||||
|
QKeySequence oldKeySequence;
|
||||||
|
QTimer modifierlessTimeout;
|
||||||
|
bool allowModifierless;
|
||||||
|
uint nKey;
|
||||||
|
uint modifierKeys;
|
||||||
|
bool isRecording;
|
||||||
|
bool multiKeyShortcutsAllowed;
|
||||||
|
QString componentName;
|
||||||
|
QString shortcutDisplay;
|
||||||
|
|
||||||
|
//! Check the key sequence against KStandardShortcut::find()
|
||||||
|
KeySequenceHelper::ShortcutTypes checkAgainstShortcutTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of action to check against for conflict shortcut
|
||||||
|
*/
|
||||||
|
QList<QAction *> checkList; // deprecated
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of action collections to check against for conflict shortcut
|
||||||
|
*/
|
||||||
|
// QList<KActionCollection *> checkActionCollections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The action to steal the shortcut from.
|
||||||
|
*/
|
||||||
|
QList<QAction *> stealActions;
|
||||||
|
|
||||||
|
bool stealShortcuts(const QList<QAction *> &actions, const QKeySequence &seq);
|
||||||
|
void wontStealShortcut(QAction *item, const QKeySequence &seq);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
KeySequenceHelperPrivate::KeySequenceHelperPrivate(KeySequenceHelper *q)
|
||||||
|
: q(q)
|
||||||
|
, allowModifierless(false)
|
||||||
|
, nKey(0)
|
||||||
|
, modifierKeys(0)
|
||||||
|
, isRecording(false)
|
||||||
|
, multiKeyShortcutsAllowed(true)
|
||||||
|
, componentName()
|
||||||
|
, checkAgainstShortcutTypes(KeySequenceHelper::LocalShortcuts | KeySequenceHelper::GlobalShortcuts)
|
||||||
|
, stealActions()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
KeySequenceHelper::KeySequenceHelper(QObject* parent):
|
||||||
|
QObject(),
|
||||||
|
d(new KeySequenceHelperPrivate(this))
|
||||||
|
{
|
||||||
|
connect(&d->modifierlessTimeout, SIGNAL(timeout()), this, SLOT(doneRecording()));
|
||||||
|
d->updateShortcutDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KeySequenceHelper::~KeySequenceHelper()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeySequenceHelper::multiKeyShortcutsAllowed() const
|
||||||
|
{
|
||||||
|
return d->multiKeyShortcutsAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeySequenceHelper::setMultiKeyShortcutsAllowed(bool allowed)
|
||||||
|
{
|
||||||
|
d->multiKeyShortcutsAllowed = allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeySequenceHelper::setModifierlessAllowed(bool allow)
|
||||||
|
{
|
||||||
|
d->allowModifierless = allow;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeySequenceHelper::isModifierlessAllowed()
|
||||||
|
{
|
||||||
|
return d->allowModifierless;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeySequenceHelper::isKeySequenceAvailable(const QKeySequence& keySequence) const
|
||||||
|
{
|
||||||
|
if (keySequence.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !(d->conflictWithGlobalShortcuts(keySequence)
|
||||||
|
|| d->conflictWithStandardShortcuts(keySequence));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// void KeySequenceHelper::setCheckActionCollections(const QList<KActionCollection *> &actionCollections)
|
||||||
|
// {
|
||||||
|
// d->checkActionCollections = actionCollections;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
//slot
|
||||||
|
void KeySequenceHelper::captureKeySequence()
|
||||||
|
{
|
||||||
|
d->startRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
QKeySequence KeySequenceHelper::keySequence() const
|
||||||
|
{
|
||||||
|
return d->keySequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeySequenceHelper::setKeySequence(const QKeySequence& sequence)
|
||||||
|
{
|
||||||
|
if (!d->isRecording) {
|
||||||
|
d->oldKeySequence = d->keySequence;
|
||||||
|
}
|
||||||
|
d->keySequence = sequence;
|
||||||
|
doneRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KeySequenceHelper::clearKeySequence()
|
||||||
|
{
|
||||||
|
setKeySequence(QKeySequence());
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeySequenceHelperPrivate::startRecording()
|
||||||
|
{
|
||||||
|
nKey = 0;
|
||||||
|
modifierKeys = 0;
|
||||||
|
oldKeySequence = keySequence;
|
||||||
|
keySequence = QKeySequence();
|
||||||
|
isRecording = true;
|
||||||
|
|
||||||
|
updateShortcutDisplay();
|
||||||
|
}
|
||||||
|
//
|
||||||
|
void KeySequenceHelper::doneRecording()
|
||||||
|
{
|
||||||
|
d->modifierlessTimeout.stop();
|
||||||
|
d->isRecording = false;
|
||||||
|
d->stealActions.clear();
|
||||||
|
|
||||||
|
if (d->keySequence == d->oldKeySequence) {
|
||||||
|
// The sequence hasn't changed
|
||||||
|
d->updateShortcutDisplay();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! isKeySequenceAvailable(d->keySequence)) {
|
||||||
|
// The sequence had conflicts and the user said no to stealing it
|
||||||
|
d->keySequence = d->oldKeySequence;
|
||||||
|
} else {
|
||||||
|
emit keySequenceChanged(d->keySequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_EMIT captureFinished();
|
||||||
|
|
||||||
|
d->updateShortcutDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool KeySequenceHelperPrivate::conflictWithGlobalShortcuts(const QKeySequence &keySequence)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
//on windows F12 is reserved by the debugger at all times, so we can't use it for a global shortcut
|
||||||
|
if (KeySequenceHelper::GlobalShortcuts && keySequence.toString().contains("F12")) {
|
||||||
|
QString title = i18n("Reserved Shortcut");
|
||||||
|
QString message = i18n("The F12 key is reserved on Windows, so cannot be used for a global shortcut.\n"
|
||||||
|
"Please choose another one.");
|
||||||
|
|
||||||
|
KMessageBox::sorry(q, message, title);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!(checkAgainstShortcutTypes & KeySequenceHelper::GlobalShortcuts)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global shortcuts are on key+modifier shortcuts. They can clash with
|
||||||
|
// each of the keys of a multi key shortcut.
|
||||||
|
QHash<QKeySequence, QList<KGlobalShortcutInfo> > others;
|
||||||
|
for (int i = 0; i < keySequence.count(); ++i) {
|
||||||
|
QKeySequence tmp(keySequence[i]);
|
||||||
|
|
||||||
|
if (!KGlobalAccel::isGlobalShortcutAvailable(tmp, componentName)) {
|
||||||
|
others.insert(tmp, KGlobalAccel::getGlobalShortcutsByKey(tmp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!others.isEmpty()
|
||||||
|
&& !promptStealShortcutSystemwide(0, others, keySequence)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user approved stealing the shortcut. We have to steal
|
||||||
|
// it immediately because KAction::setGlobalShortcut() refuses
|
||||||
|
// to set a global shortcut that is already used. There is no
|
||||||
|
// error it just silently fails. So be nice because this is
|
||||||
|
// most likely the first action that is done in the slot
|
||||||
|
// listening to keySequenceChanged().
|
||||||
|
for (int i = 0; i < keySequence.count(); ++i) {
|
||||||
|
KGlobalAccel::stealShortcutSystemwide(keySequence[i]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeySequenceHelperPrivate::conflictWithStandardShortcuts(const QKeySequence &keySequence)
|
||||||
|
{
|
||||||
|
if (!checkAgainstStandardShortcuts()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KStandardShortcut::StandardShortcut ssc = KStandardShortcut::find(keySequence);
|
||||||
|
if (ssc != KStandardShortcut::AccelNone && !stealStandardShortcut(ssc, keySequence)) {
|
||||||
|
qDebug() << "!!!!!!!!!!!!!!";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeySequenceHelperPrivate::stealStandardShortcut(KStandardShortcut::StandardShortcut std, const QKeySequence &seq)
|
||||||
|
{
|
||||||
|
QString title = i18n("Conflict with Standard Application Shortcut");
|
||||||
|
QString message = i18n("The '%1' key combination is also used for the standard action "
|
||||||
|
"\"%2\" that some applications use.\n"
|
||||||
|
"Do you really want to use it as a global shortcut as well?",
|
||||||
|
seq.toString(QKeySequence::NativeText), KStandardShortcut::label(std));
|
||||||
|
|
||||||
|
if (KMessageBox::warningContinueCancel(0, message, title, KGuiItem(i18n("Reassign"))) != KMessageBox::Continue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeySequenceHelperPrivate::updateShortcutDisplay()
|
||||||
|
{
|
||||||
|
//empty string if no non-modifier was pressed
|
||||||
|
QString s = keySequence.toString(QKeySequence::NativeText);
|
||||||
|
s.replace(QLatin1Char('&'), QStringLiteral("&&"));
|
||||||
|
|
||||||
|
if (isRecording) {
|
||||||
|
if (modifierKeys) {
|
||||||
|
if (!s.isEmpty()) {
|
||||||
|
s.append(QLatin1Char(','));
|
||||||
|
}
|
||||||
|
if (modifierKeys & Qt::META) {
|
||||||
|
s += KKeyServer::modToStringUser(Qt::META) + QLatin1Char('+');
|
||||||
|
}
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
if (modifierKeys & Qt::ALT) {
|
||||||
|
s += KKeyServer::modToStringUser(Qt::ALT) + QLatin1Char('+');
|
||||||
|
}
|
||||||
|
if (modifierKeys & Qt::CTRL) {
|
||||||
|
s += KKeyServer::modToStringUser(Qt::CTRL) + QLatin1Char('+');
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (modifierKeys & Qt::CTRL) {
|
||||||
|
s += KKeyServer::modToStringUser(Qt::CTRL) + QLatin1Char('+');
|
||||||
|
}
|
||||||
|
if (modifierKeys & Qt::ALT) {
|
||||||
|
s += KKeyServer::modToStringUser(Qt::ALT) + QLatin1Char('+');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (modifierKeys & Qt::SHIFT) {
|
||||||
|
s += KKeyServer::modToStringUser(Qt::SHIFT) + QLatin1Char('+');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (nKey == 0) {
|
||||||
|
s = i18nc("What the user inputs now will be taken as the new shortcut", "Input");
|
||||||
|
}
|
||||||
|
//make it clear that input is still going on
|
||||||
|
s.append(QStringLiteral(" ..."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.isEmpty()) {
|
||||||
|
s = i18nc("No shortcut defined", "None");
|
||||||
|
}
|
||||||
|
|
||||||
|
s.prepend(QLatin1Char(' '));
|
||||||
|
s.append(QLatin1Char(' '));
|
||||||
|
shortcutDisplay = s;
|
||||||
|
q->shortcutDisplayChanged(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KeySequenceHelper::shortcutDisplay() const
|
||||||
|
{
|
||||||
|
return d->shortcutDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeySequenceHelper::keyPressed(int key, int modifiers)
|
||||||
|
{
|
||||||
|
if (key == -1) {
|
||||||
|
// Qt sometimes returns garbage keycodes, I observed -1, if it doesn't know a key.
|
||||||
|
// We cannot do anything useful with those (several keys have -1, indistinguishable)
|
||||||
|
// and QKeySequence.toString() will also yield a garbage string.
|
||||||
|
KMessageBox::sorry(0,
|
||||||
|
i18n("The key you just pressed is not supported by Qt."),
|
||||||
|
i18n("Unsupported Key"));
|
||||||
|
return d->cancelRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
//don't have the return or space key appear as first key of the sequence when they
|
||||||
|
//were pressed to start editing - catch and them and imitate their effect
|
||||||
|
if (!d->isRecording && ((key == Qt::Key_Return || key == Qt::Key_Space))) {
|
||||||
|
d->startRecording();
|
||||||
|
d->modifierKeys = modifiers;
|
||||||
|
d->updateShortcutDisplay();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->modifierKeys = modifiers;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case Qt::Key_AltGr: //or else we get unicode salad
|
||||||
|
return;
|
||||||
|
case Qt::Key_Shift:
|
||||||
|
case Qt::Key_Control:
|
||||||
|
case Qt::Key_Alt:
|
||||||
|
case Qt::Key_Meta:
|
||||||
|
case Qt::Key_Menu: //unused (yes, but why?)
|
||||||
|
d->controlModifierlessTimout();
|
||||||
|
d->updateShortcutDisplay();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
if (d->nKey == 0 && !(d->modifierKeys & ~Qt::SHIFT)) {
|
||||||
|
// It's the first key and no modifier pressed. Check if this is
|
||||||
|
// allowed
|
||||||
|
if (!(KeySequenceHelperPrivate::isOkWhenModifierless(key)
|
||||||
|
|| d->allowModifierless)) {
|
||||||
|
// No it's not
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now have a valid key press.
|
||||||
|
if (key) {
|
||||||
|
if ((key == Qt::Key_Backtab) && (d->modifierKeys & Qt::SHIFT)) {
|
||||||
|
key = Qt::Key_Tab | d->modifierKeys;
|
||||||
|
} else {
|
||||||
|
key |= (d->modifierKeys & ~Qt::SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->nKey == 0) {
|
||||||
|
d->keySequence = QKeySequence(key);
|
||||||
|
} else {
|
||||||
|
d->keySequence =
|
||||||
|
KeySequenceHelperPrivate::appendToSequence(d->keySequence, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->nKey++;
|
||||||
|
if ((!d->multiKeyShortcutsAllowed) || (d->nKey >= 4)) {
|
||||||
|
doneRecording();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->controlModifierlessTimout();
|
||||||
|
d->updateShortcutDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
void KeySequenceHelper::keyReleased(int key, int modifiers)
|
||||||
|
{
|
||||||
|
if (key == -1) {
|
||||||
|
// ignore garbage, see keyPressEvent()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if a modifier that belongs to the shortcut was released...
|
||||||
|
if ((modifiers & d->modifierKeys) < d->modifierKeys) {
|
||||||
|
d->modifierKeys = modifiers;
|
||||||
|
d->controlModifierlessTimout();
|
||||||
|
d->updateShortcutDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//static
|
||||||
|
QKeySequence KeySequenceHelperPrivate::appendToSequence(const QKeySequence &seq, int keyQt)
|
||||||
|
{
|
||||||
|
switch (seq.count()) {
|
||||||
|
case 0:
|
||||||
|
return QKeySequence(keyQt);
|
||||||
|
case 1:
|
||||||
|
return QKeySequence(seq[0], keyQt);
|
||||||
|
case 2:
|
||||||
|
return QKeySequence(seq[0], seq[1], keyQt);
|
||||||
|
case 3:
|
||||||
|
return QKeySequence(seq[0], seq[1], seq[2], keyQt);
|
||||||
|
default:
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//static
|
||||||
|
bool KeySequenceHelperPrivate::isOkWhenModifierless(int keyQt)
|
||||||
|
{
|
||||||
|
//this whole function is a hack, but especially the first line of code
|
||||||
|
if (QKeySequence(keyQt).toString().length() == 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (keyQt) {
|
||||||
|
case Qt::Key_Return:
|
||||||
|
case Qt::Key_Space:
|
||||||
|
case Qt::Key_Tab:
|
||||||
|
case Qt::Key_Backtab: //does this ever happen?
|
||||||
|
case Qt::Key_Backspace:
|
||||||
|
case Qt::Key_Delete:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* <one line to give the library's name and an idea of what it does.>
|
||||||
|
* Copyright (C) 2014 David Edmundson <davidedmundson@kde.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEYSEQUENCEHELPER_H
|
||||||
|
#define KEYSEQUENCEHELPER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QKeySequence>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is a clone of Key from XMLGUI
|
||||||
|
* It performs only the logic of building shortcuts
|
||||||
|
* It is a private class to be used by KeySequenceItem
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class KeySequenceHelperPrivate;
|
||||||
|
|
||||||
|
class KeySequenceHelper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_FLAGS(ShortcutTypes)
|
||||||
|
|
||||||
|
Q_PROPERTY(
|
||||||
|
QKeySequence keySequence
|
||||||
|
READ keySequence
|
||||||
|
WRITE setKeySequence
|
||||||
|
NOTIFY keySequenceChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(
|
||||||
|
bool multiKeyShortcutsAllowed
|
||||||
|
READ multiKeyShortcutsAllowed
|
||||||
|
WRITE setMultiKeyShortcutsAllowed)
|
||||||
|
|
||||||
|
Q_PROPERTY(
|
||||||
|
QString shortcutDisplay
|
||||||
|
READ shortcutDisplay
|
||||||
|
NOTIFY shortcutDisplayChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(
|
||||||
|
bool modifierlessAllowed
|
||||||
|
READ isModifierlessAllowed
|
||||||
|
WRITE setModifierlessAllowed)
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum ShortcutType {
|
||||||
|
None = 0x00, //!< No checking for conflicts
|
||||||
|
LocalShortcuts = 0x01, //!< Check with local shortcuts. @see setCheckActionCollections()
|
||||||
|
StandardShortcuts = 0x02, //!< Check against standard shortcuts. @see KStandardShortcut
|
||||||
|
GlobalShortcuts = 0x04 //!< Check against global shortcuts. @see KGlobalAccel
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(ShortcutTypes, ShortcutType)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
explicit KeySequenceHelper(QObject* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructs the widget.
|
||||||
|
*/
|
||||||
|
virtual ~KeySequenceHelper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow multikey shortcuts?
|
||||||
|
*/
|
||||||
|
void setMultiKeyShortcutsAllowed(bool);
|
||||||
|
bool multiKeyShortcutsAllowed() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This only applies to user input, not to setShortcut().
|
||||||
|
* Set whether to accept "plain" keys without modifiers (like Ctrl, Alt, Meta).
|
||||||
|
* Plain keys by our definition include letter and symbol keys and
|
||||||
|
* text editing keys (Return, Space, Tab, Backspace, Delete).
|
||||||
|
* "Special" keys like F1, Cursor keys, Insert, PageDown will always work.
|
||||||
|
*/
|
||||||
|
void setModifierlessAllowed(bool allow);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see setModifierlessAllowed()
|
||||||
|
*/
|
||||||
|
bool isModifierlessAllowed();
|
||||||
|
|
||||||
|
|
||||||
|
bool isRecording() const;
|
||||||
|
void setShortcut(bool recording);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default key sequence from a string
|
||||||
|
*/
|
||||||
|
void setKeySequence(const QKeySequence &sequence);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the currently selected key sequence as a string
|
||||||
|
*/
|
||||||
|
QKeySequence keySequence() const;
|
||||||
|
QString shortcutDisplay() const;
|
||||||
|
|
||||||
|
bool isKeySequenceAvailable(const QKeySequence &keySequence) const;
|
||||||
|
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void keySequenceChanged(const QKeySequence &seq);
|
||||||
|
void shortcutDisplayChanged(const QString &string);
|
||||||
|
void captureFinished();
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void captureKeySequence();
|
||||||
|
void keyPressed(int key, int modifiers);
|
||||||
|
void keyReleased(int key, int modifiers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the key sequence.
|
||||||
|
*/
|
||||||
|
void clearKeySequence();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void doneRecording();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class KeySequenceHelperPrivate;
|
||||||
|
KeySequenceHelperPrivate *const d;
|
||||||
|
|
||||||
|
Q_DISABLE_COPY(KeySequenceHelper)
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(KeySequenceHelper::ShortcutTypes)
|
||||||
|
|
||||||
|
|
||||||
|
#endif // KEYSEQUENCEHELPER_H
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 David Edmundson <davidedmundson@kde.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Library General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2, 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 Library 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 "kquickcontrolsprivateplugin.h"
|
||||||
|
|
||||||
|
#include <QtQml>
|
||||||
|
|
||||||
|
#include "keysequencehelper.h"
|
||||||
|
|
||||||
|
void KQuickControlsPrivatePlugin::registerTypes(const char *uri)
|
||||||
|
{
|
||||||
|
Q_ASSERT(uri == QLatin1String("org.kde.private.kquickcontrols"));
|
||||||
|
qmlRegisterType<KeySequenceHelper>(uri, 2, 0, "KeySequenceHelper");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 David Edmundson <davidedmundson@kde.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Library General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2, 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 Library 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 KQUICKCONTROLSPRIVATEPLUGIN_H
|
||||||
|
#define KQUICKCONTROLSPRIVATEPLUGIN_H
|
||||||
|
|
||||||
|
#include <QQmlExtensionPlugin>
|
||||||
|
|
||||||
|
class KQuickControlsPrivatePlugin : public QQmlExtensionPlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
|
||||||
|
|
||||||
|
public:
|
||||||
|
void registerTypes(const char *uri);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
4
src/declarativeimports/kquickcontrols/private/qmldir
Normal file
4
src/declarativeimports/kquickcontrols/private/qmldir
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
module org.kde.private.kquickcontrols
|
||||||
|
plugin kquickcontrolsprivateplugin
|
||||||
|
|
||||||
|
ShortcutButton 2.0 ShortcutButton.qml
|
1
src/declarativeimports/kquickcontrols/qmldir
Normal file
1
src/declarativeimports/kquickcontrols/qmldir
Normal file
@ -0,0 +1 @@
|
|||||||
|
KeySequenceItem 2.0 KeySequenceItem.qml
|
@ -2,3 +2,4 @@ module org.kde.qtextracomponents
|
|||||||
plugin qtextracomponentsplugin
|
plugin qtextracomponentsplugin
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutButton 2.0 ShortcutButton.qml
|
||||||
|
Loading…
Reference in New Issue
Block a user