14#include <config-libkleo.h>
16#include "keyselectiondialog.h"
18#include "keylistview.h"
19#include "progressdialog.h"
21#include <libkleo/compat.h>
22#include <libkleo/compliance.h>
23#include <libkleo/dn.h>
24#include <libkleo/formatting.h>
26#include <kleo_ui_debug.h>
29#include <KConfigGroup>
30#include <KLocalizedString>
32#include <KSharedConfig>
34#include <QGpgME/KeyListJob>
36#include <QApplication>
38#include <QDialogButtonBox>
46#include <QRegularExpression>
51#include <gpgme++/key.h>
52#include <gpgme++/keylistresult.h>
60static bool checkKeyUsage(
const GpgME::Key &key,
unsigned int keyUsage,
QString *statusString =
nullptr)
62 auto setStatusString = [statusString](
const QString &
status) {
68 if (keyUsage & KeySelectionDialog::ValidKeys) {
69 if (key.isInvalid()) {
70 if (key.keyListMode() & GpgME::Validate) {
71 qCDebug(KLEO_UI_LOG) <<
"key is invalid";
72 setStatusString(
i18n(
"The key is not valid."));
75 qCDebug(KLEO_UI_LOG) <<
"key is invalid - ignoring";
78 if (key.isExpired()) {
79 qCDebug(KLEO_UI_LOG) <<
"key is expired";
80 setStatusString(
i18n(
"The key is expired."));
82 }
else if (key.isRevoked()) {
83 qCDebug(KLEO_UI_LOG) <<
"key is revoked";
84 setStatusString(
i18n(
"The key is revoked."));
86 }
else if (key.isDisabled()) {
87 qCDebug(KLEO_UI_LOG) <<
"key is disabled";
88 setStatusString(
i18n(
"The key is disabled."));
93 if (keyUsage & KeySelectionDialog::EncryptionKeys && !Kleo::keyHasEncrypt(key)) {
94 qCDebug(KLEO_UI_LOG) <<
"key can't encrypt";
95 setStatusString(
i18n(
"The key is not designated for encryption."));
98 if (keyUsage & KeySelectionDialog::SigningKeys && !Kleo::keyHasSign(key)) {
99 qCDebug(KLEO_UI_LOG) <<
"key can't sign";
100 setStatusString(
i18n(
"The key is not designated for signing."));
103 if (keyUsage & KeySelectionDialog::CertificationKeys && !Kleo::keyHasCertify(key)) {
104 qCDebug(KLEO_UI_LOG) <<
"key can't certify";
105 setStatusString(
i18n(
"The key is not designated for certifying."));
108 if (keyUsage & KeySelectionDialog::AuthenticationKeys && !Kleo::keyHasAuthenticate(key)) {
109 qCDebug(KLEO_UI_LOG) <<
"key can't authenticate";
110 setStatusString(
i18n(
"The key is not designated for authentication."));
114 if (keyUsage & KeySelectionDialog::SecretKeys && !(keyUsage & KeySelectionDialog::PublicKeys) && !key.hasSecret()) {
115 qCDebug(KLEO_UI_LOG) <<
"key isn't secret";
116 setStatusString(
i18n(
"The key is not secret."));
120 if (keyUsage & KeySelectionDialog::TrustedKeys && key.protocol() == GpgME::OpenPGP &&
124 std::vector<GpgME::UserID> uids = key.userIDs();
125 for (std::vector<GpgME::UserID>::const_iterator it = uids.begin(); it != uids.end(); ++it) {
126 if (!it->isRevoked() && it->validity() >= GpgME::UserID::Marginal) {
127 setStatusString(
i18n(
"The key can be used."));
131 qCDebug(KLEO_UI_LOG) <<
"key has no UIDs with validity >= Marginal";
132 setStatusString(
i18n(
"The key is not trusted enough."));
138 setStatusString(
i18n(
"The key can be used."));
142static bool checkKeyUsage(
const std::vector<GpgME::Key> &keys,
unsigned int keyUsage)
144 for (
auto it = keys.begin(); it != keys.end(); ++it) {
145 if (!checkKeyUsage(*it, keyUsage)) {
155class ColumnStrategy :
public KeyListView::ColumnStrategy
158 ColumnStrategy(
unsigned int keyUsage);
160 QString title(
int col)
const override;
161 int width(
int col,
const QFontMetrics &fm)
const override;
163 QString text(
const GpgME::Key &key,
int col)
const override;
164 QString accessibleText(
const GpgME::Key &key,
int column)
const override;
165 QString toolTip(
const GpgME::Key &key,
int col)
const override;
166 QIcon icon(
const GpgME::Key &key,
int col)
const override;
169 const QIcon mKeyGoodPix, mKeyBadPix, mKeyUnknownPix, mKeyValidPix;
170 const unsigned int mKeyUsage;
173ColumnStrategy::ColumnStrategy(
unsigned int keyUsage)
174 : KeyListView::ColumnStrategy()
175 , mKeyGoodPix(QStringLiteral(
":/libkleopatra/key_ok"))
176 , mKeyBadPix(QStringLiteral(
":/libkleopatra/key_bad"))
177 , mKeyUnknownPix(QStringLiteral(
":/libkleopatra/key_unknown"))
178 , mKeyValidPix(QStringLiteral(
":/libkleopatra/key"))
179 , mKeyUsage(keyUsage)
182 qCWarning(KLEO_UI_LOG) <<
"KeySelectionDialog: keyUsage == 0. You want to use AllKeys instead.";
186QString ColumnStrategy::title(
int col)
const
190 return i18n(
"Key ID");
192 return i18n(
"User ID");
198int ColumnStrategy::width(
int col,
const QFontMetrics &fm)
const
201 static const char hexchars[] =
"0123456789ABCDEF";
203 for (
unsigned int i = 0; i < 16; ++i) {
206 return 8 * maxWidth + 2 * 16 ;
208 return KeyListView::ColumnStrategy::width(col, fm);
211QString ColumnStrategy::text(
const GpgME::Key &key,
int col)
const
216 return Formatting::prettyID(key.keyID());
218 return xi18n(
"<placeholder>unknown</placeholder>");
222 const char *uid = key.userID(0).id();
223 if (key.protocol() == GpgME::OpenPGP) {
234QString ColumnStrategy::accessibleText(
const GpgME::Key &key,
int col)
const
239 return Formatting::accessibleHexID(key.keyID());
248QString ColumnStrategy::toolTip(
const GpgME::Key &key,
int)
const
250 const char *uid = key.userID(0).id();
251 const char *fpr = key.primaryFingerprint();
252 const char *issuer = key.issuerName();
253 const GpgME::Subkey subkey = key.subkey(0);
254 const QString expiry = Formatting::expirationDateString(subkey);
255 const QString creation = Formatting::creationDateString(subkey);
257 if (!checkKeyUsage(key, mKeyUsage, &keyStatusString)) {
262 QString html = QStringLiteral(
"<qt><p style=\"style='white-space:pre'\">");
263 if (key.protocol() == GpgME::OpenPGP) {
266 html +=
i18n(
"S/MIME key for <b>%1</b>", uid ?
DN(uid).prettyDN() :
i18n(
"unknown"));
268 html += QStringLiteral(
"</p><table>");
271 html += QStringLiteral(
"<tr><td align=\"right\"><b>%1: </b></td><td>%2</td></tr>").
arg(name, value);
276 if (key.protocol() != GpgME::OpenPGP) {
277 addRow(
i18nc(
"Key issuer",
"Issuer"), issuer ?
DN(issuer).prettyDN() :
i18n(
"unknown"));
279 addRow(
i18nc(
"Key status",
"Status"), keyStatusString);
280 if (DeVSCompliance::isActive()) {
281 addRow(
i18nc(
"Compliance of key",
"Compliance"), DeVSCompliance::name(key.isDeVs()));
283 html += QStringLiteral(
"</table></qt>");
288QIcon ColumnStrategy::icon(
const GpgME::Key &key,
int col)
const
294 if (!(key.keyListMode() & GpgME::Validate)) {
295 return mKeyUnknownPix;
298 if (!checkKeyUsage(key, mKeyUsage)) {
302 if (key.protocol() == GpgME::CMS) {
306 switch (key.userID(0).validity()) {
308 case GpgME::UserID::Unknown:
309 case GpgME::UserID::Undefined:
310 return mKeyUnknownPix;
311 case GpgME::UserID::Never:
313 case GpgME::UserID::Marginal:
314 case GpgME::UserID::Full:
315 case GpgME::UserID::Ultimate: {
316 if (DeVSCompliance::isActive() && !key.isDeVs()) {
326static const int sCheckSelectionDelay = 250;
328KeySelectionDialog::KeySelectionDialog(
QWidget *parent, Options options)
330 , mOpenPGPBackend(QGpgME::openpgp())
331 , mSMIMEBackend(QGpgME::smime())
334 qCDebug(KLEO_UI_LOG) <<
"mTruncated:" << mTruncated <<
"mSavedOffsetY:" << mSavedOffsetY;
338KeySelectionDialog::KeySelectionDialog(
const QString &title,
340 const std::vector<GpgME::Key> &selectedKeys,
341 unsigned int keyUsage,
342 bool extendedSelection,
347 , mSelectedKeys(selectedKeys)
348 , mKeyUsage(keyUsage)
350 setWindowTitle(title);
352 init(rememberChoice, extendedSelection, text,
QString());
355KeySelectionDialog::KeySelectionDialog(
const QString &title,
358 const std::vector<GpgME::Key> &selectedKeys,
359 unsigned int keyUsage,
360 bool extendedSelection,
365 , mSelectedKeys(selectedKeys)
366 , mKeyUsage(keyUsage)
367 , mSearchText(initialQuery)
368 , mInitialQuery(initialQuery)
370 setWindowTitle(title);
372 init(rememberChoice, extendedSelection, text, initialQuery);
375KeySelectionDialog::KeySelectionDialog(
const QString &title,
378 unsigned int keyUsage,
379 bool extendedSelection,
384 , mKeyUsage(keyUsage)
385 , mSearchText(initialQuery)
386 , mInitialQuery(initialQuery)
388 setWindowTitle(title);
390 init(rememberChoice, extendedSelection, text, initialQuery);
393void KeySelectionDialog::setUpUI(Options options,
const QString &initialQuery)
401 mCheckSelectionTimer =
new QTimer(
this);
402 mStartSearchTimer =
new QTimer(
this);
405 mainLayout->addWidget(page);
406 mainLayout->addWidget(buttonBox);
411 mTextLabel =
new QLabel(page);
425 searchExternalPB->
hide();
432 le->setClearButtonEnabled(
true);
433 le->setText(initialQuery);
438 hlay->addWidget(lbSearchFor);
439 hlay->addWidget(le, 1);
447 mKeyListView =
new KeyListView(
new ColumnStrategy(mKeyUsage),
nullptr, page);
454 if (options & ExtendedSelection) {
459 if (options & RememberChoice) {
460 mRememberCB =
new QCheckBox(
i18nc(
"@option:check",
"&Remember choice"), page);
463 i18n(
"<qt><p>If you check this box your choice will "
464 "be stored and you will not be asked again."
469 slotCheckSelection();
473 connect(mKeyListView, &KeyListView::doubleClicked,
this, &KeySelectionDialog::slotTryOk);
474 connect(mKeyListView, &KeyListView::contextMenu,
this, &KeySelectionDialog::slotRMB);
476 if (options & RereadKeys) {
481 if (options & ExternalCertificateManager) {
485 slotStartCertificateManager();
496 dialogSize = dialogConfig.readEntry(
"Dialog size", dialogSize);
505void KeySelectionDialog::init(
bool rememberChoice,
bool extendedSelection,
const QString &text,
const QString &initialQuery)
507 Options options = {RereadKeys, ExternalCertificateManager};
508 options.setFlag(ExtendedSelection, extendedSelection);
509 options.setFlag(RememberChoice, rememberChoice);
511 setUpUI(options, initialQuery);
514 if (mKeyUsage & OpenPGPKeys) {
515 mOpenPGPBackend = QGpgME::openpgp();
517 if (mKeyUsage & SMIMEKeys) {
518 mSMIMEBackend = QGpgME::smime();
524KeySelectionDialog::~KeySelectionDialog()
528 dialogConfig.writeEntry(
"Dialog size",
size());
529 dialogConfig.writeEntry(
"header", mKeyListView->
header()->
saveState());
533void KeySelectionDialog::setText(
const QString &text)
539void KeySelectionDialog::setKeys(
const std::vector<GpgME::Key> &keys)
541 for (
const GpgME::Key &key : keys) {
542 mKeyListView->slotAddKey(key);
546void KeySelectionDialog::connectSignals()
548 if (mKeyListView->isMultiSelection()) {
552 qOverload<KeyListViewItem *>(&KeyListView::selectionChanged),
554 qOverload<KeyListViewItem *>(&KeySelectionDialog::slotCheckSelection));
558void KeySelectionDialog::disconnectSignals()
560 if (mKeyListView->isMultiSelection()) {
564 qOverload<KeyListViewItem *>(&KeyListView::selectionChanged),
566 qOverload<KeyListViewItem *>(&KeySelectionDialog::slotCheckSelection));
570const GpgME::Key &KeySelectionDialog::selectedKey()
const
572 static const GpgME::Key null = GpgME::Key::null;
573 if (mKeyListView->isMultiSelection() || !mKeyListView->selectedItem()) {
576 return mKeyListView->selectedItem()->key();
579QString KeySelectionDialog::fingerprint()
const
584QStringList KeySelectionDialog::fingerprints()
const
587 for (
auto it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it) {
588 if (
const char *fpr = it->primaryFingerprint()) {
595QStringList KeySelectionDialog::pgpKeyFingerprints()
const
598 for (
auto it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it) {
599 if (it->protocol() == GpgME::OpenPGP) {
600 if (
const char *fpr = it->primaryFingerprint()) {
608QStringList KeySelectionDialog::smimeFingerprints()
const
611 for (
auto it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it) {
612 if (it->protocol() == GpgME::CMS) {
613 if (
const char *fpr = it->primaryFingerprint()) {
621void KeySelectionDialog::slotRereadKeys()
623 mKeyListView->clear();
632 if (mOpenPGPBackend) {
633 startKeyListJobForBackend(mOpenPGPBackend, std::vector<GpgME::Key>(),
false );
636 startKeyListJobForBackend(mSMIMEBackend, std::vector<GpgME::Key>(),
false );
639 if (mListJobCount == 0) {
642 i18n(
"No backends found for listing keys. "
643 "Check your installation."),
644 i18nc(
"@title:window",
"Key Listing Failed"));
649void KeySelectionDialog::slotStartCertificateManager(
const QString &query)
654 args << QStringLiteral(
"--search") <<
query;
657 if (
exec.isEmpty()) {
658 qCWarning(KLEO_UI_LOG) <<
"Could not find kleopatra executable in PATH";
660 i18n(
"Could not start certificate manager; "
661 "please check your installation."),
662 i18nc(
"@title:window",
"Certificate Manager Error"));
665 qCDebug(KLEO_UI_LOG) <<
"\nslotStartCertManager(): certificate manager started.";
669#ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
670#define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
671static void showKeyListError(
QWidget *parent,
const GpgME::Error &err)
675 "<qt><p>An error occurred while fetching "
676 "the keys from the backend:</p>"
677 "<p><b>%1</b></p></qt>",
678 Formatting::errorAsString(err));
686struct ExtractFingerprint {
687 QString operator()(
const GpgME::Key &key)
694void KeySelectionDialog::startKeyListJobForBackend(
const QGpgME::Protocol *backend,
const std::vector<GpgME::Key> &keys,
bool validate)
697 QGpgME::KeyListJob *job = backend->keyListJob(
false,
false, validate);
702 connect(job, &QGpgME::KeyListJob::result,
this, &KeySelectionDialog::slotKeyListResult);
704 connect(job, &QGpgME::KeyListJob::nextKey, mKeyListView, &KeyListView::slotRefreshKey);
706 connect(job, &QGpgME::KeyListJob::nextKey, mKeyListView, &KeyListView::slotAddKey);
710 std::transform(keys.begin(), keys.end(), std::back_inserter(fprs), ExtractFingerprint());
711 const GpgME::Error err = job->start(fprs, mKeyUsage & SecretKeys && !(mKeyUsage & PublicKeys));
714 return showKeyListError(
this, err);
717#ifndef LIBKLEO_NO_PROGRESSDIALOG
719 (void)
new ProgressDialog(job, validate ?
i18n(
"Checking selected keys...") :
i18n(
"Fetching keys..."),
this);
724static void selectKeys(KeyListView *klv,
const std::vector<GpgME::Key> &selectedKeys)
727 if (selectedKeys.empty()) {
730 for (
auto it = selectedKeys.begin(); it != selectedKeys.end(); ++it) {
731 if (KeyListViewItem *item = klv->itemByFingerprint(it->primaryFingerprint())) {
732 item->setSelected(
true);
737void KeySelectionDialog::slotKeyListResult(
const GpgME::KeyListResult &res)
740 showKeyListError(
this, res.error());
741 }
else if (res.isTruncated()) {
745 if (--mListJobCount > 0) {
749 if (mTruncated > 0) {
751 i18np(
"<qt>One backend returned truncated output.<p>"
752 "Not all available keys are shown</p></qt>",
753 "<qt>%1 backends returned truncated output.<p>"
754 "Not all available keys are shown</p></qt>",
756 i18n(
"Key List Result"));
759 mKeyListView->flushKeys();
762 mListJobCount = mTruncated = 0;
763 mKeysToCheck.clear();
765 selectKeys(mKeyListView, mSelectedKeys);
771 slotSelectionChanged();
778void KeySelectionDialog::slotSelectionChanged()
780 qCDebug(KLEO_UI_LOG) <<
"KeySelectionDialog::slotSelectionChanged()";
785 mCheckSelectionTimer->
start(sCheckSelectionDelay);
790struct AlreadyChecked {
791 bool operator()(
const GpgME::Key &key)
const
793 return key.keyListMode() & GpgME::Validate;
798void KeySelectionDialog::slotCheckSelection(KeyListViewItem *item)
800 qCDebug(KLEO_UI_LOG) <<
"KeySelectionDialog::slotCheckSelection()";
802 mCheckSelectionTimer->
stop();
804 mSelectedKeys.clear();
806 if (!mKeyListView->isMultiSelection()) {
808 mSelectedKeys.push_back(item->key());
812 for (KeyListViewItem *it = mKeyListView->firstChild(); it; it = it->nextSibling()) {
813 if (it->isSelected()) {
814 mSelectedKeys.push_back(it->key());
818 mKeysToCheck.clear();
819 std::remove_copy_if(mSelectedKeys.begin(), mSelectedKeys.end(), std::back_inserter(mKeysToCheck), AlreadyChecked());
820 if (mKeysToCheck.empty()) {
821 mOkButton->
setEnabled(!mSelectedKeys.empty() && checkKeyUsage(mSelectedKeys, mKeyUsage));
826 startValidatingKeyListing();
829void KeySelectionDialog::startValidatingKeyListing()
831 if (mKeysToCheck.empty()) {
842 std::vector<GpgME::Key> smime;
843 std::vector<GpgME::Key> openpgp;
844 for (std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin(); it != mKeysToCheck.end(); ++it) {
845 if (it->protocol() == GpgME::OpenPGP) {
846 openpgp.push_back(*it);
848 smime.push_back(*it);
852 if (!openpgp.empty()) {
853 Q_ASSERT(mOpenPGPBackend);
854 startKeyListJobForBackend(mOpenPGPBackend, openpgp,
true );
856 if (!smime.empty()) {
857 Q_ASSERT(mSMIMEBackend);
858 startKeyListJobForBackend(mSMIMEBackend, smime,
true );
861 Q_ASSERT(mListJobCount > 0);
864bool KeySelectionDialog::rememberSelection()
const
866 return mRememberCB && mRememberCB->
isChecked();
869void KeySelectionDialog::slotRMB(KeyListViewItem *item,
const QPoint &p)
875 mCurrentContextMenuItem = item;
878 menu.
addAction(
i18n(
"Recheck Key"),
this, &KeySelectionDialog::slotRecheckKey);
882void KeySelectionDialog::slotRecheckKey()
884 if (!mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull()) {
888 mKeysToCheck.clear();
889 mKeysToCheck.push_back(mCurrentContextMenuItem->key());
892void KeySelectionDialog::slotTryOk()
894 if (!mSelectedKeys.empty() && checkKeyUsage(mSelectedKeys, mKeyUsage)) {
899void KeySelectionDialog::slotOk()
901 if (mCheckSelectionTimer->
isActive()) {
902 slotCheckSelection();
906 if (!mSelectedKeys.empty() && checkKeyUsage(mSelectedKeys, mKeyUsage)) {
910 mStartSearchTimer->
stop();
914void KeySelectionDialog::slotCancel()
916 mCheckSelectionTimer->
stop();
917 mStartSearchTimer->
stop();
921void KeySelectionDialog::slotSearch(
const QString &text)
927void KeySelectionDialog::slotSearch()
930 mStartSearchTimer->
start(sCheckSelectionDelay);
933void KeySelectionDialog::slotFilter()
942 if (keyIdRegExp.match(mSearchText).hasMatch()) {
945 filterByKeyID(mSearchText.
mid(2));
948 filterByKeyIDOrUID(mSearchText);
952 filterByUID(mSearchText);
956void KeySelectionDialog::filterByKeyID(
const QString &keyID)
958 Q_ASSERT(keyID.
length() <= 16);
963 for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
975 const std::vector<GpgME::UserID> uids = item->key().userIDs();
976 for (
auto it = uids.begin(); it != uids.end(); ++it) {
984void KeySelectionDialog::filterByKeyIDOrUID(
const QString &str)
991 for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
996void KeySelectionDialog::filterByUID(
const QString &str)
1003 for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
1004 item->
setHidden(!anyUIDMatches(item, rx));
1008void KeySelectionDialog::showAllItems()
1010 for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
1015#include "moc_keyselectiondialog.cpp"
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
A progress dialog for Kleo::Jobs.
Q_SCRIPTABLE CaptureState status()
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString xi18n(const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void setSelectionMode(QAbstractItemView::SelectionMode mode)
void addLayout(QLayout *layout, int stretch)
bool isEmpty() const const
virtual QSize sizeHint() const const override
QRect boundingRect(QChar ch) const const
void linkActivated(const QString &link)
void setBuddy(QWidget *buddy)
void setText(const QString &)
void setWordWrap(bool on)
void setContentsMargins(const QMargins &margins)
void textChanged(const QString &text)
bool isEmpty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
void setObjectName(QAnyStringView name)
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
QString anchoredPattern(QStringView expression)
QString escape(QStringView str)
bool hasMatch() const const
QString findExecutable(const QString &executableName, const QStringList &paths)
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString toUpper() const const
QString trimmed() const const
QTestData & addRow(const char *format,...)
bool isActive() const const
void setSingleShot(bool singleShot)
void setRootIsDecorated(bool show)
void setSortingEnabled(bool enable)
QString text(int column) const const