Git commit b19141b9bfabf727d771f7ac8ee9588194af39e5 by Jan Kundr?t. Committed on 02/01/2014 at 20:30. Pushed by jkt into branch 'master'.
GUI: move the "mark as reply" selector to the row of buttons There's a GCI task for changing various replying modes from within the composer (think reply-to-all vs. reply-privately). That change needs a button to be added somewhere, so it makes sense to use a button for the feature which Thomas added yesterday. Besides, it seems to me that it is a bit easier to discover this way. This is best viewed as a diff from commit 944a49e33562bd508a2af6e0dcfc938ba2769f1b; that way it is clearer what has changed compared to the standalone-checkbox approach. v2 changes: - Hide the button altogether when not replying instead of just disabling it. - Pretty formatting of the tooltips and sanitization of HTML input - Better captions Thanks to Thomas L?bking for his comments. v3 changes: - Enable quick toggling via a default action, without expanding the menu - Fix restoring of v2 drafts v4 changes: - Removed one superfluous QAction::trigger - Better identifiers for the slots for updating & processing the quick toggle action - Changed the caption of the threaded reply marking action - Some inline comments REVIEW: 114815 M +73 -26 src/Gui/ComposeWidget.cpp M +9 -2 src/Gui/ComposeWidget.h M +6 -36 src/Gui/ComposeWidget.ui http://commits.kde.org/trojita/b19141b9bfabf727d771f7ac8ee9588194af39e5 diff --git a/src/Gui/ComposeWidget.cpp b/src/Gui/ComposeWidget.cpp index 1b98081..3b0ef6d 100644 --- a/src/Gui/ComposeWidget.cpp +++ b/src/Gui/ComposeWidget.cpp @@ -32,6 +32,7 @@ #include <QPushButton> #include <QSettings> #include <QTimer> +#include <QToolButton> #include "ui_ComposeWidget.h" #include "Composer/MessageComposer.h" @@ -60,7 +61,6 @@ namespace { enum { OFFSET_OF_FIRST_ADDRESSEE = 1, MIN_MAX_VISIBLE_RECIPIENTS = 4 }; -enum { IN_REPLY_TO = 0, SUBJECT = 1 }; } namespace Gui @@ -123,7 +123,34 @@ ComposeWidget::ComposeWidget(MainWindow *mainWindow, QSettings *settings, MSA::M ui->recipientSlider->setVisible(false); ui->envelopeWidget->installEventFilter(this); - connect(ui->markAsReply, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleInReplyTo(int))); + m_markButton = new QToolButton(ui->buttonBox); + m_markButton->setPopupMode(QToolButton::MenuButtonPopup); + m_markButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + m_markAsReply = new QActionGroup(m_markButton); + m_markAsReply->setExclusive(true); + auto *asReplyMenu = new QMenu(m_markButton); + m_markButton->setMenu(asReplyMenu); + m_actionStandalone = asReplyMenu->addAction(tr("Standalone")); + m_actionStandalone->setActionGroup(m_markAsReply); + m_actionStandalone->setCheckable(true); + m_actionStandalone->setToolTip(tr("This mail will be sent as a standalone message.<hr/>Change to preserve the reply hierarchy.")); + m_actionInReplyTo = asReplyMenu->addAction(tr("Threaded")); + m_actionInReplyTo->setActionGroup(m_markAsReply); + m_actionInReplyTo->setCheckable(true); + + // This is a "quick shortcut action". It shows the UI bits of the current option, but when the user clicks it, + // the *other* action is triggered. + m_actionToggleMarking = new QAction(m_markButton); + connect(m_actionToggleMarking, SIGNAL(triggered()), this, SLOT(toggleReplyMarking())); + m_markButton->setDefaultAction(m_actionToggleMarking); + + // Unfortunately, there's no signal for toggled(QAction*), so we'll have to call QAction::trigger() to have this working + connect(m_markAsReply, SIGNAL(triggered(QAction*)), this, SLOT(updateReplyMarkingAction())); + m_actionStandalone->trigger(); + // We want to have the button aligned to the left; the only "portable" way of this is the ResetRole + // (thanks to TL for mentioning this, and for the Qt's doc for providing pretty pictures on different platforms) + ui->buttonBox->addButton(m_markButton, QDialogButtonBox::ResetRole); + m_markButton->hide(); ui->mailText->setFont(Gui::Util::systemMonospaceFont()); @@ -294,7 +321,7 @@ bool ComposeWidget::buildMessageData() } m_submission->composer()->setText(ui->mailText->toPlainText()); - if (ui->markAsReply->currentIndex() == IN_REPLY_TO) { + if (m_actionInReplyTo->isChecked()) { m_submission->composer()->setInReplyTo(m_inReplyTo); m_submission->composer()->setReferences(m_references); m_submission->composer()->setReplyingToMessage(m_replyingToMessage); @@ -365,15 +392,20 @@ void ComposeWidget::setData(const QList<QPair<Composer::RecipientKind, QString> m_references = references; m_replyingToMessage = replyingToMessage; if (m_replyingToMessage.isValid()) { - QVariant replySubject = m_replyingToMessage.data(Imap::Mailbox::RoleMessageSubject); - ui->markAsReply->setProperty("tooltip", replySubject); - ui->markAsReply->setToolTip(replySubject.toString()); - ui->subjectLabel->hide(); - ui->markAsReply->show(); - ui->markAsReply->setCurrentIndex(IN_REPLY_TO); + m_markButton->show(); + // Got to use trigger() so that the default action of the QToolButton is updated + m_actionInReplyTo->setToolTip(tr("This mail will be marked as a response<hr/>%1").arg( +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + m_replyingToMessage.data(Imap::Mailbox::RoleMessageSubject).toString().toHtmlEscaped() +#else + Qt::escape(m_replyingToMessage.data(Imap::Mailbox::RoleMessageSubject).toString()) +#endif + )); + m_actionInReplyTo->trigger(); } else { - ui->markAsReply->hide(); - ui->subjectLabel->show(); + m_markButton->hide(); + m_actionInReplyTo->setToolTip(QString()); + m_actionStandalone->trigger(); } int row = -1; @@ -1008,7 +1040,7 @@ void ComposeWidget::saveDraft(const QString &path) stream << m_recipients.at(i).second->text(); } stream << m_submission->composer()->timestamp() << m_inReplyTo << m_references; - stream << bool(ui->markAsReply->currentIndex() == IN_REPLY_TO); + stream << m_actionInReplyTo->isChecked(); stream << ui->subject->text(); stream << ui->mailText->toPlainText(); // we spare attachments @@ -1060,12 +1092,8 @@ void ComposeWidget::loadDraft(const QString &path) QDateTime timestamp; stream >> timestamp >> m_inReplyTo >> m_references; m_submission->composer()->setTimestamp(timestamp); - if (m_inReplyTo.isEmpty()) { - ui->markAsReply->hide(); - ui->subjectLabel->show(); - } else { - ui->subjectLabel->hide(); - ui->markAsReply->show(); + if (!m_inReplyTo.isEmpty()) { + m_markButton->show(); // We do not have the message index at this point, but we can at least show the Message-Id here QStringList inReplyTo; @@ -1073,13 +1101,28 @@ void ComposeWidget::loadDraft(const QString &path) // There's no HTML escaping to worry about inReplyTo << QLatin1Char('<') + QString::fromUtf8(item.constData()) + QLatin1Char('>'); } - ui->markAsReply->setProperty("tooltip", tr("In-Reply-To: %1").arg(inReplyTo.join(tr(", ")))); + m_actionInReplyTo->setToolTip(tr("This mail will be marked as a response<hr/>%1").arg( +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + inReplyTo.join(tr("<br/>")).toHtmlEscaped() +#else + Qt::escape(inReplyTo.join(tr("<br/>"))) +#endif + )); + if (version == 2) { + // it is always marked as a reply in v2 + m_actionInReplyTo->trigger(); + } } } if (version >= 3) { bool replyChecked; stream >> replyChecked; - ui->markAsReply->setCurrentIndex(replyChecked ? IN_REPLY_TO : SUBJECT); + // Got to use trigger() so that the default action of the QToolButton is updated + if (replyChecked) { + m_actionInReplyTo->trigger(); + } else { + m_actionStandalone->trigger(); + } } stream >> string; ui->subject->setText(string); @@ -1111,13 +1154,17 @@ void ComposeWidget::updateWindowTitle() } } -void ComposeWidget::toggleInReplyTo(int mode) +void ComposeWidget::toggleReplyMarking() { - if (mode == IN_REPLY_TO) { - ui->markAsReply->setToolTip(ui->markAsReply->property("tooltip").toString()); - } else { - ui->markAsReply->setToolTip(tr("Change to preserve reply hierarchy")); - } + (m_actionInReplyTo->isChecked() ? m_actionStandalone : m_actionInReplyTo)->trigger(); +} + +void ComposeWidget::updateReplyMarkingAction() +{ + auto action = m_markAsReply->checkedAction(); + m_actionToggleMarking->setText(action->text()); + m_actionToggleMarking->setIcon(action->icon()); + m_actionToggleMarking->setToolTip(action->toolTip()); } } diff --git a/src/Gui/ComposeWidget.h b/src/Gui/ComposeWidget.h index af3d03d..d556af4 100644 --- a/src/Gui/ComposeWidget.h +++ b/src/Gui/ComposeWidget.h @@ -36,11 +36,13 @@ class ComposeWidget; } class QAbstractListModel; +class QActionGroup; class QComboBox; class QLineEdit; class QMenu; class QPushButton; class QSettings; +class QToolButton; namespace Composer { class Submission; @@ -111,8 +113,8 @@ private slots: void setUiWidgetsEnabled(const bool enabled); void passwordRequested(const QString &user, const QString &host); - - void toggleInReplyTo(int mode); + void toggleReplyMarking(); + void updateReplyMarkingAction(); private: static QByteArray extractMailAddress(const QString &text, bool &ok); @@ -130,6 +132,11 @@ private: Ui::ComposeWidget *ui; QPushButton *sendButton; QPushButton *cancelButton; + QToolButton *m_markButton; + QActionGroup *m_markAsReply; + QAction *m_actionStandalone; + QAction *m_actionInReplyTo; + QAction *m_actionToggleMarking; typedef QPair<QComboBox*, QLineEdit*> Recipient; QList<Recipient> m_recipients; QTimer *m_recipientListUpdateTimer; diff --git a/src/Gui/ComposeWidget.ui b/src/Gui/ComposeWidget.ui index f2f6cdc..559a849 100644 --- a/src/Gui/ComposeWidget.ui +++ b/src/Gui/ComposeWidget.ui @@ -72,44 +72,14 @@ </widget> </item> <item row="1" column="0"> - <layout class="QHBoxLayout" name="horizontalLayout1"> - <property name="spacing"> - <number>0</number> + <widget class="QLabel" name="subjectLabel"> + <property name="text"> + <string>Subject</string> </property> - <property name="margin"> - <number>0</number> + <property name="buddy"> + <cstring>subject</cstring> </property> - <item> - <widget class="QLabel" name="subjectLabel"> - <property name="text"> - <string>Subject</string> - </property> - <property name="buddy"> - <cstring>subject</cstring> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="markAsReply"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <item> - <property name="text"> - <string>Reply to</string> - </property> - </item> - <item> - <property name="text"> - <string>Subject</string> - </property> - </item> - </widget> - </item> - </layout> + </widget> </item> <item row="1" column="1"> <widget class="LineEdit" name="subject"/>
