Core: Merge actionmanager/commandsfile pair into their only user

Also, de-QObject-ify and inline the Context wrapper structure
for the key strings.

Change-Id: I21f3afec61ef9ecfcc4c3d89afb9fb3a1548afae
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2024-07-25 10:55:44 +02:00
parent 8974d844ff
commit f0c2239fa3
7 changed files with 161 additions and 235 deletions

View File

@@ -13,8 +13,6 @@ add_qtc_plugin(Core
actionmanager/command_p.h actionmanager/command_p.h
actionmanager/commandmappings.cpp actionmanager/commandmappings.cpp
actionmanager/commandmappings.h actionmanager/commandmappings.h
actionmanager/commandsfile.cpp
actionmanager/commandsfile.h
actionsfilter.cpp actionsfilter.cpp
actionsfilter.h actionsfilter.h
basefilewizard.cpp basefilewizard.cpp

View File

@@ -18,8 +18,6 @@
#include <QPushButton> #include <QPushButton>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
using namespace Utils; using namespace Utils;
namespace Core { namespace Core {

View File

@@ -1,170 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "commandsfile.h"
#include "command.h"
#include "../dialogs/shortcutsettings.h"
#include "../icore.h"
#include <utils/qtcassert.h>
#include <utils/fileutils.h>
#include <QKeySequence>
#include <QFile>
#include <QXmlStreamAttributes>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDebug>
#include <QDateTime>
using namespace Utils;
namespace Core {
namespace Internal {
struct Context // XML parsing context with strings.
{
const QString mappingElement = "mapping";
const QString shortCutElement = "shortcut";
const QString idAttribute = "id";
const QString keyElement = "key";
const QString valueAttribute = "value";
};
/*!
\class Core::Internal::CommandsFile
\internal
\inmodule QtCreator
\brief The CommandsFile class provides a collection of import and export commands.
\inheaderfile commandsfile.h
*/
/*!
\internal
*/
CommandsFile::CommandsFile(const FilePath &filename)
: m_filePath(filename)
{
}
// XML attributes cannot contain these characters, and
// QXmlStreamWriter just bails out with an error.
// QKeySequence::toString() should probably not result in these
// characters, but it currently does, see QTCREATORBUG-29431
static bool containsInvalidCharacters(const QString &s)
{
const auto end = s.constEnd();
for (auto it = s.constBegin(); it != end; ++it) {
// from QXmlStreamWriterPrivate::writeEscaped
if (*it == u'\v' || *it == u'\f' || *it <= u'\x1F' || *it >= u'\uFFFE') {
return true;
}
}
return false;
}
static QString toAttribute(const QString &s)
{
if (containsInvalidCharacters(s))
return "0x" + QString::fromUtf8(s.toUtf8().toHex());
return s;
}
static QString fromAttribute(const QStringView &s)
{
if (s.startsWith(QLatin1String("0x")))
return QString::fromUtf8(QByteArray::fromHex(s.sliced(2).toUtf8()));
return s.toString();
}
/*!
\internal
*/
QMap<QString, QList<QKeySequence>> CommandsFile::importCommands() const
{
QMap<QString, QList<QKeySequence>> result;
QFile file(m_filePath.toString());
if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
return result;
Context ctx;
QXmlStreamReader r(&file);
QString currentId;
while (!r.atEnd()) {
switch (r.readNext()) {
case QXmlStreamReader::StartElement: {
const auto name = r.name();
if (name == ctx.shortCutElement) {
currentId = r.attributes().value(ctx.idAttribute).toString();
if (!result.contains(currentId))
result.insert(currentId, {});
} else if (name == ctx.keyElement) {
QTC_ASSERT(!currentId.isEmpty(), continue);
const QXmlStreamAttributes attributes = r.attributes();
if (attributes.hasAttribute(ctx.valueAttribute)) {
QString keyString = fromAttribute(attributes.value(ctx.valueAttribute));
if (HostOsInfo::isMacHost())
keyString = keyString.replace("AlwaysCtrl", "Meta");
else
keyString = keyString.replace("AlwaysCtrl", "Ctrl");
QList<QKeySequence> keys = result.value(currentId);
result.insert(currentId, keys << QKeySequence(keyString));
}
} // if key element
} // case QXmlStreamReader::StartElement
default:
break;
} // switch
} // while !atEnd
file.close();
return result;
}
/*!
\internal
*/
bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
{
FileSaver saver(m_filePath, QIODevice::Text);
if (!saver.hasError()) {
const Context ctx;
QXmlStreamWriter w(saver.file());
w.setAutoFormatting(true);
w.setAutoFormattingIndent(1); // Historical, used to be QDom.
w.writeStartDocument();
w.writeDTD(QLatin1String("<!DOCTYPE KeyboardMappingScheme>"));
w.writeComment(QString::fromLatin1(" Written by %1, %2. ").
arg(ICore::versionString(),
QDateTime::currentDateTime().toString(Qt::ISODate)));
w.writeStartElement(ctx.mappingElement);
for (const ShortcutItem *item : std::as_const(items)) {
const Id id = item->m_cmd->id();
if (item->m_keys.isEmpty() || item->m_keys.first().isEmpty()) {
w.writeEmptyElement(ctx.shortCutElement);
w.writeAttribute(ctx.idAttribute, id.toString());
} else {
w.writeStartElement(ctx.shortCutElement);
w.writeAttribute(ctx.idAttribute, id.toString());
for (const QKeySequence &k : item->m_keys) {
w.writeEmptyElement(ctx.keyElement);
w.writeAttribute(ctx.valueAttribute, toAttribute(k.toString()));
}
w.writeEndElement(); // Shortcut
}
}
w.writeEndElement();
w.writeEndDocument();
if (!saver.setResult(&w))
qWarning() << saver.errorString();
}
return saver.finalize();
}
} // namespace Internal
} // namespace Core

View File

@@ -1,34 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <utils/filepath.h>
#include <QObject>
#include <QString>
#include <QMap>
QT_FORWARD_DECLARE_CLASS(QKeySequence)
namespace Core {
namespace Internal {
struct ShortcutItem;
class CommandsFile : public QObject
{
Q_OBJECT
public:
CommandsFile(const Utils::FilePath &filePath);
QMap<QString, QList<QKeySequence> > importCommands() const;
bool exportCommands(const QList<ShortcutItem *> &items);
private:
Utils::FilePath m_filePath;
};
} // namespace Internal
} // namespace Core

View File

@@ -187,7 +187,6 @@ QtcPlugin {
"actionmanager.cpp", "actionmanager.h", "actionmanager_p.h", "actionmanager.cpp", "actionmanager.h", "actionmanager_p.h",
"command.cpp", "command.h", "command_p.h", "command.cpp", "command.h", "command_p.h",
"commandmappings.cpp", "commandmappings.h", "commandmappings.cpp", "commandmappings.h",
"commandsfile.cpp", "commandsfile.h",
] ]
} }

View File

@@ -3,15 +3,14 @@
#include "shortcutsettings.h" #include "shortcutsettings.h"
#include "ioptionspage.h"
#include "../actionmanager/actionmanager.h"
#include "../actionmanager/command.h"
#include "../actionmanager/commandmappings.h"
#include "../coreconstants.h" #include "../coreconstants.h"
#include "../coreplugintr.h" #include "../coreplugintr.h"
#include "../documentmanager.h" #include "../documentmanager.h"
#include "../icore.h" #include "../icore.h"
#include "../actionmanager/actionmanager.h"
#include "../actionmanager/command.h"
#include "../actionmanager/commandsfile.h"
#include "../actionmanager/commandmappings.h"
#include "ioptionspage.h"
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/fancylineedit.h> #include <utils/fancylineedit.h>
@@ -22,8 +21,9 @@
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
#include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QFileDialog> #include <QFile>
#include <QGridLayout> #include <QGridLayout>
#include <QGroupBox> #include <QGroupBox>
#include <QKeyEvent> #include <QKeyEvent>
@@ -34,19 +34,168 @@
#include <QPushButton> #include <QPushButton>
#include <QTimer> #include <QTimer>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
#include <QXmlStreamAttributes>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <array> #include <array>
using namespace Utils; using namespace Utils;
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
namespace Core::Internal { namespace Core::Internal {
const char kSeparator[] = " | "; const char kSeparator[] = " | ";
static int translateModifiers(Qt::KeyboardModifiers state, struct ShortcutItem final
const QString &text) {
Command *m_cmd;
QList<QKeySequence> m_keys;
QTreeWidgetItem *m_item;
};
/*!
\class Core::Internal::CommandsFile
\internal
\inmodule QtCreator
\brief The CommandsFile class provides a collection of import and export commands.
*/
class CommandsFile final
{
public:
CommandsFile(const FilePath &filePath) : m_filePath(filePath) {}
QMap<QString, QList<QKeySequence> > importCommands() const;
bool exportCommands(const QList<ShortcutItem *> &items);
private:
const QString mappingElement = "mapping";
const QString shortCutElement = "shortcut";
const QString idAttribute = "id";
const QString keyElement = "key";
const QString valueAttribute = "value";
FilePath m_filePath;
};
// XML attributes cannot contain these characters, and
// QXmlStreamWriter just bails out with an error.
// QKeySequence::toString() should probably not result in these
// characters, but it currently does, see QTCREATORBUG-29431
static bool containsInvalidCharacters(const QString &s)
{
const auto end = s.constEnd();
for (auto it = s.constBegin(); it != end; ++it) {
// from QXmlStreamWriterPrivate::writeEscaped
if (*it == u'\v' || *it == u'\f' || *it <= u'\x1F' || *it >= u'\uFFFE') {
return true;
}
}
return false;
}
static QString toAttribute(const QString &s)
{
if (containsInvalidCharacters(s))
return "0x" + QString::fromUtf8(s.toUtf8().toHex());
return s;
}
static QString fromAttribute(const QStringView &s)
{
if (s.startsWith(QLatin1String("0x")))
return QString::fromUtf8(QByteArray::fromHex(s.sliced(2).toUtf8()));
return s.toString();
}
/*!
\internal
*/
QMap<QString, QList<QKeySequence>> CommandsFile::importCommands() const
{
QMap<QString, QList<QKeySequence>> result;
QFile file(m_filePath.toString());
if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
return result;
QXmlStreamReader r(&file);
QString currentId;
while (!r.atEnd()) {
switch (r.readNext()) {
case QXmlStreamReader::StartElement: {
const auto name = r.name();
if (name == shortCutElement) {
currentId = r.attributes().value(idAttribute).toString();
if (!result.contains(currentId))
result.insert(currentId, {});
} else if (name == keyElement) {
QTC_ASSERT(!currentId.isEmpty(), continue);
const QXmlStreamAttributes attributes = r.attributes();
if (attributes.hasAttribute(valueAttribute)) {
QString keyString = fromAttribute(attributes.value(valueAttribute));
if (HostOsInfo::isMacHost())
keyString = keyString.replace("AlwaysCtrl", "Meta");
else
keyString = keyString.replace("AlwaysCtrl", "Ctrl");
QList<QKeySequence> keys = result.value(currentId);
result.insert(currentId, keys << QKeySequence(keyString));
}
} // if key element
} // case QXmlStreamReader::StartElement
default:
break;
} // switch
} // while !atEnd
file.close();
return result;
}
/*!
\internal
*/
bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
{
FileSaver saver(m_filePath, QIODevice::Text);
if (!saver.hasError()) {
QXmlStreamWriter w(saver.file());
w.setAutoFormatting(true);
w.setAutoFormattingIndent(1); // Historical, used to be QDom.
w.writeStartDocument();
w.writeDTD(QLatin1String("<!DOCTYPE KeyboardMappingScheme>"));
w.writeComment(QString::fromLatin1(" Written by %1, %2. ").
arg(ICore::versionString(),
QDateTime::currentDateTime().toString(Qt::ISODate)));
w.writeStartElement(mappingElement);
for (const ShortcutItem *item : std::as_const(items)) {
const Id id = item->m_cmd->id();
if (item->m_keys.isEmpty() || item->m_keys.first().isEmpty()) {
w.writeEmptyElement(shortCutElement);
w.writeAttribute(idAttribute, id.toString());
} else {
w.writeStartElement(shortCutElement);
w.writeAttribute(idAttribute, id.toString());
for (const QKeySequence &k : item->m_keys) {
w.writeEmptyElement(keyElement);
w.writeAttribute(valueAttribute, toAttribute(k.toString()));
}
w.writeEndElement(); // Shortcut
}
}
w.writeEndElement();
w.writeEndDocument();
if (!saver.setResult(&w))
qWarning() << saver.errorString();
}
return saver.finalize();
}
static int translateModifiers(Qt::KeyboardModifiers state, const QString &text)
{ {
int result = 0; int result = 0;
// The shift modifier only counts when it is not used to type a symbol // The shift modifier only counts when it is not used to type a symbol

View File

@@ -3,22 +3,8 @@
#pragma once #pragma once
#include "../actionmanager/commandmappings.h" namespace Core::Internal {
namespace Core {
class Command;
namespace Internal {
struct ShortcutItem
{
Command *m_cmd;
QList<QKeySequence> m_keys;
QTreeWidgetItem *m_item;
};
void setupShortcutSettings(); void setupShortcutSettings();
} // namespace Internal } // Core::Core
} // namespace Core