Utils: Add StringSelectionAspect

Change-Id: I73b5c964be1222f56fcc01f30d17506f92d1f6b2
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-09-15 11:56:03 +02:00
parent b81026488c
commit 67bd5fc359
6 changed files with 169 additions and 133 deletions

View File

@@ -23,6 +23,7 @@
#include <QButtonGroup> #include <QButtonGroup>
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox> #include <QComboBox>
#include <QCompleter>
#include <QDebug> #include <QDebug>
#include <QGroupBox> #include <QGroupBox>
#include <QLabel> #include <QLabel>
@@ -36,6 +37,7 @@
#include <QScrollArea> #include <QScrollArea>
#include <QSettings> #include <QSettings>
#include <QSpinBox> #include <QSpinBox>
#include <QStandardItemModel>
#include <QTextEdit> #include <QTextEdit>
#include <QUndoStack> #include <QUndoStack>
@@ -3242,4 +3244,126 @@ void AspectList::addToLayout(Layouting::LayoutItem &parent)
parent.addItem(scrollArea); parent.addItem(scrollArea);
} }
StringSelectionAspect::StringSelectionAspect(AspectContainer *container)
: TypedAspect<QString>(container)
{}
QStandardItem *StringSelectionAspect::itemById(const QString &id)
{
for (int i = 0; i < m_model->rowCount(); ++i) {
auto cur = m_model->item(i);
if (cur->data() == id)
return cur;
}
return nullptr;
}
void StringSelectionAspect::bufferToGui()
{
if (!m_model)
return;
auto selected = itemById(m_buffer);
if (selected) {
m_undoable.setSilently(selected->data().toString());
m_selectionModel->setCurrentIndex(selected->index(),
QItemSelectionModel::SelectionFlag::ClearAndSelect);
return;
}
if (m_model->rowCount() > 0) {
m_undoable.setSilently(m_model->item(0)->data().toString());
m_selectionModel->setCurrentIndex(m_model->item(0)->index(),
QItemSelectionModel::SelectionFlag::ClearAndSelect);
} else {
m_selectionModel->setCurrentIndex(QModelIndex(), QItemSelectionModel::SelectionFlag::Clear);
}
handleGuiChanged();
}
bool StringSelectionAspect::guiToBuffer()
{
if (!m_model)
return false;
auto oldBuffer = m_buffer;
m_buffer = m_undoable.get();
return oldBuffer != m_buffer;
}
void StringSelectionAspect::addToLayout(Layouting::LayoutItem &parent)
{
QTC_ASSERT(m_fillCallback, return);
auto cb = [this](const QList<QStandardItem *> &items) {
m_model->clear();
for (QStandardItem *item : items)
m_model->appendRow(item);
bufferToGui();
};
if (!m_model) {
m_model = new QStandardItemModel(this);
m_selectionModel = new QItemSelectionModel(m_model);
connect(this, &StringSelectionAspect::refillRequested, this, [this, cb] {
m_fillCallback(cb);
});
m_fillCallback(cb);
}
QComboBox *comboBox = new QComboBox();
comboBox->setInsertPolicy(QComboBox::InsertPolicy::NoInsert);
comboBox->setEditable(true);
comboBox->completer()->setCompletionMode(QCompleter::PopupCompletion);
comboBox->completer()->setFilterMode(Qt::MatchContains);
comboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
comboBox->setCurrentText(value());
comboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
comboBox->setModel(m_model);
connect(m_selectionModel,
&QItemSelectionModel::currentChanged,
comboBox,
[comboBox](QModelIndex currentIdx) {
if (currentIdx.isValid() && comboBox->currentIndex() != currentIdx.row())
comboBox->setCurrentIndex(currentIdx.row());
});
connect(comboBox, &QComboBox::activated, this, [this](int idx) {
QModelIndex modelIdx = m_model->index(idx, 0);
if (!modelIdx.isValid())
return;
QString newValue = m_model->index(idx, 0).data(Qt::UserRole + 1).toString();
if (newValue.isEmpty())
return;
pushUndo(m_undoable.set(newValue));
bufferToGui();
});
connect(&m_undoable.m_signal, &UndoSignaller::changed, comboBox, [this, comboBox]() {
auto item = itemById(m_undoable.get());
if (item)
m_selectionModel->setCurrentIndex(item->index(), QItemSelectionModel::ClearAndSelect);
else
comboBox->setCurrentText(m_undoable.get());
handleGuiChanged();
});
if (m_selectionModel->currentIndex().isValid())
comboBox->setCurrentIndex(m_selectionModel->currentIndex().row());
return addLabeledItem(parent, comboBox);
}
} // namespace Utils } // namespace Utils

View File

@@ -21,9 +21,14 @@ QT_BEGIN_NAMESPACE
class QAction; class QAction;
class QSettings; class QSettings;
class QUndoStack; class QUndoStack;
class QStandardItem;
class QStandardItemModel;
class QItemSelectionModel;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Layouting { class LayoutItem; } namespace Layouting {
class LayoutItem;
}
namespace Utils { namespace Utils {
@@ -1068,4 +1073,34 @@ private:
std::unique_ptr<Internal::AspectListPrivate> d; std::unique_ptr<Internal::AspectListPrivate> d;
}; };
class QTCREATOR_UTILS_EXPORT StringSelectionAspect : public Utils::TypedAspect<QString>
{
Q_OBJECT
public:
StringSelectionAspect(Utils::AspectContainer *container = nullptr);
void addToLayout(Layouting::LayoutItem &parent) override;
using ResultCallback = std::function<void(QList<QStandardItem *> items)>;
using FillCallback = std::function<void(ResultCallback)>;
void setFillCallback(FillCallback callback) { m_fillCallback = callback; }
void refill() { emit refillRequested(); }
void bufferToGui() override;
bool guiToBuffer() override;
signals:
void refillRequested();
private:
QStandardItem *itemById(const QString &id);
FillCallback m_fillCallback;
QStandardItemModel *m_model{nullptr};
QItemSelectionModel *m_selectionModel{nullptr};
Utils::UndoableValue<QString> m_undoable;
};
} // namespace Utils } // namespace Utils

View File

@@ -18,103 +18,6 @@ using namespace Utils;
namespace CompilerExplorer { namespace CompilerExplorer {
StringSelectionAspect::StringSelectionAspect(AspectContainer *container)
: TypedAspect<QString>(container)
{}
void StringSelectionAspect::bufferToGui()
{
if (!m_model)
return;
for (int i = 0; i < m_model->rowCount(); ++i) {
auto cur = m_model->item(i);
if (cur->data() == m_buffer) {
m_selectionModel->setCurrentIndex(cur->index(),
QItemSelectionModel::SelectionFlag::ClearAndSelect);
return;
}
}
if (m_model->rowCount() > 0)
m_selectionModel->setCurrentIndex(m_model->item(0)->index(),
QItemSelectionModel::SelectionFlag::ClearAndSelect);
else
m_selectionModel->setCurrentIndex(QModelIndex(), QItemSelectionModel::SelectionFlag::Clear);
handleGuiChanged();
}
bool StringSelectionAspect::guiToBuffer()
{
if (!m_model)
return false;
auto oldBuffer = m_buffer;
QModelIndex index = m_selectionModel->currentIndex();
if (index.isValid())
m_buffer = index.data(Qt::UserRole + 1).toString();
else
m_buffer.clear();
return oldBuffer != m_buffer;
}
void StringSelectionAspect::addToLayout(Layouting::LayoutItem &parent)
{
QTC_ASSERT(m_fillCallback, return);
auto cb = [this](const QList<QStandardItem *> &items) {
m_model->clear();
for (QStandardItem *item : items)
m_model->appendRow(item);
bufferToGui();
};
if (!m_model) {
m_model = new QStandardItemModel(this);
m_selectionModel = new QItemSelectionModel(m_model);
connect(this, &StringSelectionAspect::refillRequested, this, [this, cb] {
m_fillCallback(cb);
});
m_fillCallback(cb);
}
QComboBox *comboBox = new QComboBox();
comboBox->setInsertPolicy(QComboBox::InsertPolicy::NoInsert);
comboBox->setEditable(true);
comboBox->completer()->setCompletionMode(QCompleter::PopupCompletion);
comboBox->completer()->setFilterMode(Qt::MatchContains);
comboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
comboBox->setCurrentText(value());
comboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
comboBox->setModel(m_model);
connect(m_selectionModel,
&QItemSelectionModel::currentChanged,
comboBox,
[comboBox](QModelIndex currentIdx) {
if (currentIdx.isValid() && comboBox->currentIndex() != currentIdx.row())
comboBox->setCurrentIndex(currentIdx.row());
});
connect(comboBox, &QComboBox::activated, this, [this, comboBox] {
m_selectionModel->setCurrentIndex(m_model->index(comboBox->currentIndex(), 0),
QItemSelectionModel::SelectionFlag::ClearAndSelect);
handleGuiChanged();
});
if (m_selectionModel->currentIndex().isValid())
comboBox->setCurrentIndex(m_selectionModel->currentIndex().row());
return addLabeledItem(parent, comboBox);
}
LibrarySelectionAspect::LibrarySelectionAspect(AspectContainer *container) LibrarySelectionAspect::LibrarySelectionAspect(AspectContainer *container)
: TypedAspect<QMap<QString, QString>>(container) : TypedAspect<QMap<QString, QString>>(container)
{} {}

View File

@@ -14,32 +14,6 @@
namespace CompilerExplorer { namespace CompilerExplorer {
class StringSelectionAspect : public Utils::TypedAspect<QString>
{
Q_OBJECT
public:
StringSelectionAspect(Utils::AspectContainer *container = nullptr);
void addToLayout(Layouting::LayoutItem &parent) override;
using ResultCallback = std::function<void(QList<QStandardItem *> items)>;
using FillCallback = std::function<void(ResultCallback)>;
void setFillCallback(FillCallback callback) { m_fillCallback = callback; }
void refill() { emit refillRequested(); }
void bufferToGui() override;
bool guiToBuffer() override;
signals:
void refillRequested();
private:
FillCallback m_fillCallback;
QStandardItemModel *m_model{nullptr};
QItemSelectionModel *m_selectionModel{nullptr};
};
// QMap<Library.Id, Library.Version.Id> // QMap<Library.Id, Library.Version.Id>
class LibrarySelectionAspect : public Utils::TypedAspect<QMap<QString, QString>> class LibrarySelectionAspect : public Utils::TypedAspect<QMap<QString, QString>>
{ {

View File

@@ -77,7 +77,7 @@ SourceSettings::SourceSettings(const ApiConfigFunction &apiConfigFunction)
auto result = std::make_shared<CompilerSettings>(apiConfigFunction); auto result = std::make_shared<CompilerSettings>(apiConfigFunction);
connect(this, &SourceSettings::languagesChanged, result.get(), &CompilerSettings::refresh); connect(this, &SourceSettings::languagesChanged, result.get(), &CompilerSettings::refresh);
connect(&languageId, connect(&languageId,
&StringSelectionAspect::changed, &Utils::StringSelectionAspect::changed,
result.get(), result.get(),
[this, result = result.get()] { result->setLanguageId(languageId()); }); [this, result = result.get()] { result->setLanguageId(languageId()); });
@@ -176,7 +176,7 @@ void CompilerSettings::setLanguageId(const QString &languageId)
compilerOptions.setValue(""); compilerOptions.setValue("");
} }
void CompilerSettings::fillLibraries(LibrarySelectionAspect::ResultCallback cb) void CompilerSettings::fillLibraries(const LibrarySelectionAspect::ResultCallback &cb)
{ {
const QString lang = m_languageId; const QString lang = m_languageId;
auto fillFromCache = [cb, lang] { auto fillFromCache = [cb, lang] {
@@ -212,7 +212,7 @@ void CompilerSettings::fillLibraries(LibrarySelectionAspect::ResultCallback cb)
}); });
} }
void SourceSettings::fillLanguageIdModel(StringSelectionAspect::ResultCallback cb) void SourceSettings::fillLanguageIdModel(const Utils::StringSelectionAspect::ResultCallback &cb)
{ {
auto fillFromCache = [cb, this] { auto fillFromCache = [cb, this] {
QList<QStandardItem *> items; QList<QStandardItem *> items;
@@ -254,7 +254,7 @@ void SourceSettings::fillLanguageIdModel(StringSelectionAspect::ResultCallback c
}); });
} }
void CompilerSettings::fillCompilerModel(StringSelectionAspect::ResultCallback cb) void CompilerSettings::fillCompilerModel(const Utils::StringSelectionAspect::ResultCallback &cb)
{ {
auto fillFromCache = [cb](auto it) { auto fillFromCache = [cb](auto it) {
QList<QStandardItem *> items; QList<QStandardItem *> items;

View File

@@ -59,7 +59,7 @@ public:
ApiConfigFunction apiConfigFunction() const { return m_apiConfigFunction; } ApiConfigFunction apiConfigFunction() const { return m_apiConfigFunction; }
public: public:
StringSelectionAspect languageId{this}; Utils::StringSelectionAspect languageId{this};
Utils::StringAspect source{this}; Utils::StringAspect source{this};
Utils::AspectList compilers{this}; Utils::AspectList compilers{this};
@@ -70,7 +70,7 @@ signals:
void languagesChanged(); void languagesChanged();
private: private:
void fillLanguageIdModel(StringSelectionAspect::ResultCallback cb); void fillLanguageIdModel(const Utils::StringSelectionAspect::ResultCallback &cb);
private: private:
CompilerExplorerSettings *m_parent; CompilerExplorerSettings *m_parent;
@@ -82,7 +82,7 @@ class CompilerSettings : public Utils::AspectContainer
public: public:
CompilerSettings(const ApiConfigFunction &apiConfigFunction); CompilerSettings(const ApiConfigFunction &apiConfigFunction);
StringSelectionAspect compiler{this}; Utils::StringSelectionAspect compiler{this};
Utils::StringAspect compilerOptions{this}; Utils::StringAspect compilerOptions{this};
LibrarySelectionAspect libraries{this}; LibrarySelectionAspect libraries{this};
@@ -97,8 +97,8 @@ public:
void setLanguageId(const QString &languageId); void setLanguageId(const QString &languageId);
private: private:
void fillCompilerModel(StringSelectionAspect::ResultCallback cb); void fillCompilerModel(const Utils::StringSelectionAspect::ResultCallback &cb);
void fillLibraries(LibrarySelectionAspect::ResultCallback cb); void fillLibraries(const LibrarySelectionAspect::ResultCallback &cb);
QString m_languageId; QString m_languageId;
ApiConfigFunction m_apiConfigFunction; ApiConfigFunction m_apiConfigFunction;