<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    dialogs/signcertificatedialog.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2008 Klarälvdalens Datakonsult AB

    Kleopatra 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.

    Kleopatra 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, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "certifycertificatedialog.h"
#include "certifycertificatedialog_p.h"

#include <utils/formatting.h>

#include <KDebug>
#include <KLocalizedString>

#include <QGridLayout>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QListView>
#include <QListWidgetItem>
#include <QVBoxLayout>
#include <QWizardPage>

#include <QTextDocument> // Qt::escape

#include <cassert>

using namespace boost;
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace Kleo::Dialogs::CertifyCertificateDialogPrivate;

void UserIDModel::setCertificateToCertify( const Key & key ) {
    m_key = key;
    clear();
    const std::vector<UserID> ids = key.userIDs();
    for ( unsigned int i = 0; i < ids.size(); ++i ) {
        QStandardItem * const item = new QStandardItem;
        item->setText( Formatting::prettyUserID( key.userID( i ) ) );
        item->setData( i, UserIDIndex );
        item->setCheckable( true );
        item->setEditable( false );
        appendRow( item );
    }
}

std::vector<unsigned int> UserIDModel::checkedUserIDs() const {
    std::vector<unsigned int> ids;
    for ( int i = 0; i < rowCount(); ++i )
        if ( item( i )->checkState() == Qt::Checked )
            ids.push_back( item( i )->data( UserIDIndex ).toUInt() );
    return ids;
}

void SecretKeysModel::setSecretKeys( const std::vector<Key> & keys ) {
    clear();
    m_secretKeys = keys;
    for ( unsigned int i = 0; i < m_secretKeys.size(); ++i ) {
        const Key key = m_secretKeys[i];
        QStandardItem * const item = new QStandardItem;
        item->setText( Formatting::prettyNameAndEMail( key ) );
        item->setData( i, IndexRole );
        item->setEditable( false );
        appendRow( item );
    }
}

Key SecretKeysModel::keyFromItem( const QStandardItem * item ) const {
    assert( item );
    const unsigned int idx = item->data( IndexRole ).toUInt();
    assert( idx < m_secretKeys.size() );
    return m_secretKeys[idx];
}

Key SecretKeysModel::keyFromIndex( const QModelIndex & idx ) const {
    return keyFromItem( itemFromIndex( idx ) );
}

SelectUserIDsPage::SelectUserIDsPage( QWidget * parent ) : QWizardPage( parent ), m_userIDModel() {
    QVBoxLayout * const layout = new QVBoxLayout ( this );
    QLabel * const label = new QLabel;
    label->setText( i18n( "Step 1: Please select the user IDs you wish to certify." ) );
    m_listView = new QListView;
    m_listView->setModel( &m_userIDModel );
    connect( &m_userIDModel, SIGNAL(itemChanged(QStandardItem*)), this, SIGNAL(completeChanged()) );
    layout->addWidget( m_listView );
}

bool SelectUserIDsPage::isComplete() const {
    return !selectedUserIDs().empty();
}

std::vector<unsigned int> SelectUserIDsPage::selectedUserIDs() const {
    return m_userIDModel.checkedUserIDs();
}

void SelectUserIDsPage::setCertificateToCertify( const Key & key ) {
    m_userIDModel.setCertificateToCertify( key );

}

SelectCheckLevelPage::SelectCheckLevelPage( QWidget * parent ) : QWizardPage( parent ), m_ui() {
    m_ui.setupUi( this );
}

unsigned int SelectCheckLevelPage::checkLevel() const {
    if ( m_ui.checkLevelNotCheckedRB->isChecked() )
        return 1;
    if ( m_ui.checkLevelCasualRB->isChecked() )
        return 2;
    if ( m_ui.checkLevelThoroughlyRB->isChecked() )
        return 3;
    assert( !"No check level radiobutton checked" );
    return 0;
}

OptionsPage::OptionsPage( QWidget * parent ) : QWizardPage( parent ), m_ui() {
    m_ui.setupUi( this );
    m_ui.keyListView->setModel( &m_model );
    connect( m_ui.keyListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(completeChanged()) );
    setCommitPage( true );
    setButtonText( QWizard::CommitButton, i18n( "Certify" ) );
}

bool OptionsPage::exportableCertificationSelected() const {
    return m_ui.exportableSignatureRB->isChecked();
}

void OptionsPage::setCertificatesWithSecretKeys( const std::vector<Key> & keys ) {
    assert( !keys.empty() );
    m_model.setSecretKeys( keys );
    if ( keys.size() == 1 ) {
        m_ui.stackedWidget->setCurrentWidget( m_ui.singleKeyPage );
        m_ui.singleKeyLabel->setText( i18n( "Certification will be performed using certificate %1.", Formatting::prettyNameAndEMail( keys[0] ) ) );
    } else {
        m_ui.stackedWidget->setCurrentWidget( m_ui.multipleKeysPage );
    }
    emit completeChanged();
}

Key OptionsPage::selectedSecretKey() const {
    const QModelIndexList idxs = m_ui.keyListView->selectionModel()->selectedIndexes();
    assert( idxs.size() <= 1 );
    return idxs.isEmpty() ? Key() : m_model.keyFromIndex( idxs[0] );
}

bool OptionsPage::sendToServer() const {
    return m_ui.sendToServerCB->isChecked();
}

bool OptionsPage::validatePage() {
    emit nextClicked();
    return true;
}

bool OptionsPage::isComplete() const {
    return !selectedSecretKey().isNull();
}

SummaryPage::SummaryPage( QWidget * parent ) : QWizardPage( parent ), m_complete( false ) {
    QGridLayout * const layout = new QGridLayout( this );
    QLabel * const uidLabelLabel = new QLabel( i18n( "Signed user IDs:" ) );
    uidLabelLabel->setAlignment( Qt::AlignTop );
    layout->addWidget( uidLabelLabel, 0, 0 );
    layout->addWidget( m_userIDsLabel = new QLabel, 0, 1 );
    layout->addWidget( new QLabel( i18n( "Check level:"  )), 1, 0 );
    layout->addWidget( m_checkLevelLabel = new QLabel, 1, 1 );
    layout->addWidget( new QLabel( i18n( "Selected secret certificate:" ) ), 2, 0 );
    layout->addWidget( m_secretKeyLabel = new QLabel, 2, 1 );
    m_secretKeyLabel->setTextFormat( Qt::PlainText );
    layout->addWidget( m_resultLabel = new QLabel, 3, 0, 2, 1 );
}

bool SummaryPage::isComplete() const {
    return m_complete;
}

void SummaryPage::setSummary( const SummaryPage::Summary & sum ) {
    const Key key = sum.certificateToCertify;
    QStringList ids;
    Q_FOREACH ( const unsigned int i, sum.selectedUserIDs )
        ids += Qt::escape( Formatting::prettyUserID( key.userID( i ) ) );
    m_userIDsLabel->setText( "<qt>" + ids.join( "
" ) + "</qt>" );
    m_secretKeyLabel->setText( sum.secretKey.isNull() ? i18n( "Default certificate" ) : Formatting::prettyNameAndEMail( sum.secretKey ) );
    switch( sum.checkLevel ) {
        case 0:
            m_checkLevelLabel->setText( i18n( "No statement made" ) );
            break;
        case 1:
            m_checkLevelLabel->setText( i18n( "Not checked" ) );
            break;
        case 2:
            m_checkLevelLabel->setText( i18n( "Casually checked" ) );
            break;
        case 3:
            m_checkLevelLabel->setText( i18n( "Thoroughly checked" ) );
            break;
    }
}

void SummaryPage::setComplete( bool complete ) {
    if ( complete == m_complete )
        return;
    m_complete = complete;
    emit completeChanged();
}
void SummaryPage::setResult( const Error & err ) {
    if ( err && !err.isCanceled() )
        m_resultLabel->setText( i18n( "Error: %1", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ) );
    else if ( err.isCanceled() )
        m_resultLabel->setText( "Certification canceled." );
    else
        m_resultLabel->setText("Certification finished." );
}

class CertifyCertificateDialog::Private {
    friend class ::Kleo::Dialogs::CertifyCertificateDialog;
    CertifyCertificateDialog * const q;

public:
    explicit Private( CertifyCertificateDialog * qq )
        : q( qq ),
        summaryPageId( 0 ),
        selectUserIDsPage( 0 ),
        selectCheckLevelPage( 0 ),
        optionsPage( 0 ),
        summaryPage( 0 )
    {
        selectUserIDsPage = new SelectUserIDsPage( q );
        q->addPage( selectUserIDsPage );
        selectCheckLevelPage = new SelectCheckLevelPage( q );
        q->addPage( selectCheckLevelPage );
        optionsPage = new OptionsPage( q );
        q->addPage( optionsPage );
        summaryPage = new SummaryPage( q );
        summaryPageId = q->addPage( summaryPage );
        connect( optionsPage, SIGNAL(nextClicked()), q, SIGNAL(certificationPrepared()) );
    }

    void ensureSummaryPageVisible();

    void certificationResult( const Error & error );

    void setOperationCompleted() {
        summaryPage->setComplete( true );
    }

    SummaryPage::Summary createSummary() const {
        SummaryPage::Summary sum;
        sum.selectedUserIDs = selectUserIDsPage->selectedUserIDs();
        sum.secretKey = optionsPage->selectedSecretKey();
        sum.certificateToCertify = selectUserIDsPage->certificateToCertify();
        sum.checkLevel = selectCheckLevelPage->checkLevel();
        sum.exportable = optionsPage->exportableCertificationSelected();
        sum.sendToServer = optionsPage->sendToServer();
        return sum;
    }

    int summaryPageId;
    SelectUserIDsPage * selectUserIDsPage;
    SelectCheckLevelPage * selectCheckLevelPage;
    OptionsPage * optionsPage;
    SummaryPage * summaryPage;
};

CertifyCertificateDialog::CertifyCertificateDialog( QWidget * p, Qt::WindowFlags f )
    : QWizard( p, f ), d( new Private( this ) )
{
}

CertifyCertificateDialog::~CertifyCertificateDialog() {}

void CertifyCertificateDialog::setCertificateToCertify( const Key & key ) {
    setWindowTitle( i18nc( "arg is name, email of certificate holder", "Certify Certificate: %1", Formatting::prettyName( key ) ) );
    d->selectUserIDsPage->setCertificateToCertify( key );
}

void CertifyCertificateDialog::setCertificatesWithSecretKeys( const std::vector<Key> & keys ) {
    d->optionsPage->setCertificatesWithSecretKeys( keys );
}

bool CertifyCertificateDialog::exportableCertificationSelected() const {
    return d->optionsPage->exportableCertificationSelected();
}

bool CertifyCertificateDialog::trustCertificationSelected() const {
    return false;
}

bool CertifyCertificateDialog::nonRevocableCertificationSelected() const {
    return false;
}

Key CertifyCertificateDialog::selectedSecretKey() const {
    return d->optionsPage->selectedSecretKey();
}

bool CertifyCertificateDialog::sendToServer() const {
    return d->optionsPage->sendToServer();
}

unsigned int CertifyCertificateDialog::selectedCheckLevel() const {
    return d->selectCheckLevelPage->checkLevel();
}

void CertifyCertificateDialog::connectJob( SignKeyJob * job ) {
    connect( job, SIGNAL(result(GpgME::Error)), this, SLOT(certificationResult(GpgME::Error)) );
    d->summaryPage->setSummary( d->createSummary() );
}

void CertifyCertificateDialog::setError( const Error & error ) {
    d->setOperationCompleted();
    d->summaryPage->setResult( error );
    d->ensureSummaryPageVisible();
    if ( error.isCanceled() )
        close();
}

void CertifyCertificateDialog::Private::certificationResult( const Error & err ) {
    setOperationCompleted();
    summaryPage->setResult( err );
    ensureSummaryPageVisible();
}

std::vector<unsigned int> CertifyCertificateDialog::selectedUserIDs() const {
    return d->selectUserIDsPage->selectedUserIDs();
}

void CertifyCertificateDialog::Private::ensureSummaryPageVisible() {
    while ( q->currentId() != summaryPageId )
        q->next();
}

#include "moc_certifycertificatedialog.cpp"
#include "moc_certifycertificatedialog_p.cpp"
<commit_msg>add label to layout<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    dialogs/signcertificatedialog.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2008 Klarälvdalens Datakonsult AB

    Kleopatra 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.

    Kleopatra 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, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "certifycertificatedialog.h"
#include "certifycertificatedialog_p.h"

#include <utils/formatting.h>

#include <KDebug>
#include <KLocalizedString>

#include <QGridLayout>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QListView>
#include <QListWidgetItem>
#include <QVBoxLayout>
#include <QWizardPage>

#include <QTextDocument> // Qt::escape

#include <cassert>

using namespace boost;
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace Kleo::Dialogs::CertifyCertificateDialogPrivate;

void UserIDModel::setCertificateToCertify( const Key & key ) {
    m_key = key;
    clear();
    const std::vector<UserID> ids = key.userIDs();
    for ( unsigned int i = 0; i < ids.size(); ++i ) {
        QStandardItem * const item = new QStandardItem;
        item->setText( Formatting::prettyUserID( key.userID( i ) ) );
        item->setData( i, UserIDIndex );
        item->setCheckable( true );
        item->setEditable( false );
        appendRow( item );
    }
}

std::vector<unsigned int> UserIDModel::checkedUserIDs() const {
    std::vector<unsigned int> ids;
    for ( int i = 0; i < rowCount(); ++i )
        if ( item( i )->checkState() == Qt::Checked )
            ids.push_back( item( i )->data( UserIDIndex ).toUInt() );
    return ids;
}

void SecretKeysModel::setSecretKeys( const std::vector<Key> & keys ) {
    clear();
    m_secretKeys = keys;
    for ( unsigned int i = 0; i < m_secretKeys.size(); ++i ) {
        const Key key = m_secretKeys[i];
        QStandardItem * const item = new QStandardItem;
        item->setText( Formatting::prettyNameAndEMail( key ) );
        item->setData( i, IndexRole );
        item->setEditable( false );
        appendRow( item );
    }
}

Key SecretKeysModel::keyFromItem( const QStandardItem * item ) const {
    assert( item );
    const unsigned int idx = item->data( IndexRole ).toUInt();
    assert( idx < m_secretKeys.size() );
    return m_secretKeys[idx];
}

Key SecretKeysModel::keyFromIndex( const QModelIndex & idx ) const {
    return keyFromItem( itemFromIndex( idx ) );
}

SelectUserIDsPage::SelectUserIDsPage( QWidget * parent ) : QWizardPage( parent ), m_userIDModel() {
    QVBoxLayout * const layout = new QVBoxLayout ( this );
    QLabel * const label = new QLabel;
    label->setText( i18n( "Step 1: Please select the user IDs you wish to certify." ) );
    layout->addWidget( label );
    m_listView = new QListView;
    m_listView->setModel( &m_userIDModel );
    connect( &m_userIDModel, SIGNAL(itemChanged(QStandardItem*)), this, SIGNAL(completeChanged()) );
    layout->addWidget( m_listView );
}

bool SelectUserIDsPage::isComplete() const {
    return !selectedUserIDs().empty();
}

std::vector<unsigned int> SelectUserIDsPage::selectedUserIDs() const {
    return m_userIDModel.checkedUserIDs();
}

void SelectUserIDsPage::setCertificateToCertify( const Key & key ) {
    m_userIDModel.setCertificateToCertify( key );

}

SelectCheckLevelPage::SelectCheckLevelPage( QWidget * parent ) : QWizardPage( parent ), m_ui() {
    m_ui.setupUi( this );
}

unsigned int SelectCheckLevelPage::checkLevel() const {
    if ( m_ui.checkLevelNotCheckedRB->isChecked() )
        return 1;
    if ( m_ui.checkLevelCasualRB->isChecked() )
        return 2;
    if ( m_ui.checkLevelThoroughlyRB->isChecked() )
        return 3;
    assert( !"No check level radiobutton checked" );
    return 0;
}

OptionsPage::OptionsPage( QWidget * parent ) : QWizardPage( parent ), m_ui() {
    m_ui.setupUi( this );
    m_ui.keyListView->setModel( &m_model );
    connect( m_ui.keyListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(completeChanged()) );
    setCommitPage( true );
    setButtonText( QWizard::CommitButton, i18n( "Certify" ) );
}

bool OptionsPage::exportableCertificationSelected() const {
    return m_ui.exportableSignatureRB->isChecked();
}

void OptionsPage::setCertificatesWithSecretKeys( const std::vector<Key> & keys ) {
    assert( !keys.empty() );
    m_model.setSecretKeys( keys );
    if ( keys.size() == 1 ) {
        m_ui.stackedWidget->setCurrentWidget( m_ui.singleKeyPage );
        m_ui.singleKeyLabel->setText( i18n( "Certification will be performed using certificate %1.", Formatting::prettyNameAndEMail( keys[0] ) ) );
    } else {
        m_ui.stackedWidget->setCurrentWidget( m_ui.multipleKeysPage );
    }
    emit completeChanged();
}

Key OptionsPage::selectedSecretKey() const {
    const QModelIndexList idxs = m_ui.keyListView->selectionModel()->selectedIndexes();
    assert( idxs.size() <= 1 );
    return idxs.isEmpty() ? Key() : m_model.keyFromIndex( idxs[0] );
}

bool OptionsPage::sendToServer() const {
    return m_ui.sendToServerCB->isChecked();
}

bool OptionsPage::validatePage() {
    emit nextClicked();
    return true;
}

bool OptionsPage::isComplete() const {
    return !selectedSecretKey().isNull();
}

SummaryPage::SummaryPage( QWidget * parent ) : QWizardPage( parent ), m_complete( false ) {
    QGridLayout * const layout = new QGridLayout( this );
    QLabel * const uidLabelLabel = new QLabel( i18n( "Signed user IDs:" ) );
    uidLabelLabel->setAlignment( Qt::AlignTop );
    layout->addWidget( uidLabelLabel, 0, 0 );
    layout->addWidget( m_userIDsLabel = new QLabel, 0, 1 );
    layout->addWidget( new QLabel( i18n( "Check level:"  )), 1, 0 );
    layout->addWidget( m_checkLevelLabel = new QLabel, 1, 1 );
    layout->addWidget( new QLabel( i18n( "Selected secret certificate:" ) ), 2, 0 );
    layout->addWidget( m_secretKeyLabel = new QLabel, 2, 1 );
    m_secretKeyLabel->setTextFormat( Qt::PlainText );
    layout->addWidget( m_resultLabel = new QLabel, 3, 0, 2, 1 );
}

bool SummaryPage::isComplete() const {
    return m_complete;
}

void SummaryPage::setSummary( const SummaryPage::Summary & sum ) {
    const Key key = sum.certificateToCertify;
    QStringList ids;
    Q_FOREACH ( const unsigned int i, sum.selectedUserIDs )
        ids += Qt::escape( Formatting::prettyUserID( key.userID( i ) ) );
    m_userIDsLabel->setText( "<qt>" + ids.join( "
" ) + "</qt>" );
    m_secretKeyLabel->setText( sum.secretKey.isNull() ? i18n( "Default certificate" ) : Formatting::prettyNameAndEMail( sum.secretKey ) );
    switch( sum.checkLevel ) {
        case 0:
            m_checkLevelLabel->setText( i18n( "No statement made" ) );
            break;
        case 1:
            m_checkLevelLabel->setText( i18n( "Not checked" ) );
            break;
        case 2:
            m_checkLevelLabel->setText( i18n( "Casually checked" ) );
            break;
        case 3:
            m_checkLevelLabel->setText( i18n( "Thoroughly checked" ) );
            break;
    }
}

void SummaryPage::setComplete( bool complete ) {
    if ( complete == m_complete )
        return;
    m_complete = complete;
    emit completeChanged();
}
void SummaryPage::setResult( const Error & err ) {
    if ( err && !err.isCanceled() )
        m_resultLabel->setText( i18n( "Error: %1", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ) );
    else if ( err.isCanceled() )
        m_resultLabel->setText( "Certification canceled." );
    else
        m_resultLabel->setText("Certification finished." );
}

class CertifyCertificateDialog::Private {
    friend class ::Kleo::Dialogs::CertifyCertificateDialog;
    CertifyCertificateDialog * const q;

public:
    explicit Private( CertifyCertificateDialog * qq )
        : q( qq ),
        summaryPageId( 0 ),
        selectUserIDsPage( 0 ),
        selectCheckLevelPage( 0 ),
        optionsPage( 0 ),
        summaryPage( 0 )
    {
        selectUserIDsPage = new SelectUserIDsPage( q );
        q->addPage( selectUserIDsPage );
        selectCheckLevelPage = new SelectCheckLevelPage( q );
        q->addPage( selectCheckLevelPage );
        optionsPage = new OptionsPage( q );
        q->addPage( optionsPage );
        summaryPage = new SummaryPage( q );
        summaryPageId = q->addPage( summaryPage );
        connect( optionsPage, SIGNAL(nextClicked()), q, SIGNAL(certificationPrepared()) );
    }

    void ensureSummaryPageVisible();

    void certificationResult( const Error & error );

    void setOperationCompleted() {
        summaryPage->setComplete( true );
    }

    SummaryPage::Summary createSummary() const {
        SummaryPage::Summary sum;
        sum.selectedUserIDs = selectUserIDsPage->selectedUserIDs();
        sum.secretKey = optionsPage->selectedSecretKey();
        sum.certificateToCertify = selectUserIDsPage->certificateToCertify();
        sum.checkLevel = selectCheckLevelPage->checkLevel();
        sum.exportable = optionsPage->exportableCertificationSelected();
        sum.sendToServer = optionsPage->sendToServer();
        return sum;
    }

    int summaryPageId;
    SelectUserIDsPage * selectUserIDsPage;
    SelectCheckLevelPage * selectCheckLevelPage;
    OptionsPage * optionsPage;
    SummaryPage * summaryPage;
};

CertifyCertificateDialog::CertifyCertificateDialog( QWidget * p, Qt::WindowFlags f )
    : QWizard( p, f ), d( new Private( this ) )
{
}

CertifyCertificateDialog::~CertifyCertificateDialog() {}

void CertifyCertificateDialog::setCertificateToCertify( const Key & key ) {
    setWindowTitle( i18nc( "arg is name, email of certificate holder", "Certify Certificate: %1", Formatting::prettyName( key ) ) );
    d->selectUserIDsPage->setCertificateToCertify( key );
}

void CertifyCertificateDialog::setCertificatesWithSecretKeys( const std::vector<Key> & keys ) {
    d->optionsPage->setCertificatesWithSecretKeys( keys );
}

bool CertifyCertificateDialog::exportableCertificationSelected() const {
    return d->optionsPage->exportableCertificationSelected();
}

bool CertifyCertificateDialog::trustCertificationSelected() const {
    return false;
}

bool CertifyCertificateDialog::nonRevocableCertificationSelected() const {
    return false;
}

Key CertifyCertificateDialog::selectedSecretKey() const {
    return d->optionsPage->selectedSecretKey();
}

bool CertifyCertificateDialog::sendToServer() const {
    return d->optionsPage->sendToServer();
}

unsigned int CertifyCertificateDialog::selectedCheckLevel() const {
    return d->selectCheckLevelPage->checkLevel();
}

void CertifyCertificateDialog::connectJob( SignKeyJob * job ) {
    connect( job, SIGNAL(result(GpgME::Error)), this, SLOT(certificationResult(GpgME::Error)) );
    d->summaryPage->setSummary( d->createSummary() );
}

void CertifyCertificateDialog::setError( const Error & error ) {
    d->setOperationCompleted();
    d->summaryPage->setResult( error );
    d->ensureSummaryPageVisible();
    if ( error.isCanceled() )
        close();
}

void CertifyCertificateDialog::Private::certificationResult( const Error & err ) {
    setOperationCompleted();
    summaryPage->setResult( err );
    ensureSummaryPageVisible();
}

std::vector<unsigned int> CertifyCertificateDialog::selectedUserIDs() const {
    return d->selectUserIDsPage->selectedUserIDs();
}

void CertifyCertificateDialog::Private::ensureSummaryPageVisible() {
    while ( q->currentId() != summaryPageId )
        q->next();
}

#include "moc_certifycertificatedialog.cpp"
#include "moc_certifycertificatedialog_p.cpp"
<|endoftext|>


<commit_before>/**
 * kmacctimap.cpp
 *
 * Copyright (c) 2000-2002 Michael Haeckel <haeckel@kde.org>
 *
 * This file is based on kmacctexppop.cpp by Don Sanders
 *
 *  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; version 2 of the License
 *
 *  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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmacctimap.h"
using KMail::SieveConfig;

#include "kmbroadcaststatus.h"
#include "kmfoldertree.h"
#include "kmfoldermgr.h"
#include "kmfolderimap.h"
#include "kmmainwin.h"
#include "folderstorage.h"
#include "imapjob.h"
using KMail::ImapJob;
#include "progressmanager.h"
using KPIM::ProgressItem;
using KPIM::ProgressManager;
#include <kio/scheduler.h>
#include <kio/slave.h>
#include <kmessagebox.h>
#include <kdebug.h>

//-----------------------------------------------------------------------------
KMAcctImap::KMAcctImap(KMAcctMgr* aOwner, const QString& aAccountName, uint id):
  KMail::ImapAccountBase(aOwner, aAccountName, id),
  mCountRemainChecks( 0 )
{
  mFolder = 0;
  mOpenFolders.setAutoDelete(true);
  connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
      this, SLOT(slotUpdateFolderList()));
}

//-----------------------------------------------------------------------------
KMAcctImap::~KMAcctImap()
{
  killAllJobs( true );
}

//-----------------------------------------------------------------------------
QString KMAcctImap::type() const
{
  return "imap";
}

//-----------------------------------------------------------------------------
void KMAcctImap::pseudoAssign( const KMAccount * a ) {
  mIdleTimer.stop();
  killAllJobs( true );
  if (mFolder)
  {
    mFolder->setContentState(KMFolderImap::imapNoInformation);
    mFolder->setSubfolderState(KMFolderImap::imapNoInformation);
  }
  ImapAccountBase::pseudoAssign( a );
}

//-----------------------------------------------------------------------------
void KMAcctImap::setImapFolder(KMFolderImap *aFolder)
{
  mFolder = aFolder;
  mFolder->setImapPath(mPrefix);
}

//-----------------------------------------------------------------------------

bool KMAcctImap::handleError( int errorCode, const QString &errorMsg, KIO::Job* job, const QString& context, bool abortSync )
{
  /* TODO check where to handle this one better. */
  if ( errorCode == KIO::ERR_DOES_NOT_EXIST ) {
    // folder is gone, so reload the folderlist
    if ( mFolder )
      mFolder->listDirectory();
    return true;
  }
  return ImapAccountBase::handleError( errorCode, errorMsg, job, context, abortSync );
}

//-----------------------------------------------------------------------------
void KMAcctImap::killAllJobs( bool disconnectSlave )
{
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for ( ; it != mapJobData.end(); ++it)
  {
    QPtrList<KMMessage> msgList = (*it).msgList;
    QPtrList<KMMessage>::Iterator it2 = msgList.begin();
    for ( ; it2 != msgList.end(); ++it2 ) {
       KMMessage *msg = *it2;
       if ( msg->transferInProgress() ) {
          kdDebug(5006) << "KMAcctImap::killAllJobs - resetting mail" << endl;
          msg->setTransferInProgress( false );
       }
    }
    if ((*it).parent)
    {
      // clear folder state
      KMFolderImap *fld = static_cast<KMFolderImap*>((*it).parent->storage());
      fld->setCheckingValidity(false);
      fld->setContentState(KMFolderImap::imapNoInformation);
      fld->setSubfolderState(KMFolderImap::imapNoInformation);
      fld->sendFolderComplete(FALSE);
      fld->removeJobs();
    }
  }
  if (mSlave && mapJobData.begin() != mapJobData.end())
  {
    mSlave->kill();
    mSlave = 0;
  }
  // remove the jobs
  mapJobData.clear();
  KMAccount::deleteFolderJobs();
  // make sure that no new-mail-check is blocked
  if (mCountRemainChecks > 0)
  {
    checkDone( false, CheckOK ); // returned 0 new messages
    mCountRemainChecks = 0;
  }
  if ( disconnectSlave && slave() ) {
    KIO::Scheduler::disconnectSlave( slave() );
    mSlave = 0;
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::ignoreJobsForMessage( KMMessage* msg )
{
  if (!msg) return;
  QPtrListIterator<ImapJob> it( mJobList );
  while ( it.current() )
  {
    ImapJob *job = it.current();
    ++it;
    if ( job->msgList().findRef( msg ) != -1 )
    {
      if ( job->mJob )
        removeJob( job->mJob );
      mJobList.remove( job );
      job->kill();
    }
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::ignoreJobsForFolder( KMFolder* folder )
{
  QPtrListIterator<ImapJob> it( mJobList );
  while ( it.current() )
  {
    ImapJob *job = it.current();
    ++it;
    if ( !job->msgList().isEmpty() && job->msgList().first()->parent() == folder )
    {
      if ( job->mJob )
        removeJob( job->mJob );
      mJobList.remove( job );
      job->kill();
    }
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::removeSlaveJobsForFolder( KMFolder* folder )
{
  // Make sure the folder is not referenced in any kio slave jobs
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  while ( it != mapJobData.end() ) {
     QMap<KIO::Job*, jobData>::Iterator i = it;
     it++;
     if ( (*i).parent ) {
        if ( (*i).parent == folder ) {
           mapJobData.remove(i);
        }
     }
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::cancelMailCheck()
{
  // Make list of folders to reset, like in killAllJobs
  QValueList<KMFolderImap*> folderList;
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for (; it != mapJobData.end(); ++it) {
    if ( (*it).cancellable && (*it).parent ) {
      folderList << static_cast<KMFolderImap*>((*it).parent->storage());
    }
  }
  // Kill jobs
  // FIXME
  // ImapAccountBase::cancelMailCheck();
  killAllJobs( true );
  // emit folderComplete, this is important for
  // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
  for( QValueList<KMFolderImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolderImap *fld = *it;
    fld->sendFolderComplete(FALSE);
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::processNewMail(bool interactive)
{
  if (!mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
      makeConnection() == ImapAccountBase::Error)
  {
    mCountRemainChecks = 0;
    checkDone( false, CheckError );
    return;
  }
  // if necessary then initialize the list of folders which should be checked
  if( mMailCheckFolders.isEmpty() )
  {
    slotUpdateFolderList();
    // if no folders should be checked then the check is finished
    if( mMailCheckFolders.isEmpty() )
    {
      checkDone( false, CheckOK );
    }
  }
  // Ok, we're really checking, get a progress item;
  Q_ASSERT( !mMailCheckProgressItem );
  mMailCheckProgressItem =
    ProgressManager::createProgressItem(
        "MailCheckAccount" + name(),
        i18n("Checking account: " ) + name(),
        QString::null, // status
        true, // can be canceled
        useSSL() || useTLS() );

  mMailCheckProgressItem->setTotalItems( mMailCheckFolders.count() );
  connect ( mMailCheckProgressItem,
            SIGNAL( progressItemCanceled( ProgressItem*) ),
            this,
            SLOT( slotMailCheckCanceled() ) );

  QValueList<QGuardedPtr<KMFolder> >::Iterator it;
  // first get the current count of unread-messages
  mCountRemainChecks = 0;
  mCountUnread = 0;
  mUnreadBeforeCheck.clear();
  for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); it++)
  {
    KMFolder *folder = *it;
    if (folder && !folder->noContent())
    {
      mUnreadBeforeCheck[folder->idString()] = folder->countUnread();
    }
  }
  bool gotError = false;
  // then check for new mails
  for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); it++)
  {
    KMFolder *folder = *it;
    if (folder && !folder->noContent())
    {
      KMFolderImap *imapFolder = static_cast<KMFolderImap*>(folder->storage());
      if (imapFolder->getContentState() != KMFolderImap::imapInProgress)
      {
        // connect the result-signals for new-mail-notification
        mCountRemainChecks++;
        if (imapFolder->isSelected()) {
          connect(imapFolder, SIGNAL(folderComplete(KMFolderImap*, bool)),
              this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
          imapFolder->getFolder();
        }
        else {
          connect(imapFolder, SIGNAL(numUnreadMsgsChanged(KMFolder*)),
              this, SLOT(postProcessNewMail(KMFolder*)));
          bool ok = imapFolder->processNewMail(interactive);
          if (!ok)
          {
            // there was an error so cancel
            mCountRemainChecks--;
            gotError = true;
          }
        }
      }
    }
  } // end for
  if ( gotError )
    slotUpdateFolderList();
}

//-----------------------------------------------------------------------------
void KMAcctImap::postProcessNewMail(KMFolderImap* folder, bool)
{
  disconnect(folder, SIGNAL(folderComplete(KMFolderImap*, bool)),
      this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
  postProcessNewMail(static_cast<KMFolder*>(folder->folder()));
}

void KMAcctImap::postProcessNewMail( KMFolder * folder ) {

  disconnect( folder->storage(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
              this, SLOT(postProcessNewMail(KMFolder*)) );

  if ( mMailCheckProgressItem ) {
    mMailCheckProgressItem->incCompletedItems();
    mMailCheckProgressItem->updateProgress();
    mMailCheckProgressItem->setStatus( folder->prettyURL() + i18n(" completed") );
  }
  mCountRemainChecks--;

  // count the unread messages
  const QString folderId = folder->idString();
  int newInFolder = folder->countUnread();
  if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
    newInFolder -= mUnreadBeforeCheck[folderId];
  if ( newInFolder > 0 ) {
    addToNewInFolder( folderId, newInFolder );
    mCountUnread += newInFolder;
  }
  if (mCountRemainChecks == 0)
  {
    // all checks are done
    mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
    ImapAccountBase::postProcessNewMail();
    mUnreadBeforeCheck.clear();
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::slotUpdateFolderList()
{
  if (!mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
      makeConnection() != ImapAccountBase::Connected)
    return;
  QStringList strList;
  mMailCheckFolders.clear();
  kmkernel->imapFolderMgr()->createFolderList(&strList, &mMailCheckFolders,
    mFolder->folder()->child(), QString::null, false);
  // the new list
  QValueList<QGuardedPtr<KMFolder> > includedFolders;
  // check for excluded folders
  QValueList<QGuardedPtr<KMFolder> >::Iterator it;
  for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); it++)
  {
    KMFolderImap* folder = static_cast<KMFolderImap*>(((KMFolder*)(*it))->storage());
    if (folder->includeInMailCheck())
      includedFolders.append(*it);
  }
  mMailCheckFolders = includedFolders;
}

//-----------------------------------------------------------------------------
void KMAcctImap::listDirectory()
{
  mFolder->listDirectory();
}

//-----------------------------------------------------------------------------
void KMAcctImap::setPrefixHook() {
  if ( mFolder ) mFolder->setImapPath( prefix() );
}

//-----------------------------------------------------------------------------
void KMAcctImap::readConfig(KConfig& config)
{
  ImapAccountBase::readConfig( config );
  if ( checkExclude() ) {
    disconnect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
        this, SLOT(slotUpdateFolderList()));
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::slotMailCheckCanceled()
{
  if( mMailCheckProgressItem )
    mMailCheckProgressItem->setComplete();
  cancelMailCheck();
}

//-----------------------------------------------------------------------------
FolderStorage* KMAcctImap::rootFolder()
{
  return mFolder;
}

#include "kmacctimap.moc"
<commit_msg>Send a noop every 60 sec. Pretty basic solution but should work. CCMAIL: 82805-done@bugs.kde.org<commit_after>/**
 * kmacctimap.cpp
 *
 * Copyright (c) 2000-2002 Michael Haeckel <haeckel@kde.org>
 *
 * This file is based on kmacctexppop.cpp by Don Sanders
 *
 *  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; version 2 of the License
 *
 *  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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmacctimap.h"
using KMail::SieveConfig;

#include "kmbroadcaststatus.h"
#include "kmfoldertree.h"
#include "kmfoldermgr.h"
#include "kmfolderimap.h"
#include "kmmainwin.h"
#include "folderstorage.h"
#include "imapjob.h"
using KMail::ImapJob;
#include "progressmanager.h"
using KPIM::ProgressItem;
using KPIM::ProgressManager;
#include <kio/scheduler.h>
#include <kio/slave.h>
#include <kmessagebox.h>
#include <kdebug.h>

//-----------------------------------------------------------------------------
KMAcctImap::KMAcctImap(KMAcctMgr* aOwner, const QString& aAccountName, uint id):
  KMail::ImapAccountBase(aOwner, aAccountName, id),
  mCountRemainChecks( 0 )
{
  mFolder = 0;
  mIdle = false; // never disconnect
  mIdleTimer.start( 60000 ); // // send a noop every minute
  mOpenFolders.setAutoDelete(true);
  connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
      this, SLOT(slotUpdateFolderList()));
}

//-----------------------------------------------------------------------------
KMAcctImap::~KMAcctImap()
{
  killAllJobs( true );
}

//-----------------------------------------------------------------------------
QString KMAcctImap::type() const
{
  return "imap";
}

//-----------------------------------------------------------------------------
void KMAcctImap::pseudoAssign( const KMAccount * a ) {
  killAllJobs( true );
  if (mFolder)
  {
    mFolder->setContentState(KMFolderImap::imapNoInformation);
    mFolder->setSubfolderState(KMFolderImap::imapNoInformation);
  }
  ImapAccountBase::pseudoAssign( a );
}

//-----------------------------------------------------------------------------
void KMAcctImap::setImapFolder(KMFolderImap *aFolder)
{
  mFolder = aFolder;
  mFolder->setImapPath(mPrefix);
}

//-----------------------------------------------------------------------------

bool KMAcctImap::handleError( int errorCode, const QString &errorMsg, KIO::Job* job, const QString& context, bool abortSync )
{
  /* TODO check where to handle this one better. */
  if ( errorCode == KIO::ERR_DOES_NOT_EXIST ) {
    // folder is gone, so reload the folderlist
    if ( mFolder )
      mFolder->listDirectory();
    return true;
  }
  return ImapAccountBase::handleError( errorCode, errorMsg, job, context, abortSync );
}

//-----------------------------------------------------------------------------
void KMAcctImap::killAllJobs( bool disconnectSlave )
{
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for ( ; it != mapJobData.end(); ++it)
  {
    QPtrList<KMMessage> msgList = (*it).msgList;
    QPtrList<KMMessage>::Iterator it2 = msgList.begin();
    for ( ; it2 != msgList.end(); ++it2 ) {
       KMMessage *msg = *it2;
       if ( msg->transferInProgress() ) {
          kdDebug(5006) << "KMAcctImap::killAllJobs - resetting mail" << endl;
          msg->setTransferInProgress( false );
       }
    }
    if ((*it).parent)
    {
      // clear folder state
      KMFolderImap *fld = static_cast<KMFolderImap*>((*it).parent->storage());
      fld->setCheckingValidity(false);
      fld->setContentState(KMFolderImap::imapNoInformation);
      fld->setSubfolderState(KMFolderImap::imapNoInformation);
      fld->sendFolderComplete(FALSE);
      fld->removeJobs();
    }
  }
  if (mSlave && mapJobData.begin() != mapJobData.end())
  {
    mSlave->kill();
    mSlave = 0;
  }
  // remove the jobs
  mapJobData.clear();
  KMAccount::deleteFolderJobs();
  // make sure that no new-mail-check is blocked
  if (mCountRemainChecks > 0)
  {
    checkDone( false, CheckOK ); // returned 0 new messages
    mCountRemainChecks = 0;
  }
  if ( disconnectSlave && slave() ) {
    KIO::Scheduler::disconnectSlave( slave() );
    mSlave = 0;
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::ignoreJobsForMessage( KMMessage* msg )
{
  if (!msg) return;
  QPtrListIterator<ImapJob> it( mJobList );
  while ( it.current() )
  {
    ImapJob *job = it.current();
    ++it;
    if ( job->msgList().findRef( msg ) != -1 )
    {
      if ( job->mJob )
        removeJob( job->mJob );
      mJobList.remove( job );
      job->kill();
    }
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::ignoreJobsForFolder( KMFolder* folder )
{
  QPtrListIterator<ImapJob> it( mJobList );
  while ( it.current() )
  {
    ImapJob *job = it.current();
    ++it;
    if ( !job->msgList().isEmpty() && job->msgList().first()->parent() == folder )
    {
      if ( job->mJob )
        removeJob( job->mJob );
      mJobList.remove( job );
      job->kill();
    }
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::removeSlaveJobsForFolder( KMFolder* folder )
{
  // Make sure the folder is not referenced in any kio slave jobs
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  while ( it != mapJobData.end() ) {
     QMap<KIO::Job*, jobData>::Iterator i = it;
     it++;
     if ( (*i).parent ) {
        if ( (*i).parent == folder ) {
           mapJobData.remove(i);
        }
     }
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::cancelMailCheck()
{
  // Make list of folders to reset, like in killAllJobs
  QValueList<KMFolderImap*> folderList;
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for (; it != mapJobData.end(); ++it) {
    if ( (*it).cancellable && (*it).parent ) {
      folderList << static_cast<KMFolderImap*>((*it).parent->storage());
    }
  }
  // Kill jobs
  // FIXME
  // ImapAccountBase::cancelMailCheck();
  killAllJobs( true );
  // emit folderComplete, this is important for
  // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
  for( QValueList<KMFolderImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolderImap *fld = *it;
    fld->sendFolderComplete(FALSE);
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::processNewMail(bool interactive)
{
  if (!mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
      makeConnection() == ImapAccountBase::Error)
  {
    mCountRemainChecks = 0;
    checkDone( false, CheckError );
    return;
  }
  // if necessary then initialize the list of folders which should be checked
  if( mMailCheckFolders.isEmpty() )
  {
    slotUpdateFolderList();
    // if no folders should be checked then the check is finished
    if( mMailCheckFolders.isEmpty() )
    {
      checkDone( false, CheckOK );
    }
  }
  // Ok, we're really checking, get a progress item;
  Q_ASSERT( !mMailCheckProgressItem );
  mMailCheckProgressItem =
    ProgressManager::createProgressItem(
        "MailCheckAccount" + name(),
        i18n("Checking account: " ) + name(),
        QString::null, // status
        true, // can be canceled
        useSSL() || useTLS() );

  mMailCheckProgressItem->setTotalItems( mMailCheckFolders.count() );
  connect ( mMailCheckProgressItem,
            SIGNAL( progressItemCanceled( ProgressItem*) ),
            this,
            SLOT( slotMailCheckCanceled() ) );

  QValueList<QGuardedPtr<KMFolder> >::Iterator it;
  // first get the current count of unread-messages
  mCountRemainChecks = 0;
  mCountUnread = 0;
  mUnreadBeforeCheck.clear();
  for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); it++)
  {
    KMFolder *folder = *it;
    if (folder && !folder->noContent())
    {
      mUnreadBeforeCheck[folder->idString()] = folder->countUnread();
    }
  }
  bool gotError = false;
  // then check for new mails
  for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); it++)
  {
    KMFolder *folder = *it;
    if (folder && !folder->noContent())
    {
      KMFolderImap *imapFolder = static_cast<KMFolderImap*>(folder->storage());
      if (imapFolder->getContentState() != KMFolderImap::imapInProgress)
      {
        // connect the result-signals for new-mail-notification
        mCountRemainChecks++;
        if (imapFolder->isSelected()) {
          connect(imapFolder, SIGNAL(folderComplete(KMFolderImap*, bool)),
              this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
          imapFolder->getFolder();
        }
        else {
          connect(imapFolder, SIGNAL(numUnreadMsgsChanged(KMFolder*)),
              this, SLOT(postProcessNewMail(KMFolder*)));
          bool ok = imapFolder->processNewMail(interactive);
          if (!ok)
          {
            // there was an error so cancel
            mCountRemainChecks--;
            gotError = true;
          }
        }
      }
    }
  } // end for
  if ( gotError )
    slotUpdateFolderList();
}

//-----------------------------------------------------------------------------
void KMAcctImap::postProcessNewMail(KMFolderImap* folder, bool)
{
  disconnect(folder, SIGNAL(folderComplete(KMFolderImap*, bool)),
      this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
  postProcessNewMail(static_cast<KMFolder*>(folder->folder()));
}

void KMAcctImap::postProcessNewMail( KMFolder * folder ) {

  disconnect( folder->storage(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
              this, SLOT(postProcessNewMail(KMFolder*)) );

  if ( mMailCheckProgressItem ) {
    mMailCheckProgressItem->incCompletedItems();
    mMailCheckProgressItem->updateProgress();
    mMailCheckProgressItem->setStatus( folder->prettyURL() + i18n(" completed") );
  }
  mCountRemainChecks--;

  // count the unread messages
  const QString folderId = folder->idString();
  int newInFolder = folder->countUnread();
  if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
    newInFolder -= mUnreadBeforeCheck[folderId];
  if ( newInFolder > 0 ) {
    addToNewInFolder( folderId, newInFolder );
    mCountUnread += newInFolder;
  }
  if (mCountRemainChecks == 0)
  {
    // all checks are done
    mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
    ImapAccountBase::postProcessNewMail();
    mUnreadBeforeCheck.clear();
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::slotUpdateFolderList()
{
  if (!mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
      makeConnection() != ImapAccountBase::Connected)
    return;
  QStringList strList;
  mMailCheckFolders.clear();
  kmkernel->imapFolderMgr()->createFolderList(&strList, &mMailCheckFolders,
    mFolder->folder()->child(), QString::null, false);
  // the new list
  QValueList<QGuardedPtr<KMFolder> > includedFolders;
  // check for excluded folders
  QValueList<QGuardedPtr<KMFolder> >::Iterator it;
  for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); it++)
  {
    KMFolderImap* folder = static_cast<KMFolderImap*>(((KMFolder*)(*it))->storage());
    if (folder->includeInMailCheck())
      includedFolders.append(*it);
  }
  mMailCheckFolders = includedFolders;
}

//-----------------------------------------------------------------------------
void KMAcctImap::listDirectory()
{
  mFolder->listDirectory();
}

//-----------------------------------------------------------------------------
void KMAcctImap::setPrefixHook() {
  if ( mFolder ) mFolder->setImapPath( prefix() );
}

//-----------------------------------------------------------------------------
void KMAcctImap::readConfig(KConfig& config)
{
  ImapAccountBase::readConfig( config );
  if ( checkExclude() ) {
    disconnect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
        this, SLOT(slotUpdateFolderList()));
  }
}

//-----------------------------------------------------------------------------
void KMAcctImap::slotMailCheckCanceled()
{
  if( mMailCheckProgressItem )
    mMailCheckProgressItem->setComplete();
  cancelMailCheck();
}

//-----------------------------------------------------------------------------
FolderStorage* KMAcctImap::rootFolder()
{
  return mFolder;
}

#include "kmacctimap.moc"
<|endoftext|>


<commit_before>/*
Dwarf Therapist
Copyright (c) 2009 Trey Stout (chmod)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "traitcolumn.h"
#include "columntypes.h"
#include "viewcolumnset.h"
#include "dwarfmodel.h"
#include "dwarf.h"
#include "trait.h"
#include "gamedatareader.h"

TraitColumn::TraitColumn(const QString &title, const short &trait_id, ViewColumnSet *set, QObject *parent)
    : ViewColumn(title, CT_TRAIT, set, parent)
    , m_trait_id(trait_id)
    , m_trait(0)
{
    m_trait = GameDataReader::ptr()->get_trait(trait_id);
}

TraitColumn::TraitColumn(QSettings &s, ViewColumnSet *set, QObject *parent)
    : ViewColumn(s, set, parent)
    , m_trait_id(s.value("trait_id", -1).toInt())
    , m_trait(0)
{
    m_trait = GameDataReader::ptr()->get_trait(m_trait_id);
}

TraitColumn::TraitColumn(const TraitColumn &to_copy)
    : ViewColumn(to_copy)
    , m_trait_id(to_copy.m_trait_id)
    , m_trait(to_copy.m_trait)
{}

QStandardItem *TraitColumn::build_cell(Dwarf *d) {
    QStandardItem *item = init_cell(d);
    short score = d->trait(m_trait_id);
    if (score == -1) // not an active trait...
        item->setText("");
    else
        item->setText(QString::number(score));
    item->setData(CT_TRAIT, DwarfModel::DR_COL_TYPE);
    item->setData(score, DwarfModel::DR_SORT_VALUE);

    QString msg = "???";
    if (m_trait)
        msg = m_trait->level_message(score);
    if (score == -1)
        msg = "Not an active trait for this dwarf";

    QString tooltip = QString("
%1
%2 (%3)
%4
")
        .arg(m_title)
        .arg(msg)
        .arg(score)
        .arg(d->nice_name());
    item->setToolTip(tooltip);
    return item;
}

QStandardItem *TraitColumn::build_aggregate(const QString &group_name, const QVector<Dwarf*> &dwarves) {
    Q_UNUSED(group_name);
    Q_UNUSED(dwarves);
    QStandardItem *item = new QStandardItem;
    item->setData(m_bg_color, DwarfModel::DR_DEFAULT_BG_COLOR);
    return item;
}
<commit_msg> * treat inactive dwarf traits as a value of 50 rather than -1 (Fixed issue 149)<commit_after>/*
Dwarf Therapist
Copyright (c) 2009 Trey Stout (chmod)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "traitcolumn.h"
#include "columntypes.h"
#include "viewcolumnset.h"
#include "dwarfmodel.h"
#include "dwarf.h"
#include "trait.h"
#include "gamedatareader.h"

TraitColumn::TraitColumn(const QString &title, const short &trait_id, ViewColumnSet *set, QObject *parent)
    : ViewColumn(title, CT_TRAIT, set, parent)
    , m_trait_id(trait_id)
    , m_trait(0)
{
    m_trait = GameDataReader::ptr()->get_trait(trait_id);
}

TraitColumn::TraitColumn(QSettings &s, ViewColumnSet *set, QObject *parent)
    : ViewColumn(s, set, parent)
    , m_trait_id(s.value("trait_id", -1).toInt())
    , m_trait(0)
{
    m_trait = GameDataReader::ptr()->get_trait(m_trait_id);
}

TraitColumn::TraitColumn(const TraitColumn &to_copy)
    : ViewColumn(to_copy)
    , m_trait_id(to_copy.m_trait_id)
    , m_trait(to_copy.m_trait)
{}

QStandardItem *TraitColumn::build_cell(Dwarf *d) {
    QStandardItem *item = init_cell(d);
    item->setData(CT_TRAIT, DwarfModel::DR_COL_TYPE);

    short score = d->trait(m_trait_id);
    QString msg = "???";
    if (m_trait)
        msg = m_trait->level_message(score);

    if (score == -1) { // not an active trait...
        item->setText("");
        item->setData(50, DwarfModel::DR_SORT_VALUE);
        msg = tr("Not an active trait for this dwarf");
    } else {
        item->setText(QString::number(score));
        item->setData(score, DwarfModel::DR_SORT_VALUE);
    }

    QString tooltip = QString("
%1
%2 (%3)
%4
")
        .arg(m_title)
        .arg(msg)
        .arg(score)
        .arg(d->nice_name());
    item->setToolTip(tooltip);
    return item;
}

QStandardItem *TraitColumn::build_aggregate(const QString &group_name, const QVector<Dwarf*> &dwarves) {
    Q_UNUSED(group_name);
    Q_UNUSED(dwarves);
    QStandardItem *item = new QStandardItem;
    item->setData(m_bg_color, DwarfModel::DR_DEFAULT_BG_COLOR);
    return item;
}
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <unordered_map>
#include "core/future.hh"
#include "net/api.hh"
#include "core/reactor.hh"
#include "core/iostream.hh"
#include "core/shared_ptr.hh"

namespace rpc {

using id_type = int64_t;

struct SerializerConcept {
    template<typename T>
    future<> operator()(output_stream<char>& out, T&& v);
    template<typename T>
    future<> operator()(input_stream<char>& in, T& v);
    // id_type and sstring are needed for compilation to succeed
    future<> operator()(output_stream<char>& out, id_type& v);
    future<> operator()(input_stream<char>& in, id_type& v);
    future<> operator()(output_stream<char>& out, sstring& v);
    future<> operator()(input_stream<char>& in, sstring& v);
};

struct client_info {
    socket_address addr;
};

// MsgType is a type that holds type of a message. The type should be hashable
// and serializable. It is preferable to use enum for message types, but
// do not forget to provide hash function for it
template<typename Serializer, typename MsgType = uint32_t>
class protocol {
    class connection {
    protected:
        connected_socket _fd;
        input_stream<char> _read_buf;
        output_stream<char> _write_buf;
        future<> _output_ready = make_ready_future<>();
        bool _error = false;
        protocol& _proto;
    public:
        connection(connected_socket&& fd, protocol& proto) : _fd(std::move(fd)), _read_buf(_fd.input()), _write_buf(_fd.output()), _proto(proto) {}
        connection(protocol& proto) : _proto(proto) {}
        // functions below are public because they are used by external heavily templated functions
        // and I am not smart enough to know how to define them as friends
        auto& in() { return _read_buf; }
        auto& out() { return _write_buf; }
        auto& out_ready() { return _output_ready; }
        bool error() { return _error; }
        auto& serializer() { return _proto._serializer; }
        auto& get_protocol() { return _proto; }
    };
    friend connection;

public:
    class server {
    private:
        protocol& _proto;
    public:
        class connection : public protocol::connection, public enable_lw_shared_from_this<connection> {
            server& _server;
            MsgType _type;
            client_info _info;
        public:
            connection(server& s, connected_socket&& fd, socket_address&& addr, protocol& proto);
            future<> process();
            auto& info() { return _info; }
        };
        server(protocol& proto, ipv4_addr addr);
        void accept(server_socket&& ss);
        friend connection;
    };

    class client : public protocol::connection {
        promise<> _connected;
        id_type _message_id = 1;
        id_type _rcv_msg_id = 0;
        struct reply_handler_base {
            virtual future<> operator()(client&, id_type) = 0;
        };
    public:
        template<typename Reply, typename Func>
        struct reply_handler final : reply_handler_base {
            Func func;
            Reply reply;
            reply_handler(Func&& f) : func(std::move(f)) {}
            virtual future<> operator()(client& client, id_type msg_id) override {
                return func(reply, client, msg_id);
            }
        };
    private:
        std::unordered_map<id_type, std::unique_ptr<reply_handler_base>> _outstanding;
    public:
        client(protocol& proto, ipv4_addr addr);
        auto next_message_id() { return _message_id++; }
        void wait_for_reply(id_type id, std::unique_ptr<reply_handler_base>&& h) {
            _outstanding.emplace(id, std::move(h));
        }
    };
    friend server;
private:
    using rpc_handler = std::function<future<>(lw_shared_ptr<typename server::connection>)>;
    std::unordered_map<MsgType, rpc_handler> _handlers;
    Serializer _serializer;
    std::function<void(const sstring&)> _logger;
public:
    protocol(Serializer&& serializer) : _serializer(std::forward<Serializer>(serializer)) {}
    template<typename Func>
    auto make_client(MsgType t);

    // returns a function which type depends on Func
    // if Func == Ret(Args...) then return function is
    // future<Ret>(protocol::client&, Args...)
    template<typename Func>
    auto register_handler(MsgType t, Func&& func);

    void set_logger(std::function<void(const sstring&)> logger) {
        _logger = logger;
    }

    void log(const sstring& str) {
        if (_logger) {
            _logger(str);
            _logger("\n");
        }
    }

    void log(const client_info& info, id_type msg_id, const sstring& str) {
        log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + " msg_id " + to_sstring(msg_id) + ": " + str);
    }
private:
    void register_receiver(MsgType t, rpc_handler&& handler) {
        _handlers.emplace(t, std::move(handler));
    }
};

class error : public std::runtime_error {
public:
    error(const std::string& msg) : std::runtime_error(msg) {}
};

class closed_error : public error {
public:
    closed_error() : error("connection is closed") {}
};

struct no_wait_type {};

// return this from a callback if client does not want to waiting for a reply
extern no_wait_type no_wait;
}

#include "rpc_impl.hh"
<commit_msg>rpc: add virtual destructor for reply_handler<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <unordered_map>
#include "core/future.hh"
#include "net/api.hh"
#include "core/reactor.hh"
#include "core/iostream.hh"
#include "core/shared_ptr.hh"

namespace rpc {

using id_type = int64_t;

struct SerializerConcept {
    template<typename T>
    future<> operator()(output_stream<char>& out, T&& v);
    template<typename T>
    future<> operator()(input_stream<char>& in, T& v);
    // id_type and sstring are needed for compilation to succeed
    future<> operator()(output_stream<char>& out, id_type& v);
    future<> operator()(input_stream<char>& in, id_type& v);
    future<> operator()(output_stream<char>& out, sstring& v);
    future<> operator()(input_stream<char>& in, sstring& v);
};

struct client_info {
    socket_address addr;
};

// MsgType is a type that holds type of a message. The type should be hashable
// and serializable. It is preferable to use enum for message types, but
// do not forget to provide hash function for it
template<typename Serializer, typename MsgType = uint32_t>
class protocol {
    class connection {
    protected:
        connected_socket _fd;
        input_stream<char> _read_buf;
        output_stream<char> _write_buf;
        future<> _output_ready = make_ready_future<>();
        bool _error = false;
        protocol& _proto;
    public:
        connection(connected_socket&& fd, protocol& proto) : _fd(std::move(fd)), _read_buf(_fd.input()), _write_buf(_fd.output()), _proto(proto) {}
        connection(protocol& proto) : _proto(proto) {}
        // functions below are public because they are used by external heavily templated functions
        // and I am not smart enough to know how to define them as friends
        auto& in() { return _read_buf; }
        auto& out() { return _write_buf; }
        auto& out_ready() { return _output_ready; }
        bool error() { return _error; }
        auto& serializer() { return _proto._serializer; }
        auto& get_protocol() { return _proto; }
    };
    friend connection;

public:
    class server {
    private:
        protocol& _proto;
    public:
        class connection : public protocol::connection, public enable_lw_shared_from_this<connection> {
            server& _server;
            MsgType _type;
            client_info _info;
        public:
            connection(server& s, connected_socket&& fd, socket_address&& addr, protocol& proto);
            future<> process();
            auto& info() { return _info; }
        };
        server(protocol& proto, ipv4_addr addr);
        void accept(server_socket&& ss);
        friend connection;
    };

    class client : public protocol::connection {
        promise<> _connected;
        id_type _message_id = 1;
        id_type _rcv_msg_id = 0;
        struct reply_handler_base {
            virtual future<> operator()(client&, id_type) = 0;
            virtual ~reply_handler_base() {};
        };
    public:
        template<typename Reply, typename Func>
        struct reply_handler final : reply_handler_base {
            Func func;
            Reply reply;
            reply_handler(Func&& f) : func(std::move(f)) {}
            virtual future<> operator()(client& client, id_type msg_id) override {
                return func(reply, client, msg_id);
            }
            virtual ~reply_handler() {}
        };
    private:
        std::unordered_map<id_type, std::unique_ptr<reply_handler_base>> _outstanding;
    public:
        client(protocol& proto, ipv4_addr addr);
        auto next_message_id() { return _message_id++; }
        void wait_for_reply(id_type id, std::unique_ptr<reply_handler_base>&& h) {
            _outstanding.emplace(id, std::move(h));
        }
    };
    friend server;
private:
    using rpc_handler = std::function<future<>(lw_shared_ptr<typename server::connection>)>;
    std::unordered_map<MsgType, rpc_handler> _handlers;
    Serializer _serializer;
    std::function<void(const sstring&)> _logger;
public:
    protocol(Serializer&& serializer) : _serializer(std::forward<Serializer>(serializer)) {}
    template<typename Func>
    auto make_client(MsgType t);

    // returns a function which type depends on Func
    // if Func == Ret(Args...) then return function is
    // future<Ret>(protocol::client&, Args...)
    template<typename Func>
    auto register_handler(MsgType t, Func&& func);

    void set_logger(std::function<void(const sstring&)> logger) {
        _logger = logger;
    }

    void log(const sstring& str) {
        if (_logger) {
            _logger(str);
            _logger("\n");
        }
    }

    void log(const client_info& info, id_type msg_id, const sstring& str) {
        log(to_sstring("client ") + inet_ntoa(info.addr.as_posix_sockaddr_in().sin_addr) + " msg_id " + to_sstring(msg_id) + ": " + str);
    }
private:
    void register_receiver(MsgType t, rpc_handler&& handler) {
        _handlers.emplace(t, std::move(handler));
    }
};

class error : public std::runtime_error {
public:
    error(const std::string& msg) : std::runtime_error(msg) {}
};

class closed_error : public error {
public:
    closed_error() : error("connection is closed") {}
};

struct no_wait_type {};

// return this from a callback if client does not want to waiting for a reply
extern no_wait_type no_wait;
}

#include "rpc_impl.hh"
<|endoftext|>


<commit_before>#include "player.h"

void Player::update(const CarPosition& now) {
  if (nticks == 0) {
    // HACK. CI starts in random positions
    // don't mess up speed etc starting in the middle of something
    // just get prev ok during this tick
    return;
  }

  curspeed = compute_travel(now);
  estimate_coefs(now);
  prevspeed = curspeed;
  tottravel += curspeed;
}

void Player::estimate_coefs(const CarPosition& now) {
  if (nticks == COEF_MEAS_TICKS) {
    double initial_thrust = 1.0;
    // start pos is not always 0; speed in tick delta units
    double x1 = prevspeed;//prev.inPieceDistance;
    double x2 = prevspeed+curspeed;//now.inPieceDistance;
    // v1 = x1, as x0 = 0
    double v2 = x2 - x1;

    power = x1 / initial_thrust; // v += power * thrust, initially v zero so no drag
    drag = (v2 - x1) / x1; // v2 = drag * v1 + accel, accel = increase in one step = x1
    std::cout << "COEF: p=" << power << " d=" << drag << std::endl;
  }
}

double Player::compute_travel(const CarPosition& now) const {
  // TODO lane switching
  double lanedist = track->lanedist[now.startLane];

  double travel;
  if (now.pieceIndex == prev.pieceIndex) {
    travel = now.inPieceDistance - prev.inPieceDistance;
  } else {
    // changed piece between ticks
    double last_remaining = track->track[prev.pieceIndex].travel(lanedist) - prev.inPieceDistance;
    double in_this = now.inPieceDistance;
    travel = last_remaining + in_this;
  }
  return travel;
}

double Player::compute_throttle(const CarPosition& now) const {
#if 0
  return throttle_for_speed((nticks / 200) * topspeed() / 10.0);
#endif
  // safest throttle based on all the future track.
  // probably do not need to look ahead the whole track, but what the hell
  double best_throttle = 1.0;
  // track has >= 1 pieces for sure
  for (size_t i = 0; i < track->track.size() - 1; i++) {
    double thr = throttle_for_piece(now, i);
    best_throttle = std::min(best_throttle, thr);
  }
  return best_throttle;
}

double Player::throttle_for_piece(const CarPosition& now, int lookahead) const {
  int next = (now.pieceIndex + lookahead) % track->track.size();
  // straights do not need braking
  if (track->track[next].length != 0.0)
    return 1.0;

  double topspeed = speed_for_bend(track->track[next].radius);
  if (lookahead == 0) // already in this bend
    return throttle_for_speed(topspeed);

  double dist_to_next = dist_to_piece(now, next);
  int ticks = ticks_to_slow_down(curspeed, topspeed);
  double brake_dist = brake_travel(curspeed, ticks);

  if (dist_to_next > brake_dist)
    return 1.0;
  return 0.0;
}

double Player::dist_to_piece(const CarPosition& now, int target) const {
  if (now.pieceIndex == target)
    return 0.0;

  double lanedist = track->lanedist[now.startLane]; // close enough estimate to hold current lane
  double dist = track->track[now.pieceIndex].travel(lanedist) - now.inPieceDistance;

  int idx = (now.pieceIndex + 1) % track->track.size();
  while (idx != target) {
    dist += track->track[idx].travel(lanedist);
    idx = (idx + 1) % track->track.size();
  }

  return dist;
}

double Player::throttle_for_speed(double speed) const {
  double thr = (speed - drag * curspeed) / power;
  return std::min(std::max(thr, 0.0), 1.0);
}

double Player::topspeed() const {
  // v_n+1 = v_n - (1-d)v_n + p*t
  //     0 =      -(1-d)v_n + p*t
  return power * 1.0 / (1 - drag);
}

double Player::brake_travel(double startspeed, int ticks) const {
  // sum of the first n terms of a geometric series
  return (1 - std::pow(drag, ticks)) / (1 - drag) * startspeed;
}

int Player::ticks_to_slow_down(double cur, double target) const {
  // reach slower speed from current:
  // d^n * cur = target
  // log d^n = log target / cur
  return ceil(log(target / cur) / log(drag));
}

double Player::speed_for_bend(double radius) const {
  return 0.62 * std::sqrt(radius);
}

int Player::next_bend(int curridx) const {
  while (track->track[curridx].angle == 0)
    curridx = (curridx + 1) % track->track.size();
  return curridx;
}

void Player::endtick(const CarPosition& now) {
  prev = now;
  prevspeed = curspeed;
  nticks++;
}

<commit_msg>print out max possible speed (terminal velocity)<commit_after>#include "player.h"

void Player::update(const CarPosition& now) {
  if (nticks == 0) {
    // HACK. CI starts in random positions
    // don't mess up speed etc starting in the middle of something
    // just get prev ok during this tick
    return;
  }

  curspeed = compute_travel(now);
  estimate_coefs(now);
  prevspeed = curspeed;
  tottravel += curspeed;
}

void Player::estimate_coefs(const CarPosition& now) {
  if (nticks == COEF_MEAS_TICKS) {
    double initial_thrust = 1.0;
    // start pos is not always 0; speed in tick delta units
    double x1 = prevspeed;//prev.inPieceDistance;
    double x2 = prevspeed+curspeed;//now.inPieceDistance;
    // v1 = x1, as x0 = 0
    double v2 = x2 - x1;

    power = x1 / initial_thrust; // v += power * thrust, initially v zero so no drag
    drag = (v2 - x1) / x1; // v2 = drag * v1 + accel, accel = increase in one step = x1
    double max = power / (1 - drag);
    std::cout << "COEF: p=" << power << " d=" << drag << " maxspd=" << max << std::endl;
  }
}

double Player::compute_travel(const CarPosition& now) const {
  // TODO lane switching
  double lanedist = track->lanedist[now.startLane];

  double travel;
  if (now.pieceIndex == prev.pieceIndex) {
    travel = now.inPieceDistance - prev.inPieceDistance;
  } else {
    // changed piece between ticks
    double last_remaining = track->track[prev.pieceIndex].travel(lanedist) - prev.inPieceDistance;
    double in_this = now.inPieceDistance;
    travel = last_remaining + in_this;
  }
  return travel;
}

double Player::compute_throttle(const CarPosition& now) const {
#if 0
  return throttle_for_speed((nticks / 200) * topspeed() / 10.0);
#endif
  // safest throttle based on all the future track.
  // probably do not need to look ahead the whole track, but what the hell
  double best_throttle = 1.0;
  // track has >= 1 pieces for sure
  for (size_t i = 0; i < track->track.size() - 1; i++) {
    double thr = throttle_for_piece(now, i);
    best_throttle = std::min(best_throttle, thr);
  }
  return best_throttle;
}

double Player::throttle_for_piece(const CarPosition& now, int lookahead) const {
  int next = (now.pieceIndex + lookahead) % track->track.size();
  // straights do not need braking
  if (track->track[next].length != 0.0)
    return 1.0;

  double topspeed = speed_for_bend(track->track[next].radius);
  if (lookahead == 0) // already in this bend
    return throttle_for_speed(topspeed);

  double dist_to_next = dist_to_piece(now, next);
  int ticks = ticks_to_slow_down(curspeed, topspeed);
  double brake_dist = brake_travel(curspeed, ticks);

  if (dist_to_next > brake_dist)
    return 1.0;
  return 0.0;
}

double Player::dist_to_piece(const CarPosition& now, int target) const {
  if (now.pieceIndex == target)
    return 0.0;

  double lanedist = track->lanedist[now.startLane]; // close enough estimate to hold current lane
  double dist = track->track[now.pieceIndex].travel(lanedist) - now.inPieceDistance;

  int idx = (now.pieceIndex + 1) % track->track.size();
  while (idx != target) {
    dist += track->track[idx].travel(lanedist);
    idx = (idx + 1) % track->track.size();
  }

  return dist;
}

double Player::throttle_for_speed(double speed) const {
  double thr = (speed - drag * curspeed) / power;
  return std::min(std::max(thr, 0.0), 1.0);
}

double Player::topspeed() const {
  // v_n+1 = v_n - (1-d)v_n + p*t
  //     0 =      -(1-d)v_n + p*t
  return power * 1.0 / (1 - drag);
}

double Player::brake_travel(double startspeed, int ticks) const {
  // sum of the first n terms of a geometric series
  return (1 - std::pow(drag, ticks)) / (1 - drag) * startspeed;
}

int Player::ticks_to_slow_down(double cur, double target) const {
  // reach slower speed from current:
  // d^n * cur = target
  // log d^n = log target / cur
  return ceil(log(target / cur) / log(drag));
}

double Player::speed_for_bend(double radius) const {
  return 0.62 * std::sqrt(radius);
}

int Player::next_bend(int curridx) const {
  while (track->track[curridx].angle == 0)
    curridx = (curridx + 1) % track->track.size();
  return curridx;
}

void Player::endtick(const CarPosition& now) {
  prev = now;
  prevspeed = curspeed;
  nticks++;
}

<|endoftext|>


<commit_before>/****************************************************************************

This file is part of the QtMediaHub project on http://www.gitorious.org.

Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Nokia Corporation (qt-info@nokia.com)**

You may use this file under the terms of the BSD license as follows:

"Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."

****************************************************************************/

#include "httpclient.h"

#include <QtSql>

#include "backend.h"
#include "httpserver.h"

HttpClient::HttpClient(int sockfd, HttpServer *server, QObject *parent) :
    QObject(parent)
{
    m_server = server;
    m_socket = new QTcpSocket(this);
    if (!m_socket->setSocketDescriptor(sockfd)) {
        emit error(m_socket->error());
        return;
    }

    connect(m_socket, SIGNAL(readyRead()), this, SLOT(readClient()));
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(discardClient()));
}

void HttpClient::readClient()
{
    if (m_socket->canReadLine()) {
        QByteArray bytesRead = m_socket->readLine();
        QStringList tokens = QString(bytesRead).split(QRegExp("[ \r\n][ \r\n]*"));

        while(m_socket->canReadLine()) {
            bytesRead = m_socket->readLine();
            QList<QByteArray> lineTokens = bytesRead.split(':');
            if (lineTokens.size() == 2) {
                m_request.insert(lineTokens[0], lineTokens[1].trimmed().replace("\r\n",""));
            }
        }
        qDebug() << m_request;

        if (tokens[0] == "GET") {
            m_get = tokens[1];
            qDebug() << "GET" << m_get;
            if (m_get.startsWith("/video"))
                readVideoRequest();
            else if(m_get.startsWith("/music"))
                readMusicRequest();
            else if(m_get.startsWith("/picture"))
                readPictureRequest();
        }

    }

    m_socket->close();
    discardClient();

    return;
}

void HttpClient::discardClient()
{
    m_file.close();

    m_socket->deleteLater();
    emit disconnected();

    qDebug() << "Connection closed";
}

void HttpClient::readVideoRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);

    if (m_request.contains("Range")) {
        QString offsetString = m_request.value("Range");
        offsetString.remove(0, 6);
        qint64 offset = offsetString.split("-").at(0).toLongLong();
        sendPartial(getMediaUrl("video", id.toInt()).toLocalFile(), offset);
    } else {
        sendFile(getMediaUrl("video", id.toInt()).toLocalFile());
    }

    m_socket->close();
}

void HttpClient::readMusicRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);
    sendFile(getMediaUrl("music", id.toInt()).toLocalFile());

    m_socket->close();
}

void HttpClient::readPictureRequest()
{
}

void HttpClient::answerOk(qint64 length)
{
    QByteArray answer;
    answer += "HTTP/1.1 200 OK \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(length) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

void HttpClient::answerNotFound()
{
    QByteArray answer;
    answer += "HTTP/1.1 404 Not Found \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Connection: close \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

QUrl HttpClient::getMediaUrl(QString mediaType, int id, QString field)
{
    QSqlQuery query(Backend::instance()->mediaDatabase());
    query.setForwardOnly(true);

    QString queryString;
    queryString.append("SELECT * FROM " + mediaType);
    queryString.append(" WHERE id = " + QString::number(id) + "");
    query.prepare(queryString);

    if (!query.exec()) {
        qWarning("Error executing query: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    // we should have just one result set
    if (!query.next()) {
        qWarning("No records found: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    return QUrl::fromEncoded(query.record().value(field).toByteArray());
}

bool HttpClient::sendFile(QString fileName)
{
    int chunk = 1024*16;

    qDebug() << "start send file";

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);
    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    answerOk(m_file.size());

    QByteArray ba;
    ba.resize(chunk);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    if (m_socket->state() != QAbstractSocket::ConnectedState)
        qDebug() << "fully sent connection closed";

    return  true;
}

bool HttpClient::sendPartial(QString fileName, qint64 offset)
{
    int chunk = 1024*16;

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);

    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    qDebug() << "sendPartial offset" << offset;

    QByteArray ba;
    ba.resize(chunk);
    if (!m_file.seek(offset)) {
        qDebug() << "could not seek to offset";
        return false;
    }

    QByteArray answer = "";
    answer += "HTTP/1.1 206 Partial content \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(m_file.size()-offset) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Range: bytes " + QString::number(offset) + "-" + QString::number(m_file.size()-1) + "/" + QString::number(m_file.size()) + " \t\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    qDebug() << "sendPartial sent" << (m_socket->state() == QAbstractSocket::ConnectedState);

    return  true;
}
<commit_msg>make music seekable<commit_after>/****************************************************************************

This file is part of the QtMediaHub project on http://www.gitorious.org.

Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Nokia Corporation (qt-info@nokia.com)**

You may use this file under the terms of the BSD license as follows:

"Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."

****************************************************************************/

#include "httpclient.h"

#include <QtSql>

#include "backend.h"
#include "httpserver.h"

HttpClient::HttpClient(int sockfd, HttpServer *server, QObject *parent) :
    QObject(parent)
{
    m_server = server;
    m_socket = new QTcpSocket(this);
    if (!m_socket->setSocketDescriptor(sockfd)) {
        emit error(m_socket->error());
        return;
    }

    connect(m_socket, SIGNAL(readyRead()), this, SLOT(readClient()));
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(discardClient()));
}

void HttpClient::readClient()
{
    if (m_socket->canReadLine()) {
        QByteArray bytesRead = m_socket->readLine();
        QStringList tokens = QString(bytesRead).split(QRegExp("[ \r\n][ \r\n]*"));

        while(m_socket->canReadLine()) {
            bytesRead = m_socket->readLine();
            QList<QByteArray> lineTokens = bytesRead.split(':');
            if (lineTokens.size() == 2) {
                m_request.insert(lineTokens[0], lineTokens[1].trimmed().replace("\r\n",""));
            }
        }
        qDebug() << m_request;

        if (tokens[0] == "GET") {
            m_get = tokens[1];
            qDebug() << "GET" << m_get;
            if (m_get.startsWith("/video"))
                readVideoRequest();
            else if(m_get.startsWith("/music"))
                readMusicRequest();
            else if(m_get.startsWith("/picture"))
                readPictureRequest();
        }

    }

    m_socket->close();
    discardClient();

    return;
}

void HttpClient::discardClient()
{
    m_file.close();

    m_socket->deleteLater();
    emit disconnected();

    qDebug() << "Connection closed";
}

void HttpClient::readVideoRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);

    if (m_request.contains("Range")) {
        QString offsetString = m_request.value("Range");
        offsetString.remove(0, 6);
        qint64 offset = offsetString.split("-").at(0).toLongLong();
        sendPartial(getMediaUrl("video", id.toInt()).toLocalFile(), offset);
    } else {
        sendFile(getMediaUrl("video", id.toInt()).toLocalFile());
    }

    m_socket->close();
}

void HttpClient::readMusicRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);

    if (m_request.contains("Range")) {
        QString offsetString = m_request.value("Range");
        offsetString.remove(0, 6);
        qint64 offset = offsetString.split("-").at(0).toLongLong();
        sendPartial(getMediaUrl("music", id.toInt()).toLocalFile(), offset);
    } else {
        sendFile(getMediaUrl("music", id.toInt()).toLocalFile());
    }

    m_socket->close();
}

void HttpClient::readPictureRequest()
{
}

void HttpClient::answerOk(qint64 length)
{
    QByteArray answer;
    answer += "HTTP/1.1 200 OK \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(length) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

void HttpClient::answerNotFound()
{
    QByteArray answer;
    answer += "HTTP/1.1 404 Not Found \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Connection: close \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

QUrl HttpClient::getMediaUrl(QString mediaType, int id, QString field)
{
    QSqlQuery query(Backend::instance()->mediaDatabase());
    query.setForwardOnly(true);

    QString queryString;
    queryString.append("SELECT * FROM " + mediaType);
    queryString.append(" WHERE id = " + QString::number(id) + "");
    query.prepare(queryString);

    if (!query.exec()) {
        qWarning("Error executing query: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    // we should have just one result set
    if (!query.next()) {
        qWarning("No records found: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    return QUrl::fromEncoded(query.record().value(field).toByteArray());
}

bool HttpClient::sendFile(QString fileName)
{
    int chunk = 1024*16;

    qDebug() << "start send file";

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);
    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    answerOk(m_file.size());

    QByteArray ba;
    ba.resize(chunk);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    if (m_socket->state() != QAbstractSocket::ConnectedState)
        qDebug() << "fully sent connection closed";

    return  true;
}

bool HttpClient::sendPartial(QString fileName, qint64 offset)
{
    int chunk = 1024*16;

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);

    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    qDebug() << "sendPartial offset" << offset;

    QByteArray ba;
    ba.resize(chunk);
    if (!m_file.seek(offset)) {
        qDebug() << "could not seek to offset";
        return false;
    }

    QByteArray answer = "";
    answer += "HTTP/1.1 206 Partial content \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(m_file.size()-offset) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Range: bytes " + QString::number(offset) + "-" + QString::number(m_file.size()-1) + "/" + QString::number(m_file.size()) + " \t\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    qDebug() << "sendPartial sent" << (m_socket->state() == QAbstractSocket::ConnectedState);

    return  true;
}
<|endoftext|>