reportassistantpages_bugzilla.cpp 30.8 KB
Newer Older
1
2
3
/*******************************************************************
* reportassistantpages_bugzilla.cpp
* Copyright 2009, 2010, 2011    Dario Andres Rodriguez <andresbajotierra@gmail.com>
4
* Copyright 2019 Harald Sitter <sitter@kde.org>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************/

#include "reportassistantpages_bugzilla.h"

23
#include <QAction>
24
#include <QTimer>
25
26
27
28
29
30
#include <QLabel>
#include <QCheckBox>
#include <QToolTip>
#include <QCursor>
#include <QFileDialog>
#include <QTemporaryFile>
31
#include <QTextBrowser>
David Edmundson's avatar
David Edmundson committed
32
#include <QDesktopServices>
33
#include <QWindow>
34

Laurent Montel's avatar
Laurent Montel committed
35
#include "drkonqi_debug.h"
36
37
#include <KMessageBox>
#include <KLocalizedString>
38
#include <kwallet.h>
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <KCapacityBar>

/* Unhandled error dialog includes */
#include <KIO/Job>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KJobWidgets>

#include "reportinterface.h"
#include "systeminformation.h"
#include "crashedapplication.h"
#include "bugzillalib.h"
#include "statuswidget.h"
#include "drkonqi.h"
#include "drkonqi_globals.h"
#include "applicationdetailsexamples.h"

static const char kWalletEntryName[] = "drkonqi_bugzilla";
static const char kWalletEntryUsername[] = "username";
static const char kWalletEntryPassword[] = "password";

Laurent Montel's avatar
Laurent Montel committed
60
static QString konquerorKWalletEntryName = KDE_BUGZILLA_URL + QStringLiteral("index.cgi#login");
61
62
63
64
65
66
67
static const char konquerorKWalletEntryUsername[] = "Bugzilla_login";
static const char konquerorKWalletEntryPassword[] = "Bugzilla_password";

//BEGIN BugzillaLoginPage

BugzillaLoginPage::BugzillaLoginPage(ReportAssistantDialog * parent) :
        ReportAssistantPage(parent),
68
69
        m_wallet(nullptr),
        m_walletWasOpenedBefore(false)
70
{
71
72
    connect(bugzillaManager(), &BugzillaManager::loginFinished, this, &BugzillaLoginPage::loginFinished);
    connect(bugzillaManager(), &BugzillaManager::loginError, this, &BugzillaLoginPage::loginError);
73
74
75
76
77
78
79

    ui.setupUi(this);
    ui.m_statusWidget->setIdle(i18nc("@info:status '1' is replaced with the short URL of the bugzilla ",
                                   "You need to login with your %1 account in order to proceed.",
                                   QLatin1String(KDE_BUGZILLA_SHORT_URL)));

    KGuiItem::assign(ui.m_loginButton, KGuiItem2(i18nc("@action:button", "Login"),
80
                                              QIcon::fromTheme(QStringLiteral("network-connect")),
81
82
                                              i18nc("@info:tooltip", "Use this button to login "
                                              "to the KDE bug tracking system using the provided "
83
                                              "e-mail address and password.")));
84
85
    ui.m_loginButton->setEnabled(false);

86
    connect(ui.m_loginButton, &QPushButton::clicked, this, &BugzillaLoginPage::loginClicked);
87

88
    connect(ui.m_userEdit, &KLineEdit::returnPressed, this, &BugzillaLoginPage::loginClicked);
Laurent Montel's avatar
Laurent Montel committed
89
    connect(ui.m_passwordEdit->lineEdit(), &QLineEdit::returnPressed, this, &BugzillaLoginPage::loginClicked);
90

91
    connect(ui.m_userEdit, &KLineEdit::textChanged, this, &BugzillaLoginPage::updateLoginButtonStatus);
Laurent Montel's avatar
Laurent Montel committed
92
    connect(ui.m_passwordEdit, &KPasswordLineEdit::passwordChanged, this, &BugzillaLoginPage::updateLoginButtonStatus);
93
94
95
96
97
98
99
100
101

    ui.m_noticeLabel->setText(
                        xi18nc("@info/rich","<note>You need a user account on the "
                            "<link url='%1'>KDE bug tracking system</link> in order to "
                            "file a bug report, because we may need to contact you later "
                            "for requesting further information. If you do not have "
                            "one, you can freely <link url='%2'>create one here</link>. "
                            "Please do not use disposable email accounts.</note>",
                            DrKonqi::crashedApplication()->bugReportAddress(),
102
                            KDE_BUGZILLA_CREATE_ACCOUNT_URL));
103
104
105
106
107
108
109

    // Don't advertise saving credentials when we can't save them.
    // https://bugs.kde.org/show_bug.cgi?id=363570
    if (!KWallet::Wallet::isEnabled()) {
        ui.m_savePasswordCheckBox->setVisible(false);
        ui.m_savePasswordCheckBox->setCheckState(Qt::Unchecked);
    }
110
111
112
113
114
115
116
117
118
}

bool BugzillaLoginPage::isComplete()
{
    return bugzillaManager()->getLogged();
}

void BugzillaLoginPage::updateLoginButtonStatus()
{
119
    ui.m_loginButton->setEnabled(canLogin());
120
121
}

Harald Sitter's avatar
Harald Sitter committed
122
void BugzillaLoginPage::loginError(const QString &error)
123
124
125
{
    loginFinished(false);
    ui.m_statusWidget->setIdle(xi18nc("@info:status","Error when trying to login: "
Harald Sitter's avatar
Harald Sitter committed
126
                                                 "<message>%1</message>", error));
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
}

void BugzillaLoginPage::aboutToShow()
{
    if (bugzillaManager()->getLogged()) {
        ui.m_loginButton->setEnabled(false);

        ui.m_userEdit->setEnabled(false);
        ui.m_userEdit->clear();
        ui.m_passwordEdit->setEnabled(false);
        ui.m_passwordEdit->clear();

        ui.m_loginButton->setVisible(false);
        ui.m_userEdit->setVisible(false);
        ui.m_passwordEdit->setVisible(false);
        ui.m_userLabel->setVisible(false);
        ui.m_passwordLabel->setVisible(false);

        ui.m_savePasswordCheckBox->setVisible(false);

        ui.m_noticeLabel->setVisible(false);

        ui.m_statusWidget->setIdle(i18nc("@info:status the user is logged at the bugtracker site "
                                      "as USERNAME",
                                      "Logged in at the KDE bug tracking system (%1) as: %2.",
                                      QLatin1String(KDE_BUGZILLA_SHORT_URL),
                                      bugzillaManager()->getUsername()));
    } else {
155
        // Try to show wallet dialog once this dialog is shown
156
        QTimer::singleShot(100, this, &BugzillaLoginPage::walletLogin);
157
158
159
        // ...also reset focus. walletLogin may be fully no-op and not set focus
        // if it failed to do anything which leaves the focus elsewhere
        ui.m_userEdit->setFocus(Qt::OtherFocusReason);
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    }
}

bool BugzillaLoginPage::kWalletEntryExists(const QString& entryName)
{
    return !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(),
                                               KWallet::Wallet::FormDataFolder(),
                                               entryName);
}

void BugzillaLoginPage::openWallet()
{
    //Store if the wallet was previously opened so we can know if we should close it later
    m_walletWasOpenedBefore = KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet());
174

175
    //Request open the wallet
176
177
178
179
180
181
182
183
    WId windowId = 0;
    const auto *widget = qobject_cast<QWidget*>(this->parent());
    QWindow *window = widget->windowHandle();
    if (window) {
        windowId = window->winId();
    }

    m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), windowId);
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
}

void BugzillaLoginPage::walletLogin()
{
    if (!m_wallet) {
        if (kWalletEntryExists(QLatin1String(kWalletEntryName))) {  //Key exists!
            openWallet();
            ui.m_savePasswordCheckBox->setCheckState(Qt::Checked);
            //Was the wallet opened?
            if (m_wallet) {
                m_wallet->setFolder(KWallet::Wallet::FormDataFolder());

                //Use wallet data to try login
                QMap<QString, QString> values;
                m_wallet->readMap(QLatin1String(kWalletEntryName), values);
                QString username = values.value(QLatin1String(kWalletEntryUsername));
                QString password = values.value(QLatin1String(kWalletEntryPassword));

                if (!username.isEmpty() && !password.isEmpty()) {
                    ui.m_userEdit->setText(username);
Laurent Montel's avatar
Laurent Montel committed
204
                    ui.m_passwordEdit->setPassword(password);
205
206
                }
            }
207
        } else if (kWalletEntryExists(konquerorKWalletEntryName)) {
208
209
210
211
212
213
214
            //If the DrKonqi entry is empty, but a Konqueror entry exists, use and copy it.
            openWallet();
            if (m_wallet) {
                m_wallet->setFolder(KWallet::Wallet::FormDataFolder());

                //Fetch Konqueror data
                QMap<QString, QString> values;
215
                m_wallet->readMap(konquerorKWalletEntryName, values);
216
217
218
219
220
221
222
223
224
225
226
227
228
                QString username = values.value(QLatin1String(konquerorKWalletEntryUsername));
                QString password = values.value(QLatin1String(konquerorKWalletEntryPassword));

                if (!username.isEmpty() && !password.isEmpty()) {
                    //Copy to DrKonqi own entries
                    values.clear();
                    values.insert(QLatin1String(kWalletEntryUsername), username);
                    values.insert(QLatin1String(kWalletEntryPassword), password);
                    m_wallet->writeMap(QLatin1String(kWalletEntryName), values);

                    ui.m_savePasswordCheckBox->setCheckState(Qt::Checked);

                    ui.m_userEdit->setText(username);
Laurent Montel's avatar
Laurent Montel committed
229
                    ui.m_passwordEdit->setPassword(password);
230
231
232
233
                }
            }

        }
234
235
236
237

        if (canLogin()) {
            loginClicked();
        }
238
239
240
241
242
    }
}

void BugzillaLoginPage::loginClicked()
{
243
244
245
246
    if (!canLogin()) {
        loginFinished(false);
        return;
    }
247

248
    updateWidget(false);
249

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
    if (ui.m_savePasswordCheckBox->checkState()==Qt::Checked) { //Wants to save data
        if (!m_wallet) {
            openWallet();
        }
        //Got wallet open ?
        if (m_wallet) {
            m_wallet->setFolder(KWallet::Wallet::FormDataFolder());

            QMap<QString, QString> values;
            values.insert(QLatin1String(kWalletEntryUsername), ui.m_userEdit->text());
            values.insert(QLatin1String(kWalletEntryPassword), ui.m_passwordEdit->password());
            m_wallet->writeMap(QLatin1String(kWalletEntryName), values);
        }
    } else { //User doesn't want to save or wants to remove.
        if (kWalletEntryExists(QLatin1String(kWalletEntryName))) {
265
266
267
268
269
270
            if (!m_wallet) {
                openWallet();
            }
            //Got wallet open ?
            if (m_wallet) {
                m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
271
                m_wallet->removeEntry(QLatin1String(kWalletEntryName));
272
273
274
275
            }
        }
    }

276
    login();
277
278
}

279
280
bool BugzillaLoginPage::canLogin() const
{
281
282
    return (!(ui.m_userEdit->text().isEmpty() ||
              ui.m_passwordEdit->password().isEmpty()));
283
284
285
286
287
288
}

void BugzillaLoginPage::login()
{
    Q_ASSERT(canLogin());

289
    ui.m_statusWidget->setBusy(i18nc("@info:status '1' is a url, '2' the e-mail address",
290
291
292
293
294
                                     "Performing login at %1 as %2...",
                                     QLatin1String(KDE_BUGZILLA_SHORT_URL),
                                     ui.m_userEdit->text()));

    bugzillaManager()->tryLogin(ui.m_userEdit->text(), ui.m_passwordEdit->password());
295
296
}

Laurent Montel's avatar
Laurent Montel committed
297
298
299
300
301
302
303
304
305
306
307
308
void BugzillaLoginPage::updateWidget(bool enabled)
{
    ui.m_loginButton->setEnabled(enabled);

    ui.m_userLabel->setEnabled(enabled);
    ui.m_passwordLabel->setEnabled(enabled);

    ui.m_userEdit->setEnabled(enabled);
    ui.m_passwordEdit->setEnabled(enabled);
    ui.m_savePasswordCheckBox->setEnabled(enabled);
}

309
310
311
312
313
314
315
316
317
318
319
320
321
322
void BugzillaLoginPage::loginFinished(bool logged)
{
    if (logged) {
        emitCompleteChanged();

        aboutToShow();
        if (m_wallet) {
            if (m_wallet->isOpen() && !m_walletWasOpenedBefore) {
                m_wallet->lockWallet();
            }
        }

        emit loggedTurnToNextPage();
    } else {
323
324
        ui.m_statusWidget->setIdle(i18nc("@info:status",
                                         "<b>Error: Invalid e-mail address or password</b>"));
Laurent Montel's avatar
Laurent Montel committed
325
        updateWidget(true);
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
        ui.m_userEdit->setFocus(Qt::OtherFocusReason);
    }
}

BugzillaLoginPage::~BugzillaLoginPage()
{
    //Close wallet if we close the assistant in this step
    if (m_wallet) {
        if (m_wallet->isOpen() && !m_walletWasOpenedBefore) {
            m_wallet->lockWallet();
        }
        delete m_wallet;
    }
}

//END BugzillaLoginPage

//BEGIN BugzillaInformationPage

BugzillaInformationPage::BugzillaInformationPage(ReportAssistantDialog * parent)
346
347
348
        : ReportAssistantPage(parent)
        , m_textsOK(false)
        , m_requiredCharacters(1)
349
350
{
    ui.setupUi(this);
351

352
353
354
    m_textCompleteBar = new KCapacityBar(KCapacityBar::DrawTextInline, this);
    ui.horizontalLayout_2->addWidget(m_textCompleteBar);

355
356
    connect(ui.m_titleEdit, &KLineEdit::textChanged, this, &BugzillaInformationPage::checkTexts);
    connect(ui.m_detailsEdit, &QTextEdit::textChanged, this, &BugzillaInformationPage::checkTexts);
357

358
359
    connect(ui.m_titleLabel, &QLabel::linkActivated, this, &BugzillaInformationPage::showTitleExamples);
    connect(ui.m_detailsLabel, &QLabel::linkActivated, this, &BugzillaInformationPage::showDescriptionHelpExamples);
360

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
    ui.m_compiledSourcesCheckBox->setChecked(DrKonqi::systemInformation()->compiledSources());

    ui.m_messageWidget->setVisible(false);
    auto retryAction = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")),
                                   i18nc("@action/button retry button in error widget",
                                         "Retry"),
                                   ui.m_messageWidget);
    connect(retryAction, &QAction::triggered,
            this, [this, retryAction]{
        ui.m_messageWidget->animatedHide();
        loadDistroCombo();
    });
    ui.m_messageWidget->addAction(retryAction);

    loadDistroCombo();
376
377
378
379
380
381
382
383
384
385
386
387
388
389
}

void BugzillaInformationPage::aboutToShow()
{
    //Calculate the minimum number of characters required for a description
    //If creating a new report: minimum 40, maximum 80
    //If attaching to an existent report: minimum 30, maximum 50
    int multiplier = (reportInterface()->attachToBugNumber() == 0) ? 10 : 5;
    m_requiredCharacters = 20 + (reportInterface()->selectedOptionsRating() * multiplier);

    //Fill the description textedit with some headings:
    QString descriptionTemplate;
    if (ui.m_detailsEdit->toPlainText().isEmpty()) {
        if (reportInterface()->userCanProvideActionsAppDesktop()) {
390
            descriptionTemplate += QLatin1String("- What I was doing when the application crashed:\n\n");
391
392
        }
        if (reportInterface()->userCanProvideUnusualBehavior()) {
393
            descriptionTemplate += QLatin1String("- Unusual behavior I noticed:\n\n");
394
395
        }
        if (reportInterface()->userCanProvideApplicationConfigDetails()) {
396
            descriptionTemplate += QLatin1String("- Custom settings of the application:\n\n");
397
398
399
400
401
402
403
404
405
406
407
408
        }
        ui.m_detailsEdit->setText(descriptionTemplate);
    }

    checkTexts(); //May be the options (canDetail) changed and we need to recheck
}

int BugzillaInformationPage::currentDescriptionCharactersCount()
{
    QString description = ui.m_detailsEdit->toPlainText();

    //Do not count template messages, and other misc chars
409
410
411
    description.remove(QStringLiteral("What I was doing when the application crashed"));
    description.remove(QStringLiteral("Unusual behavior I noticed"));
    description.remove(QStringLiteral("Custom settings of the application"));
Laurent Montel's avatar
Laurent Montel committed
412
413
414
415
    description.remove(QLatin1Char('\n'));
    description.remove(QLatin1Char('-'));
    description.remove(QLatin1Char(':'));
    description.remove(QLatin1Char(' '));
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448

    return description.size();
}

void BugzillaInformationPage::checkTexts()
{
    //If attaching this report to an existing one then the title is not needed
    bool showTitle = (reportInterface()->attachToBugNumber() == 0);
    ui.m_titleEdit->setVisible(showTitle);
    ui.m_titleLabel->setVisible(showTitle);

    bool ok = !((ui.m_titleEdit->isVisible() && ui.m_titleEdit->text().isEmpty())
        || ui.m_detailsEdit->toPlainText().isEmpty());

    QString message;
    int percent = currentDescriptionCharactersCount() * 100 / m_requiredCharacters;
    if (percent >= 100) {
        percent = 100;
        message = i18nc("the minimum required length of a text was reached",
                        "Minimum length reached");
    } else {
        message = i18nc("the minimum required length of a text wasn't reached yet",
                        "Provide more information");
    }
    m_textCompleteBar->setValue(percent);
    m_textCompleteBar->setText(message);

    if (ok != m_textsOK) {
        m_textsOK = ok;
        emitCompleteChanged();
    }
}

449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
void BugzillaInformationPage::loadDistroCombo()
{
    // Alway have at least unspecified otherwise bugzilla would get to decide
    // the platform and that would likely be index=0 which is compiledfromsource
    ui.m_distroChooserCombo->addItem(QStringLiteral("unspecified"));

    Bugzilla::BugFieldClient client;
    auto job = client.getField(QStringLiteral("rep_platform"));
    connect(job, &KJob::finished, this, [this, &client](KJob *job) {
        try {
            Bugzilla::BugField::Ptr field = client.getField(job);
            if (!field) {
                // This is a bit flimsy but only acts as save guard.
                // Ideally this code path is never hit.
                throw Bugzilla::RuntimeException(i18nc("@info/status error",
                                                       "Failed to get platform list"));
            }
            setDistros(field);
        } catch (Bugzilla::Exception &e) {
            qCWarning(DRKONQI_LOG) << e.whatString();
            setDistroComboError(e.whatString());
        }
    });
}

void BugzillaInformationPage::setDistros(const Bugzilla::BugField::Ptr &field)
{
    ui.m_distroChooserCombo->clear();
    for (const auto &distro : field->values()) {
        ui.m_distroChooserCombo->addItem(distro->name());
    }

    int index = 0;
    bool autoDetected = false;

    const QString detectedPlatform = DrKonqi::systemInformation()->bugzillaPlatform();
    if (detectedPlatform != QLatin1String("unspecified")) {
        index = ui.m_distroChooserCombo->findText(detectedPlatform);
        if (index >= 0) {
            autoDetected = true;
        }
    } else {
        // Restore previously selected bugzilla platform (distribution)
        KConfigGroup config(KSharedConfig::openConfig(), "BugzillaInformationPage");
        const QString entry = config.readEntry("BugzillaPlatform", "unspecified");
        index = ui.m_distroChooserCombo->findText(entry);
    }

    if (index < 0) { // failed to restore value
        index = ui.m_distroChooserCombo->findText(QStringLiteral("unspecified"));
    }
    if (index < 0) { // also failed to find unspecified... shouldn't happen
        index = 0;
    }

    ui.m_distroChooserCombo->setCurrentIndex(index);
    ui.m_distroChooserCombo->setVisible(autoDetected);
    ui.m_distroChooserCombo->setDisabled(false);
}

void BugzillaInformationPage::setDistroComboError(const QString &error)
{
    // NB: not being able to resolve the platform isn't a blocking issue.
    // You can still file a report, it'll simply default to unspecified.

    ui.m_messageWidget->setText(i18nc("@info error when talking to the bugzilla API",
Yuri Chornoivan's avatar
Yuri Chornoivan committed
515
                                      "An error occurred when talking to bugs.kde.org: %1",
516
517
518
519
520
521
522
                                      error));
    ui.m_messageWidget->animatedShow();

    ui.m_distroChooserCombo->setVisible(true);
    ui.m_distroChooserCombo->setDisabled(true);
}

523
524
525
526
527
528
529
530
531
532
533
534
bool BugzillaInformationPage::showNextPage()
{
    checkTexts();

    if (m_textsOK) {
        bool detailsShort = currentDescriptionCharactersCount() < m_requiredCharacters;

        if (detailsShort) {
            //The user input is less than we want.... encourage to write more
            QString message = i18nc("@info","The description about the crash details does not provide "
                                        "enough information yet.<br /><br />");

Laurent Montel's avatar
Laurent Montel committed
535
            message += QLatin1Char(' ') + i18nc("@info","The amount of required information is proportional to "
536
537
538
539
540
541
542
                                        "the quality of the other information like the backtrace "
                                        "or the reproducibility rate."
                                        "<br /><br />");

            if (reportInterface()->userCanProvideActionsAppDesktop()
                || reportInterface()->userCanProvideUnusualBehavior()
                || reportInterface()->userCanProvideApplicationConfigDetails()) {
Laurent Montel's avatar
Laurent Montel committed
543
                message += QLatin1Char(' ') + i18nc("@info","Previously, you told DrKonqi that you could provide some "
544
545
546
547
                                        "contextual information. Try writing more details about your situation. "
                                        "(even little ones could help us.)<br /><br />");
            }

Laurent Montel's avatar
Laurent Montel committed
548
            message += QLatin1Char(' ') + i18nc("@info","If you cannot provide more information, your report "
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
                                    "will probably waste developers' time. Can you tell us more?");

            KGuiItem yesItem = KStandardGuiItem::yes();
            yesItem.setText(i18n("Yes, let me add more information"));

            KGuiItem noItem = KStandardGuiItem::no();
            noItem.setText(i18n("No, I cannot add any other information"));

            if (KMessageBox::warningYesNo(this, message,
                                           i18nc("@title:window","We need more information"),
                                           yesItem, noItem)
                                            == KMessageBox::No) {
                //Request the assistant to close itself (it will prompt for confirmation anyways)
                assistant()->close();
                return false;
            }
        } else {
            return true;
        }
    }

    return false;
}

bool BugzillaInformationPage::isComplete()
{
    return m_textsOK;
}

void BugzillaInformationPage::aboutToHide()
{
    //Save fields data
    reportInterface()->setTitle(ui.m_titleEdit->text());
    reportInterface()->setDetailText(ui.m_detailsEdit->toPlainText());

584
    if (ui.m_distroChooserCombo->isVisible()) {
585
586
587
588
589
590
591
592
593
594
595
596
597
        //Save bugzilla platform (distribution)
        QString bugzillaPlatform = ui.m_distroChooserCombo->itemData(
                                        ui.m_distroChooserCombo->currentIndex()).toString();
        KConfigGroup config(KSharedConfig::openConfig(), "BugzillaInformationPage");
        config.writeEntry("BugzillaPlatform", bugzillaPlatform);
        DrKonqi::systemInformation()->setBugzillaPlatform(bugzillaPlatform);
    }
    bool compiledFromSources = ui.m_compiledSourcesCheckBox->checkState() == Qt::Checked;
    DrKonqi::systemInformation()->setCompiledSources(compiledFromSources);
}

void BugzillaInformationPage::showTitleExamples()
{
Laurent Montel's avatar
Laurent Montel committed
598
    QString titleExamples = xi18nc("@info:tooltip examples of good bug report titles",
599
600
601
602
603
604
605
606
607
608
609
610
611
          "<strong>Examples of good titles:</strong><nl />\"Plasma crashed after adding the Notes "
          "widget and writing on it\"<nl />\"Konqueror crashed when accessing the Facebook "
          "application 'X'\"<nl />\"Kopete suddenly closed after resuming the computer and "
          "talking to a MSN buddy\"<nl />\"Kate closed while editing a log file and pressing the "
          "Delete key a couple of times\"");
    QToolTip::showText(QCursor::pos(), titleExamples);
}

void BugzillaInformationPage::showDescriptionHelpExamples()
{
    QString descriptionHelp = i18nc("@info:tooltip help and examples of good bug descriptions",
                                  "Describe in as much detail as possible the crash circumstances:");
    if (reportInterface()->userCanProvideActionsAppDesktop()) {
612
        descriptionHelp += QLatin1String("<br />") +
613
614
615
616
617
                           i18nc("@info:tooltip help and examples of good bug descriptions",
                                 "- Detail which actions were you taking inside and outside the "
                                 "application an instant before the crash.");
    }
    if (reportInterface()->userCanProvideUnusualBehavior()) {
618
        descriptionHelp += QLatin1String("<br />") +
619
620
621
622
623
                           i18nc("@info:tooltip help and examples of good bug descriptions",
                                 "- Note if you noticed any unusual behavior in the application "
                                 "or in the whole environment.");
    }
    if (reportInterface()->userCanProvideApplicationConfigDetails()) {
624
        descriptionHelp += QLatin1String("<br />") +
625
626
627
                           i18nc("@info:tooltip help and examples of good bug descriptions",
                                 "- Note any non-default configuration in the application.");
        if (reportInterface()->appDetailsExamples()->hasExamples()) {
Laurent Montel's avatar
Laurent Montel committed
628
            descriptionHelp += QLatin1Char(' ') +
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
                               i18nc("@info:tooltip examples of configuration details. "
                                     "the examples are already translated",
                                     "Examples: %1",
                                     reportInterface()->appDetailsExamples()->examples());
        }
    }
    QToolTip::showText(QCursor::pos(), descriptionHelp);
}

//END BugzillaInformationPage

//BEGIN BugzillaPreviewPage

BugzillaPreviewPage::BugzillaPreviewPage(ReportAssistantDialog * parent)
        : ReportAssistantPage(parent)
{
    ui.setupUi(this);
}

void BugzillaPreviewPage::aboutToShow()
{
650
651
    ui.m_previewEdit->setText(reportInterface()->generateReportFullText(ReportInterface::DrKonqiStamp::Include,
                                                                        ReportInterface::Backtrace::Complete));
652
653
654
655
656
657
    assistant()->setAboutToSend(true);
}

void BugzillaPreviewPage::aboutToHide()
{
    assistant()->setAboutToSend(false);
658
659
660
661
662
663
664
665
}

//END BugzillaPreviewPage

//BEGIN BugzillaSendPage

BugzillaSendPage::BugzillaSendPage(ReportAssistantDialog * parent)
        : ReportAssistantPage(parent),
666
        m_contentsDialog(nullptr)
667
{
668
669
    connect(reportInterface(), &ReportInterface::reportSent, this, &BugzillaSendPage::sent);
    connect(reportInterface(), &ReportInterface::sendReportError, this, &BugzillaSendPage::sendError);
670
671
672
673

    ui.setupUi(this);

    KGuiItem::assign(ui.m_retryButton, KGuiItem2(i18nc("@action:button", "Retry..."),
674
                                              QIcon::fromTheme(QStringLiteral("view-refresh")),
675
676
677
678
679
                                              i18nc("@info:tooltip", "Use this button to retry "
                                                  "sending the crash report if it failed before.")));

    KGuiItem::assign(ui.m_showReportContentsButton,
                    KGuiItem2(i18nc("@action:button", "Sho&w Contents of the Report"),
680
                            QIcon::fromTheme(QStringLiteral("document-preview")),
681
682
                            i18nc("@info:tooltip", "Use this button to show the generated "
                            "report information about this crash.")));
683
    connect(ui.m_showReportContentsButton, &QPushButton::clicked, this, &BugzillaSendPage::openReportContents);
684
685

    ui.m_retryButton->setVisible(false);
686
    connect(ui.m_retryButton, &QAbstractButton::clicked, this , &BugzillaSendPage::retryClicked);
687
688
689
690

    ui.m_launchPageOnFinish->setVisible(false);
    ui.m_restartAppOnFinish->setVisible(false);

Laurent Montel's avatar
Laurent Montel committed
691
    connect(assistant()->finishButton(), &QPushButton::clicked, this, &BugzillaSendPage::finishClicked);
692
693
694
695
696
697
698
699
700
701
702
}

void BugzillaSendPage::retryClicked()
{
    ui.m_retryButton->setEnabled(false);
    aboutToShow();
}

void BugzillaSendPage::aboutToShow()
{
    ui.m_statusWidget->setBusy(i18nc("@info:status","Sending crash report... (please wait)"));
703
704
705
706
707
708
709
710
711
712
713
714
715
716

    // Trigger relogin. If the user took a long time to prepare the login our
    // token might have gone invalid in the meantime. As a cheap way to prevent
    // this we'll simply refresh the token regardless. It's plenty cheap and
    // should reliably ensure that the token is current.
    // Disconnect everything first though, this function may get called a bunch
    // of times, so we don't want duplicated submissions.
    disconnect(bugzillaManager(), &BugzillaManager::loginFinished,
               reportInterface(), &ReportInterface::sendBugReport);
    disconnect(bugzillaManager(), &BugzillaManager::loginError,
               this, nullptr);
    connect(bugzillaManager(), &BugzillaManager::loginFinished,
            reportInterface(), &ReportInterface::sendBugReport);
    connect(bugzillaManager(), &BugzillaManager::loginError,
Harald Sitter's avatar
Harald Sitter committed
717
            this, &BugzillaSendPage::sendError);
718
    bugzillaManager()->refreshToken();
719
720
721
722
}

void BugzillaSendPage::sent(int bug_id)
{
723
724
725
726
727
728
    // Disconnect login->submit chain again.
    disconnect(bugzillaManager(), &BugzillaManager::loginFinished,
               reportInterface(), &ReportInterface::sendBugReport);
    disconnect(bugzillaManager(), &BugzillaManager::loginError,
               this, nullptr);

729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
    ui.m_statusWidget->setVisible(false);
    ui.m_retryButton->setEnabled(false);
    ui.m_retryButton->setVisible(false);

    ui.m_showReportContentsButton->setVisible(false);

    ui.m_launchPageOnFinish->setVisible(true);
    ui.m_restartAppOnFinish->setVisible(!DrKonqi::crashedApplication()->hasBeenRestarted());
    ui.m_restartAppOnFinish->setChecked(false);

    reportUrl = bugzillaManager()->urlForBug(bug_id);
    ui.m_finishedLabel->setText(xi18nc("@info/rich","Crash report sent.<nl/>"
                                             "URL: <link>%1</link><nl/>"
                                             "Thank you for being part of KDE. "
                                             "You can now close this window.", reportUrl));

    emit finished(false);
}

Harald Sitter's avatar
Harald Sitter committed
748
void BugzillaSendPage::sendError(const QString &errorString)
749
750
751
752
753
754
755
756
757
758
759
{
    ui.m_statusWidget->setIdle(xi18nc("@info:status","Error sending the crash report:  "
                                  "<message>%1.</message>", errorString));

    ui.m_retryButton->setEnabled(true);
    ui.m_retryButton->setVisible(true);
}

void BugzillaSendPage::finishClicked()
{
    if (ui.m_launchPageOnFinish->isChecked() && !reportUrl.isEmpty()) {
David Edmundson's avatar
David Edmundson committed
760
        QDesktopServices::openUrl(QUrl(reportUrl));
761
762
763
764
765
766
767
768
769
770
    }
    if (ui.m_restartAppOnFinish->isChecked()) {
        DrKonqi::crashedApplication()->restart();
    }
}

void BugzillaSendPage::openReportContents()
{
    if (!m_contentsDialog)
    {
771
772
        QString report = reportInterface()->generateReportFullText(ReportInterface::DrKonqiStamp::Exclude,
                                                                   ReportInterface::Backtrace::Complete) + QLatin1Char('\n') +
773
                            i18nc("@info report to KDE bugtracker address","Report to %1",
774
775
776
777
778
779
780
781
782
                                  DrKonqi::crashedApplication()->bugReportAddress());
        m_contentsDialog = new ReportInformationDialog(report);
    }
    m_contentsDialog->show();
    m_contentsDialog->raise();
    m_contentsDialog->activateWindow();
}

//END BugzillaSendPage