Verified Commit fc4d85cc authored by Daniel Vrátil's avatar Daniel Vrátil 🤖
Browse files

Use Designer UI files for Tag dialogs/widgets

parent 2b09a556
......@@ -51,7 +51,7 @@ public:
EndRole = 65535
};
explicit TagModel(Monitor *recorder, QObject *parent);
explicit TagModel(Monitor *recorder, QObject *parent = nullptr);
~TagModel() override;
Q_REQUIRED_RESULT int columnCount(const QModelIndex &parent = QModelIndex()) const override;
......@@ -74,7 +74,7 @@ protected:
Q_DECLARE_PRIVATE(TagModel)
TagModelPrivate *d_ptr;
TagModel(Monitor *recorder, TagModelPrivate *dd, QObject *parent = nullptr);
TagModel(Monitor *recorder, TagModelPrivate *dd, QObject *parent);
Q_SIGNALS:
void populated();
......
......@@ -53,6 +53,10 @@ set(akonadiwidgets_UI
erroroverlay.ui
manageaccountwidget.ui
selftestdialog.ui
tageditwidget.ui
tagmanagementdialog.ui
tagselectiondialog.ui
tagwidget.ui
)
ecm_generate_headers(AkonadiWidgets_HEADERS
......
......@@ -19,12 +19,7 @@
02110-1301, USA.
*/
#include "tageditwidget.h"
#include <KLocalizedString>
#include <QLineEdit>
#include <KMessageBox>
#include <KCheckableProxyModel>
#include <QListView>
#include "ui_tageditwidget.h"
#include "changerecorder.h"
#include "tagcreatejob.h"
#include "tagdeletejob.h"
......@@ -32,13 +27,12 @@
#include "tagattribute.h"
#include "tagmodel.h"
#include <KLocalizedString>
#include <KMessageBox>
#include <KCheckableProxyModel>
#include <QEvent>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>
#include <QWidget>
using namespace Akonadi;
......@@ -46,46 +40,54 @@ class Q_DECL_HIDDEN TagEditWidget::Private : public QObject
{
Q_OBJECT
public:
Private(Akonadi::TagModel *model, QWidget *parent);
Private(QWidget *parent);
public Q_SLOTS:
void slotTextEdited(const QString &text);
void slotItemEntered(const QModelIndex &index);
void showDeleteButton();
void deleteTag();
void slotCreateTag();
void slotCreateTagFinished(KJob *job);
void onRowsInserted(const QModelIndex &parent, int start, int end);
void onModelPopulated();
public:
void initCheckableProxy(Akonadi::TagModel *model)
{
Q_ASSERT(m_checkableProxy);
QItemSelectionModel *selectionModel = new QItemSelectionModel(model, m_checkableProxy.get());
m_checkableProxy->setSourceModel(model);
m_checkableProxy->setSelectionModel(selectionModel);
}
void select(const QModelIndex &parent, int start, int end, QItemSelectionModel::SelectionFlag selectionFlag);
enum ItemType {
UrlTag = Qt::UserRole + 1
};
QWidget *d;
QWidget * const d;
Ui::TagEditWidget ui;
Akonadi::Tag::List m_tags;
Akonadi::TagModel *m_model = nullptr;
QListView *m_tagsView = nullptr;
KCheckableProxyModel *m_checkableProxy = nullptr;
QScopedPointer<KCheckableProxyModel> m_checkableProxy;
QModelIndex m_deleteCandidate;
QPushButton *m_newTagButton = nullptr;
QLineEdit *m_newTagEdit = nullptr;
QPushButton *m_deleteButton = nullptr;
QTimer *m_deleteButtonTimer = nullptr;
};
TagEditWidget::Private::Private(Akonadi::TagModel *model, QWidget *parent)
TagEditWidget::Private::Private(QWidget *parent)
: QObject()
, d(parent)
, m_model(model)
{
}
{}
void TagEditWidget::Private::select(const QModelIndex &parent, int start, int end, QItemSelectionModel::SelectionFlag selectionFlag)
{
if (!m_model) {
return;
}
QItemSelection selection;
for (int i = start; i <= end; i++) {
const QModelIndex index = m_model->index(i, 0, parent);
......@@ -94,7 +96,14 @@ void TagEditWidget::Private::select(const QModelIndex &parent, int start, int en
selection.select(index, index);
}
}
m_checkableProxy->selectionModel()->select(selection, selectionFlag);
if (m_checkableProxy) {
m_checkableProxy->selectionModel()->select(selection, selectionFlag);
}
}
void TagEditWidget::Private::onModelPopulated()
{
select(QModelIndex(), 0, m_model->rowCount() - 1, QItemSelectionModel::ClearAndSelect);
}
void TagEditWidget::Private::onRowsInserted(const QModelIndex &parent, int start, int end)
......@@ -104,24 +113,24 @@ void TagEditWidget::Private::onRowsInserted(const QModelIndex &parent, int start
void TagEditWidget::Private::slotCreateTag()
{
if (m_newTagButton->isEnabled()) {
Akonadi::TagCreateJob *createJob = new Akonadi::TagCreateJob(Akonadi::Tag(m_newTagEdit->text()), this);
connect(createJob, &Akonadi::TagCreateJob::finished, this, &TagEditWidget::Private::slotCreateTagFinished);
if (ui.newTagButton->isEnabled()) {
auto createJob = new TagCreateJob(Akonadi::Tag(ui.newTagEdit->text()), this);
connect(createJob, &TagCreateJob::finished, this, &TagEditWidget::Private::slotCreateTagFinished);
m_newTagEdit->clear();
m_newTagEdit->setEnabled(false);
m_newTagButton->setEnabled(false);
ui.newTagEdit->clear();
ui.newTagEdit->setEnabled(false);
ui.newTagButton->setEnabled(false);
}
}
void TagEditWidget::Private::slotCreateTagFinished(KJob *job)
{
if (job->error()) {
QMessageBox::critical(d, i18n("Failed to create a new tag"),
KMessageBox::error(d, i18n("Failed to create a new tag"),
i18n("An error occurred while creating a new tag"));
}
m_newTagEdit->setEnabled(true);
ui.newTagEdit->setEnabled(true);
}
void TagEditWidget::Private::slotTextEdited(const QString &text)
......@@ -131,28 +140,27 @@ void TagEditWidget::Private::slotTextEdited(const QString &text)
// between a tag "Test" and "Test ".
const QString tagText = text.simplified();
if (tagText.isEmpty()) {
m_newTagButton->setEnabled(false);
ui.newTagButton->setEnabled(false);
return;
}
// Check whether the new tag already exists
const int count = m_model->rowCount();
bool exists = false;
for (int i = 0; i < count; ++i) {
for (int i = 0, count = m_model->rowCount(); i < count; ++i) {
const QModelIndex index = m_model->index(i, 0, QModelIndex());
if (index.data(Qt::DisplayRole).toString() == tagText) {
exists = true;
break;
}
}
m_newTagButton->setEnabled(!exists);
ui.newTagButton->setEnabled(!exists);
}
void TagEditWidget::Private::slotItemEntered(const QModelIndex &index)
{
// align the delete-button to stay on the right border
// of the item
const QRect rect = m_tagsView->visualRect(index);
const QRect rect = ui.tagsView->visualRect(index);
const int size = rect.height();
const int x = rect.right() - size;
const int y = rect.top();
......@@ -160,94 +168,103 @@ void TagEditWidget::Private::slotItemEntered(const QModelIndex &index)
m_deleteButton->resize(size, size);
m_deleteCandidate = index;
m_deleteButtonTimer->start();
}
void TagEditWidget::Private::showDeleteButton()
{
m_deleteButton->show();
}
void TagEditWidget::Private::deleteTag()
{
Q_ASSERT(m_deleteCandidate.isValid());
const Akonadi::Tag tag = m_deleteCandidate.data(Akonadi::TagModel::TagRole).value<Akonadi::Tag>();
const auto tag = m_deleteCandidate.data(Akonadi::TagModel::TagRole).value<Akonadi::Tag>();
const QString text = xi18nc("@info",
"Do you really want to remove the tag <resource>%1</resource>?",
tag.name());
const QString caption = i18nc("@title", "Delete tag");
if (KMessageBox::questionYesNo(d, text, caption, KStandardGuiItem::del(), KStandardGuiItem::cancel()) == KMessageBox::Yes) {
new Akonadi::TagDeleteJob(tag, this);
new TagDeleteJob(tag, this);
}
}
TagEditWidget::TagEditWidget(Akonadi::TagModel *model, QWidget *parent, bool enableSelection)
TagEditWidget::TagEditWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(model, this))
, d(new Private(this))
{
QVBoxLayout *topLayout = new QVBoxLayout(this);
topLayout->setContentsMargins(0, 0, 0, 0);
QItemSelectionModel *selectionModel = new QItemSelectionModel(d->m_model, this);
d->m_checkableProxy = new KCheckableProxyModel(this);
d->m_checkableProxy->setSourceModel(d->m_model);
d->m_checkableProxy->setSelectionModel(selectionModel);
connect(d->m_model, &QAbstractItemModel::rowsInserted, d.data(), &Private::onRowsInserted);
d->m_tagsView = new QListView(this);
d->m_tagsView->setMouseTracking(true);
d->m_tagsView->setSelectionMode(QAbstractItemView::NoSelection);
d->m_tagsView->installEventFilter(this);
if (enableSelection) {
d->m_tagsView->setModel(d->m_checkableProxy);
} else {
d->m_tagsView->setModel(d->m_model);
}
connect(d->m_tagsView, &QAbstractItemView::entered,
d.data(), &Private::slotItemEntered);
d->m_newTagEdit = new QLineEdit(this);
d->m_newTagEdit->setClearButtonEnabled(true);
connect(d->m_newTagEdit, &QLineEdit::textEdited,
d.data(), &Private::slotTextEdited);
connect(d->m_newTagEdit, &QLineEdit::returnPressed,
d.data(), &Private::slotCreateTag);
d->m_newTagButton = new QPushButton(i18nc("@label", "Create new tag"));
d->m_newTagButton->setEnabled(false);
connect(d->m_newTagButton, &QAbstractButton::clicked,
d.data(), &Private::slotCreateTag);
QHBoxLayout *newTagLayout = new QHBoxLayout();
newTagLayout->addWidget(d->m_newTagEdit, 1);
newTagLayout->addWidget(d->m_newTagButton);
if (enableSelection) {
QLabel *label = new QLabel(i18nc("@label:textbox",
"Configure which tags should "
"be applied."), this);
topLayout->addWidget(label);
}
topLayout->addWidget(d->m_tagsView);
topLayout->addLayout(newTagLayout);
d->ui.setupUi(this);
d->ui.tagsView->installEventFilter(this);
connect(d->ui.tagsView, &QAbstractItemView::entered, d.get(), &Private::slotItemEntered);
connect(d->ui.newTagEdit, &QLineEdit::textEdited, d.get(), &Private::slotTextEdited);
connect(d->ui.newTagEdit, &QLineEdit::returnPressed, d.get(), &Private::slotCreateTag);
connect(d->ui.newTagButton, &QAbstractButton::clicked, d.get(), &Private::slotCreateTag);
// create the delete button, which is shown when
// hovering the items
d->m_deleteButton = new QPushButton(d->m_tagsView->viewport());
d->m_deleteButton = new QPushButton(d->ui.tagsView->viewport());
d->m_deleteButton->setObjectName(QStringLiteral("tagDeleteButton"));
d->m_deleteButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
d->m_deleteButton->setToolTip(i18nc("@info", "Delete tag"));
d->m_deleteButton->hide();
connect(d->m_deleteButton, &QAbstractButton::clicked, d.data(), &Private::deleteTag);
}
d->m_deleteButtonTimer = new QTimer(this);
d->m_deleteButtonTimer->setSingleShot(true);
d->m_deleteButtonTimer->setInterval(500);
connect(d->m_deleteButtonTimer, &QTimer::timeout, d.data(), &Private::showDeleteButton);
TagEditWidget::TagEditWidget(Akonadi::TagModel *model, QWidget *parent, bool enableSelection)
: TagEditWidget(parent)
{
setModel(model);
setSelectionEnabled(enableSelection);
}
TagEditWidget::~TagEditWidget()
TagEditWidget::~TagEditWidget() = default;
void TagEditWidget::setSelectionEnabled(bool enabled)
{
if (enabled == (d->m_checkableProxy != nullptr)) {
return;
}
if (enabled) {
d->m_checkableProxy.reset(new KCheckableProxyModel(this));
if (d->m_model) {
d->initCheckableProxy(d->m_model);
}
d->ui.tagsView->setModel(d->m_checkableProxy.get());
} else {
d->m_checkableProxy.reset();
d->ui.tagsView->setModel(d->m_model);
}
d->ui.selectLabel->setVisible(enabled);
}
void TagEditWidget::setModel(TagModel *model)
{
if (d->m_model) {
disconnect(d->m_model, &QAbstractItemModel::rowsInserted, d.get(), &Private::onRowsInserted);
disconnect(d->m_model, &TagModel::populated, d.get(), &Private::onModelPopulated);
}
d->m_model = model;
if (d->m_model) {
connect(d->m_model, &QAbstractItemModel::rowsInserted, d.get(), &Private::onRowsInserted);
if (d->m_checkableProxy) {
d->initCheckableProxy(d->m_model);
d->ui.tagsView->setModel(d->m_checkableProxy.get());
} else {
d->ui.tagsView->setModel(d->m_model);
}
connect(d->m_model, &TagModel::populated, d.get(), &Private::onModelPopulated);
}
}
TagModel *TagEditWidget::model() const
{
return d->m_model;
}
bool TagEditWidget::selectionEnabled() const
{
return d->m_checkableProxy != nullptr;
}
void TagEditWidget::setSelection(const Akonadi::Tag::List &tags)
......@@ -258,12 +275,16 @@ void TagEditWidget::setSelection(const Akonadi::Tag::List &tags)
Akonadi::Tag::List TagEditWidget::selection() const
{
if (!d->m_checkableProxy) {
return {};
}
Akonadi::Tag::List list;
for (int i = 0; i < d->m_checkableProxy->rowCount(); ++i) {
if (d->m_checkableProxy->selectionModel()->isRowSelected(i, QModelIndex())) {
const QModelIndex index = d->m_checkableProxy->index(i, 0, QModelIndex());
const Akonadi::Tag tag = index.data(Akonadi::TagModel::TagRole).value<Akonadi::Tag>();
list << tag;
const auto index = d->m_checkableProxy->index(i, 0, QModelIndex());
const auto tag = index.data(TagModel::TagRole).value<Tag>();
list.push_back(tag);
}
}
return list;
......@@ -271,11 +292,11 @@ Akonadi::Tag::List TagEditWidget::selection() const
bool TagEditWidget::eventFilter(QObject *watched, QEvent *event)
{
if ((watched == d->m_tagsView) && (event->type() == QEvent::Leave)) {
d->m_deleteButtonTimer->stop();
if ((watched == d->ui.tagsView) && (event->type() == QEvent::Leave)) {
d->m_deleteButton->hide();
}
return QWidget::eventFilter(watched, event);
}
#include "tageditwidget.moc"
......@@ -39,9 +39,16 @@ class AKONADIWIDGETS_EXPORT TagEditWidget : public QWidget
{
Q_OBJECT
public:
explicit TagEditWidget(QWidget *parent = nullptr);
explicit TagEditWidget(Akonadi::TagModel *model, QWidget *parent = nullptr, bool enableSelection = false);
~TagEditWidget() override;
void setModel(Akonadi::TagModel *model);
Akonadi::TagModel *model() const;
void setSelectionEnabled(bool enabled);
bool selectionEnabled() const;
void setSelection(const Akonadi::Tag::List &tags);
Q_REQUIRED_RESULT Akonadi::Tag::List selection() const;
......@@ -50,7 +57,7 @@ protected:
private:
class Private;
QSharedPointer<Private> d;
QScopedPointer<Private> d;
};
}
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TagEditWidget</class>
<widget class="QWidget" name="TagEditWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="selectLabel">
<property name="text">
<string>Select tags that should be applied.</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="tagsView">
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="newTagEdit"/>
</item>
<item>
<widget class="QPushButton" name="newTagButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Create new tag</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
......@@ -20,27 +20,33 @@
*/
#include "tagmanagementdialog.h"
#include "ui_tagmanagementdialog.h"
#include "tagmodel.h"
#include "monitor.h"
#include "tageditwidget.h"
#include "controlgui.h"
#include <KLocalizedString>
#include <KSharedConfig>
#include <KConfigGroup>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
using namespace Akonadi;
struct Q_DECL_HIDDEN TagManagementDialog::Private {
Private(QDialog *parent)
: d(parent)
{}
~Private()
{
writeConfig();
}
void writeConfig();
void readConfig();
QDialog *d = nullptr;
Ui::TagManagementDialog ui;
QDialog * const d = nullptr;
QDialogButtonBox *buttonBox = nullptr;
};
......@@ -63,34 +69,23 @@ TagManagementDialog::TagManagementDialog(QWidget *parent)
: QDialog(parent)
, d(new Private(this))
{
setWindowTitle(i18nc("@title:window", "Manage Tags"));
QVBoxLayout *vbox = new QVBoxLayout(this);
Monitor *monitor = new Monitor(this);
monitor->setObjectName(QStringLiteral("TagManagementDialogMonitor"));
monitor->setTypeMonitored(Monitor::Tags);
Akonadi::TagModel *model = new Akonadi::TagModel(monitor, this);
vbox->addWidget(new Akonadi::TagEditWidget(model, this, false));
d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
connect(d->buttonBox, &QDialogButtonBox::accepted, this, &TagManagementDialog::accept);
connect(d->buttonBox, &QDialogButtonBox::rejected, this, &TagManagementDialog::reject);
QPushButton *okButton = d->buttonBox->button(QDialogButtonBox::Ok);
okButton->setDefault(true);
okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
vbox->addWidget(d->buttonBox);
d->ui.setupUi(this);
d->ui.tagEditWidget->setModel(new TagModel(monitor, this));
d->ui.tagEditWidget->setSelectionEnabled(false);
d->readConfig();
}
TagManagementDialog::~TagManagementDialog()
{
d->writeConfig();
ControlGui::widgetNeedsAkonadi(this);
}
TagManagementDialog::~TagManagementDialog() = default;
QDialogButtonBox *TagManagementDialog::buttons() const
{
return d->buttonBox;
}
......@@ -46,7 +46,7 @@ public:
private:
struct Private;
QSharedPointer<Private> d;
QScopedPointer<Private> d;
};
}
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TagManagementDialog</class>
<widget class="QDialog" name="TagManagementDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>