Beispiel #1
0
Collection HandlerHelper::collectionFromIdOrName(const QByteArray &id)
{
    // id is a number
    bool ok = false;
    qint64 collectionId = id.toLongLong(&ok);
    if (ok) {
        return Collection::retrieveById(collectionId);
    }

    // id is a path
    QString path = QString::fromUtf8(id);   // ### should be UTF-7 for real IMAP compatibility

    const QStringList pathParts = path.split(QLatin1Char('/'), QString::SkipEmptyParts);
    Collection col;
    for (const QString &part : pathParts) {
        SelectQueryBuilder<Collection> qb;
        qb.addValueCondition(Collection::nameColumn(), Query::Equals, part);
        if (col.isValid()) {
            qb.addValueCondition(Collection::parentIdColumn(), Query::Equals, col.id());
        } else {
            qb.addValueCondition(Collection::parentIdColumn(), Query::Is, QVariant());
        }
        if (!qb.exec()) {
            return Collection();
        }
        Collection::List list = qb.result();
        if (list.count() != 1) {
            return Collection();
        }
        col = list.first();
    }
    return col;
}
void CalendarBaseTest::fetchCollection()
{
    CollectionFetchJob *job = new CollectionFetchJob(Collection::root(),
            CollectionFetchJob::Recursive,
            this);
    // Get list of collections
    job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.event"));
    AKVERIFYEXEC(job);

    // Find our collection
    Collection::List collections = job->collections();
    QVERIFY(!collections.isEmpty());
    mCollection = collections.first();

    QVERIFY(mCollection.isValid());
}
void IncidenceChanger::Private::onCollectionsLoaded(KJob *job)
{
    Q_ASSERT(!mPendingCreations.isEmpty());
    if (job->error() != 0 || !m_collectionFetchJob) {
        qCritical() << "Error loading collections:" << job->errorString();
        return;
    }

    Q_ASSERT(job == m_collectionFetchJob);
    Akonadi::Collection::List allCollections;
    foreach (const Akonadi::Collection &collection, m_collectionFetchJob->collections()) {
        if (collection.rights() & Akonadi::Collection::CanCreateItem) {
            allCollections << collection;
        }
    }

    m_collectionFetchJob = Q_NULLPTR;
    bool canceled = false;

    // These two will never be true, maybe even assert
    bool noAcl = false;
    bool invalidCollection = false;
    Collection collectionToUse;
    foreach (const Change::Ptr &change, mPendingCreations) {
        mPendingCreations.removeAll(change);

        if (canceled) {
            change->resultCode = ResultCodeUserCanceled;
            continue;
        }

        if (noAcl) {
            change->resultCode = ResultCodePermissions;
            continue;
        }

        if (invalidCollection) {
            change->resultCode = ResultCodeInvalidUserCollection;
            continue;
        }

        if (collectionToUse.isValid()) {
            // We don't show the dialog multiple times
            step2CreateIncidence(change, collectionToUse);
            continue;
        }

        KCalCore::Incidence::Ptr incidence = CalendarUtils::incidence(change->newItem);
        Collection::List candidateCollections = collectionsForMimeType(incidence->mimeType(), allCollections);
        if (candidateCollections.count() == 1 && candidateCollections.first().isValid()) {
            // We only have 1 writable collection, don't bother the user with a dialog
            collectionToUse = candidateCollections.first();
            qCDebug(AKONADICALENDAR_LOG) << "Only one collection exists, will not show collection dialog: " << collectionToUse.displayName();
            step2CreateIncidence(change, collectionToUse);
            continue;
        }

        // Lets ask the user which collection to use:
        int dialogCode;
        QWidget *parent = change->parentWidget;

        const QStringList mimeTypes(incidence->mimeType());
        collectionToUse = CalendarUtils::selectCollection(parent, /*by-ref*/dialogCode,
                          mimeTypes, mDefaultCollection);
        if (dialogCode != QDialog::Accepted) {
            qCDebug(AKONADICALENDAR_LOG) << "User canceled collection choosing";
            change->resultCode = ResultCodeUserCanceled;
            canceled = true;
            cancelTransaction();
            continue;
        }

        if (collectionToUse.isValid() && !hasRights(collectionToUse, ChangeTypeCreate)) {
            qCWarning(AKONADICALENDAR_LOG) << "No ACLs for incidence creation";
            const QString errorMessage = showErrorDialog(ResultCodePermissions, parent);
            change->resultCode = ResultCodePermissions;
            change->errorString = errorMessage;
            noAcl = true;
            cancelTransaction();
            continue;
        }

        // TODO: add unit test for these two situations after reviewing API
        if (!collectionToUse.isValid()) {
            qCritical() << "Invalid collection selected. Can't create incidence.";
            change->resultCode = ResultCodeInvalidUserCollection;
            const QString errorString = showErrorDialog(ResultCodeInvalidUserCollection, parent);
            change->errorString = errorString;
            invalidCollection = true;
            cancelTransaction();
            continue;
        }

        step2CreateIncidence(change, collectionToUse);
    }
void ActionStateManager::updateState(const Collection::List &collections, const Item::List &items)
{
    const int collectionCount = collections.count();
    const bool singleCollectionSelected = (collectionCount == 1);
    const bool multipleCollectionsSelected = (collectionCount > 1);
    const bool atLeastOneCollectionSelected = (singleCollectionSelected || multipleCollectionsSelected);

    const int itemCount = items.count();
    const bool singleItemSelected = (itemCount == 1);
    const bool multipleItemsSelected = (itemCount > 1);
    const bool atLeastOneItemSelected = (singleItemSelected || multipleItemsSelected);

    const bool listOfCollectionNotEmpty = collections.isEmpty() ? false : true;
    bool canDeleteCollections = listOfCollectionNotEmpty;
    if (canDeleteCollections) {
        foreach (const Collection &collection, collections) {
            // do we have the necessary rights?
            if (!(collection.rights() &Collection::CanDeleteCollection)) {
                canDeleteCollections = false;
                break;
            }

            if (isRootCollection(collection)) {
                canDeleteCollections = false;
                break;
            }

            if (isResourceCollection(collection)) {
                canDeleteCollections = false;
                break;
            }
        }
    }

    bool canCutCollections = canDeleteCollections; // we must be able to delete for cutting
    foreach (const Collection &collection, collections) {
        if (isSpecialCollection(collection)) {
            canCutCollections = false;
            break;
        }

        if (!isFolderCollection(collection)) {
            canCutCollections = false;
            break;
        }
    }

    const bool canMoveCollections = canCutCollections; // we must be able to cut for moving

    bool canCopyCollections = listOfCollectionNotEmpty;
    if (canCopyCollections) {
        foreach (const Collection &collection, collections) {
            if (isRootCollection(collection)) {
                canCopyCollections = false;
                break;
            }

            if (!isFolderCollection(collection)) {
                canCopyCollections = false;
                break;
            }
        }
    }
    bool canAddToFavoriteCollections = listOfCollectionNotEmpty;
    if (canAddToFavoriteCollections) {
        foreach (const Collection &collection, collections) {
            if (isRootCollection(collection)) {
                canAddToFavoriteCollections = false;
                break;
            }

            if (isFavoriteCollection(collection)) {
                canAddToFavoriteCollections = false;
                break;
            }

            if (!isFolderCollection(collection)) {
                canAddToFavoriteCollections = false;
                break;
            }

            if (!canContainItems(collection)) {
                canAddToFavoriteCollections = false;
                break;
            }
        }
    }
    bool canRemoveFromFavoriteCollections = listOfCollectionNotEmpty;
    foreach (const Collection &collection, collections) {
        if (!isFavoriteCollection(collection)) {
            canRemoveFromFavoriteCollections = false;
            break;
        }
    }

    bool collectionsAreFolders = listOfCollectionNotEmpty;

    foreach (const Collection &collection, collections) {
        if (!isFolderCollection(collection)) {
            collectionsAreFolders = false;
            break;
        }
    }

    bool collectionsAreInTrash = false;
    foreach (const Collection &collection, collections) {
        if (collection.hasAttribute<EntityDeletedAttribute>()) {
            collectionsAreInTrash = true;
            break;
        }
    }

    bool atLeastOneCollectionCanHaveItems = false;
    foreach (const Collection &collection, collections) {
        if (collectionCanHaveItems(collection)) {
            atLeastOneCollectionCanHaveItems = true;
            break;
        }
    }

    const Collection collection = (!collections.isEmpty() ? collections.first() : Collection());

    // collection specific actions
    enableAction(StandardActionManager::CreateCollection, singleCollectionSelected &&  // we can create only inside one collection
                 canCreateSubCollection(collection));    // we need the necessary rights

    enableAction(StandardActionManager::DeleteCollections, canDeleteCollections);

    enableAction(StandardActionManager::CopyCollections, canCopyCollections);

    enableAction(StandardActionManager::CutCollections, canCutCollections);

    enableAction(StandardActionManager::CopyCollectionToMenu, canCopyCollections);

    enableAction(StandardActionManager::MoveCollectionToMenu, canMoveCollections);

    enableAction(StandardActionManager::MoveCollectionsToTrash, atLeastOneCollectionSelected && canMoveCollections && !collectionsAreInTrash);

    enableAction(StandardActionManager::RestoreCollectionsFromTrash, atLeastOneCollectionSelected && canMoveCollections && collectionsAreInTrash);

    enableAction(StandardActionManager::CopyCollectionToDialog, canCopyCollections);

    enableAction(StandardActionManager::MoveCollectionToDialog, canMoveCollections);

    enableAction(StandardActionManager::CollectionProperties, singleCollectionSelected &&  // we can only configure one collection at a time
                 !isRootCollection(collection));    // we can not configure the root collection

    enableAction(StandardActionManager::SynchronizeCollections, atLeastOneCollectionCanHaveItems);   // it must be a valid folder collection

    enableAction(StandardActionManager::SynchronizeCollectionsRecursive, atLeastOneCollectionSelected &&
                 collectionsAreFolders);  // it must be a valid folder collection
#ifndef QT_NO_CLIPBOARD
    enableAction(StandardActionManager::Paste, singleCollectionSelected &&  // we can paste only into a single collection
                 PasteHelper::canPaste(QApplication::clipboard()->mimeData(), collection));    // there must be data on the clipboard
#else
    enableAction(StandardActionManager::Paste, false);   // no support for clipboard -> no paste
#endif

    // favorite collections specific actions
    enableAction(StandardActionManager::AddToFavoriteCollections, canAddToFavoriteCollections);

    enableAction(StandardActionManager::RemoveFromFavoriteCollections, canRemoveFromFavoriteCollections);

    enableAction(StandardActionManager::RenameFavoriteCollection, singleCollectionSelected &&  // we can rename only one collection at a time
                 isFavoriteCollection(collection));    // it must be a favorite collection already

    // resource specific actions
    int resourceCollectionCount = 0;
    bool canDeleteResources = true;
    bool canConfigureResource = true;
    bool canSynchronizeResources = true;
    foreach (const Collection &collection, collections) {
        if (isResourceCollection(collection)) {
            resourceCollectionCount++;

            // check that the 'NoConfig' flag is not set for the resource
            if (hasResourceCapability(collection, QStringLiteral("NoConfig"))) {
                canConfigureResource = false;
            }
        } else {
            // we selected a non-resource collection
            canDeleteResources = false;
            canConfigureResource = false;
            canSynchronizeResources = false;
        }
    }

    if (resourceCollectionCount == 0) {
        // not a single resource collection has been selected
        canDeleteResources = false;
        canConfigureResource = false;
        canSynchronizeResources = false;
    }

    enableAction(StandardActionManager::CreateResource, true);
    enableAction(StandardActionManager::DeleteResources, canDeleteResources);
    enableAction(StandardActionManager::ResourceProperties, canConfigureResource);
    enableAction(StandardActionManager::SynchronizeResources, canSynchronizeResources);
    enableAction(StandardActionManager::SynchronizeCollectionTree, canSynchronizeResources);

    if (collectionsAreInTrash) {
        updateAlternatingAction(StandardActionManager::MoveToTrashRestoreCollectionAlternative);
        //updatePluralLabel( StandardActionManager::MoveToTrashRestoreCollectionAlternative, collectionCount );
    } else {
        updateAlternatingAction(StandardActionManager::MoveToTrashRestoreCollection);
    }
    enableAction(StandardActionManager::MoveToTrashRestoreCollection, atLeastOneCollectionSelected && canMoveCollections);

    // item specific actions
    bool canDeleteItems = (!items.isEmpty());   //TODO: fixme
    foreach (const Item &item, items) {
        const Collection parentCollection = item.parentCollection();
        if (!parentCollection.isValid()) {
            continue;
        }

        canDeleteItems = canDeleteItems && (parentCollection.rights() &Collection::CanDeleteItem);
    }

    bool itemsAreInTrash = false;
    foreach (const Item &item, items) {
        if (item.hasAttribute<EntityDeletedAttribute>()) {
            itemsAreInTrash = true;
            break;
        }
    }

    enableAction(StandardActionManager::CopyItems, atLeastOneItemSelected);   // we need items to work with

    enableAction(StandardActionManager::CutItems, atLeastOneItemSelected &&  // we need items to work with
                 canDeleteItems);  // we need the necessary rights

    enableAction(StandardActionManager::DeleteItems, atLeastOneItemSelected &&  // we need items to work with
                 canDeleteItems);  // we need the necessary rights

    enableAction(StandardActionManager::CopyItemToMenu, atLeastOneItemSelected);   // we need items to work with

    enableAction(StandardActionManager::MoveItemToMenu, atLeastOneItemSelected &&  // we need items to work with
                 canDeleteItems);  // we need the necessary rights

    enableAction(StandardActionManager::MoveItemsToTrash, atLeastOneItemSelected && canDeleteItems && !itemsAreInTrash);

    enableAction(StandardActionManager::RestoreItemsFromTrash, atLeastOneItemSelected && itemsAreInTrash);

    enableAction(StandardActionManager::CopyItemToDialog, atLeastOneItemSelected);   // we need items to work with

    enableAction(StandardActionManager::MoveItemToDialog, atLeastOneItemSelected &&  // we need items to work with
                 canDeleteItems);  // we need the necessary rights

    if (itemsAreInTrash) {
        updateAlternatingAction(StandardActionManager::MoveToTrashRestoreItemAlternative);
        //updatePluralLabel( StandardActionManager::MoveToTrashRestoreItemAlternative, itemCount );
    } else {
        updateAlternatingAction(StandardActionManager::MoveToTrashRestoreItem);
    }
    enableAction(StandardActionManager::MoveToTrashRestoreItem, atLeastOneItemSelected &&  // we need items to work with
                 canDeleteItems);  // we need the necessary rights

    // update the texts of the actions
    updatePluralLabel(StandardActionManager::CopyCollections, collectionCount);
    updatePluralLabel(StandardActionManager::CopyItems, itemCount);
    updatePluralLabel(StandardActionManager::DeleteItems, itemCount);
    updatePluralLabel(StandardActionManager::CutItems, itemCount);
    updatePluralLabel(StandardActionManager::CutCollections, collectionCount);
    updatePluralLabel(StandardActionManager::DeleteCollections, collectionCount);
    updatePluralLabel(StandardActionManager::SynchronizeCollections, collectionCount);
    updatePluralLabel(StandardActionManager::SynchronizeCollectionsRecursive, collectionCount);
    updatePluralLabel(StandardActionManager::DeleteResources, resourceCollectionCount);
    updatePluralLabel(StandardActionManager::SynchronizeResources, resourceCollectionCount);
    updatePluralLabel(StandardActionManager::SynchronizeCollectionTree, resourceCollectionCount);

}
    // TODO: test signals
    void testMove()
    {
        QFETCH( Collection, source );
        QFETCH( Collection, destination );
        QFETCH( bool, crossResource );
        QVERIFY( source.isValid() );
        QVERIFY( destination.isValid() );

        CollectionFetchJob *fetch = new CollectionFetchJob( source, CollectionFetchJob::Base, this );
        AKVERIFYEXEC( fetch );
        QCOMPARE( fetch->collections().count(), 1 );
        source = fetch->collections().first();

        // obtain reference listing
        fetch = new CollectionFetchJob( source, CollectionFetchJob::Recursive );
        AKVERIFYEXEC( fetch );
        QHash<Collection, Item::List> referenceData;
        foreach ( const Collection &c, fetch->collections() ) {
            ItemFetchJob *job = new ItemFetchJob( c, this );
            AKVERIFYEXEC( job );
            referenceData.insert( c, job->items() );
        }

        // move collection
        CollectionMoveJob *mod = new CollectionMoveJob( source, destination, this );
        AKVERIFYEXEC( mod );

        // check if source was modified correctly
        CollectionFetchJob *ljob = new CollectionFetchJob( source, CollectionFetchJob::Base );
        AKVERIFYEXEC( ljob );
        Collection::List list = ljob->collections();

        QCOMPARE( list.count(), 1 );
        Collection col = list.first();
        QCOMPARE( col.name(), source.name() );
        QCOMPARE( col.parentCollection(), destination );

        // list destination and check if everything is still there
        ljob = new CollectionFetchJob( destination, CollectionFetchJob::Recursive );
        AKVERIFYEXEC( ljob );
        list = ljob->collections();

        QVERIFY( list.count() >= referenceData.count() );
        for ( QHash<Collection, Item::List>::ConstIterator it = referenceData.constBegin(); it != referenceData.constEnd(); ++it ) {
            QVERIFY( list.contains( it.key() ) );
            if ( crossResource ) {
                QVERIFY( list[ list.indexOf( it.key() ) ].resource() != it.key().resource() );
            } else {
                QCOMPARE( list[ list.indexOf( it.key() ) ].resource(), it.key().resource() );
            }
            ItemFetchJob *job = new ItemFetchJob( it.key(), this );
            job->fetchScope().fetchFullPayload();
            AKVERIFYEXEC( job );
            QCOMPARE( job->items().count(), it.value().count() );
            foreach ( const Item &item, job->items() ) {
                QVERIFY( it.value().contains( item ) );
                QVERIFY( item.hasPayload() );
            }
        }

        // cleanup
        mod = new CollectionMoveJob( col, source.parentCollection(), this );
        AKVERIFYEXEC( mod );
    }