コード例 #1
0
ファイル: MessageView.cpp プロジェクト: G-shadow/trojita
void MessageView::deleteLabelAction(const QString &tag)
{
    if (!message.isValid())
        return;

    Imap::Mailbox::Model *model = dynamic_cast<Imap::Mailbox::Model *>(const_cast<QAbstractItemModel *>(message.model()));
    model->setMessageFlags(QModelIndexList() << message, tag, Imap::Mailbox::FLAG_REMOVE);
}
コード例 #2
0
ファイル: MessageView.cpp プロジェクト: G-shadow/trojita
void MessageView::markAsRead()
{
    if (!message.isValid())
        return;
    Imap::Mailbox::Model *model = const_cast<Imap::Mailbox::Model *>(dynamic_cast<const Imap::Mailbox::Model *>(message.model()));
    Q_ASSERT(model);
    if (!model->isNetworkAvailable())
        return;
    if (!message.data(Imap::Mailbox::RoleMessageIsMarkedRead).toBool())
        model->markMessagesRead(QModelIndexList() << message, Imap::Mailbox::FLAG_ADD);
}
コード例 #3
0
/** @short Instruct the Model that the data it has cached for a particular message is no longer needed */
void MessageDownloader::slotFreeProcessedMessages()
{
    Q_FOREACH(const QPersistentModelIndex &index, m_messagesToBeFreed) {
        if (!index.isValid())
            continue;
        // The const_cast should be safe here -- this action is certainly not going to invalidate the index,
        // and even the releaseMessageData() won't (directly) touch its members anyway...
        Imap::Mailbox::Model *model = qobject_cast<Imap::Mailbox::Model*>(const_cast<QAbstractItemModel*>(index.model()));
        Q_ASSERT(model);
#ifdef DEBUG_PENDING_MESSAGES
        qDebug() << "Freeing memory for" << index.parent().parent().data(Imap::Mailbox::RoleMailboxName).toString() <<
                    "UID" << index.data(Imap::Mailbox::RoleMessageUid).toUInt();
#endif
        model->releaseMessageData(index);
    }
    m_messagesToBeFreed.clear();
}
コード例 #4
0
ファイル: MessageView.cpp プロジェクト: G-shadow/trojita
void MessageView::setMessage(const QModelIndex &index)
{
    // first, let's get a real model
    QModelIndex messageIndex;
    const Imap::Mailbox::Model *constModel = 0;
    Imap::Mailbox::TreeItem *item = Imap::Mailbox::Model::realTreeItem(index, &constModel, &messageIndex);
    Q_ASSERT(item); // Make sure it's a message
    Q_ASSERT(messageIndex.isValid());
    Imap::Mailbox::Model *realModel = const_cast<Imap::Mailbox::Model *>(constModel);
    Q_ASSERT(realModel);

    // The data might be available from the local cache, so let's try to save a possible roundtrip here
    item->fetch(realModel);

    if (!messageIndex.data(Imap::Mailbox::RoleIsFetched).toBool()) {
        // This happens when the message placeholder is already available in the GUI, but the actual message data haven't been
        // loaded yet. This is especially common with the threading model.
        // Note that the data might be already available in the cache, it's just that it isn't in the mailbox tree yet.
        setEmpty();
        connect(realModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(handleDataChanged(QModelIndex,QModelIndex)));
        message = messageIndex;
        return;
    }

    QModelIndex rootPartIndex = messageIndex.child(0, 0);

    headerSection->show();
    if (message != messageIndex) {
        emptyView->hide();
        layout->removeWidget(viewer);
        if (viewer != emptyView) {
            viewer->setParent(0);
            viewer->deleteLater();
        }
        message = messageIndex;
        netAccess->setExternalsEnabled(false);
        externalElements->hide();

        netAccess->setModelMessage(message);

        m_loadingItems.clear();
        m_loadingSpinner->stop();

        PartWidgetFactory::PartLoadingOptions loadingMode;
        if (m_settings->value(Common::SettingsNames::guiPreferPlaintextRendering, QVariant(true)).toBool())
            loadingMode |= PartWidgetFactory::PART_PREFER_PLAINTEXT_OVER_HTML;
        viewer = factory->create(rootPartIndex, 0, loadingMode);
        viewer->setParent(this);
        layout->addWidget(viewer);
        viewer->show();
        m_envelope->setMessage(message);

        tags->show();
        tags->setTagList(messageIndex.data(Imap::Mailbox::RoleMessageFlags).toStringList());
        disconnect(this, SLOT(handleDataChanged(QModelIndex,QModelIndex)));
        connect(realModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(handleDataChanged(QModelIndex,QModelIndex)));

        emit messageChanged();

        // We want to propagate the QWheelEvent to upper layers
        viewer->installEventFilter(this);
    }

    if (realModel->isNetworkAvailable())
        markAsReadTimer->start(200); // FIXME: make this configurable
}
コード例 #5
0
QWidget *PartWidgetFactory::create(const QModelIndex &partIndex, int recursionDepth, const PartLoadingMode loadingMode)
{
    using namespace Imap::Mailbox;
    Q_ASSERT(partIndex.isValid());

    if (recursionDepth > 1000) {
        return new QLabel(tr("This message contains too deep nesting of MIME message parts.\n"
                             "To prevent stack exhaustion and your head from exploding, only\n"
                             "the top-most thousand items or so are shown."), 0);
    }

    bool userPrefersPlaintext = QSettings().value(Common::SettingsNames::guiPreferPlaintextRendering, QVariant(true)).toBool();

    QString mimeType = partIndex.data(Imap::Mailbox::RolePartMimeType).toString();
    if (mimeType.startsWith(QLatin1String("multipart/"))) {
        // it's a compound part
        if (mimeType == QLatin1String("multipart/alternative")) {
            return new MultipartAlternativeWidget(0, this, partIndex, recursionDepth,
                                                  userPrefersPlaintext ?
                                                      QLatin1String("text/plain") :
                                                      QLatin1String("text/html"));
        } else if (mimeType == QLatin1String("multipart/signed")) {
            return new MultipartSignedWidget(0, this, partIndex, recursionDepth);
        } else if (mimeType == QLatin1String("multipart/related")) {
            // The purpose of this section is to find a text/html e-mail, along with its associated body parts, and hide
            // everything else than the HTML widget.

            // At this point, it might be interesting to somehow respect the user's preference about using text/plain
            // instead of text/html. However, things are a bit complicated; the widget used at this point really wants
            // to either show just a single part or alternatively all of them in a sequence.
            // Furthermore, if someone sends a text/plain and a text/html together inside a multipart/related, they're
            // just wrong.

            // Let's see if we know what the root part is
            QModelIndex mainPartIndex;
            QVariant mainPartCID = partIndex.data(RolePartMultipartRelatedMainCid);
            if (mainPartCID.isValid()) {
                const Imap::Mailbox::Model *constModel = 0;
                Imap::Mailbox::TreeItemPart *part = dynamic_cast<Imap::Mailbox::TreeItemPart *>(Imap::Mailbox::Model::realTreeItem(partIndex, &constModel));
                Imap::Mailbox::Model *model = const_cast<Imap::Mailbox::Model *>(constModel);
                Imap::Mailbox::TreeItemPart *mainPartPtr = Imap::Network::MsgPartNetAccessManager::cidToPart(mainPartCID.toByteArray(), model, part);
                if (mainPartPtr) {
                    mainPartIndex = mainPartPtr->toIndex(model);
                }
            }

            if (!mainPartIndex.isValid()) {
                // The Content-Type-based start parameter was not terribly useful. Let's find the HTML part manually.
                QModelIndex candidate = partIndex.child(0, 0);
                while (candidate.isValid()) {
                    if (candidate.data(RolePartMimeType).toString() == QLatin1String("text/html")) {
                        mainPartIndex = candidate;
                        break;
                    }
                    candidate = candidate.sibling(candidate.row() + 1, 0);
                }
            }

            if (mainPartIndex.isValid()) {
                if (mainPartIndex.data(RolePartMimeType).toString() == QLatin1String("text/html")) {
                    return PartWidgetFactory::create(mainPartIndex, recursionDepth+1);
                } else {
                    // Sorry, but anything else than text/html is by definition suspicious here. Better than picking some random
                    // choice, let's just show everything.
                    return new GenericMultipartWidget(0, this, partIndex, recursionDepth);
                }
            } else {
                // The RFC2387's wording is clear that in absence of an explicit START argument, the first part is the starting one.
                // On the other hand, I've seen real-world messages whose first part is some utter garbage (an image sent as
                // application/octet-stream, for example) and some *other* part is an HTML text. In that case (and if we somehow
                // failed to pick the HTML part by a heuristic), it's better to show everything.
                return new GenericMultipartWidget(0, this, partIndex, recursionDepth);
            }
        } else {
            return new GenericMultipartWidget(0, this, partIndex, recursionDepth);
        }
    } else if (mimeType == QLatin1String("message/rfc822")) {
        return new Message822Widget(0, this, partIndex, recursionDepth);
    } else {
        QStringList allowedMimeTypes;
        allowedMimeTypes << "text/html" << "text/plain" << "image/jpeg" <<
                         "image/jpg" << "image/pjpeg" << "image/png" << "image/gif";
        // The problem is that some nasty MUAs (hint hint Thunderbird) would
        // happily attach a .tar.gz and call it "inline"
        bool showInline = partIndex.data(Imap::Mailbox::RolePartBodyDisposition).toByteArray().toLower() != "attachment" &&
                          allowedMimeTypes.contains(mimeType);

        if (showInline) {
            const Imap::Mailbox::Model *constModel = 0;
            Imap::Mailbox::TreeItemPart *part = dynamic_cast<Imap::Mailbox::TreeItemPart *>(Imap::Mailbox::Model::realTreeItem(partIndex, &constModel));
            Imap::Mailbox::Model *model = const_cast<Imap::Mailbox::Model *>(constModel);
            Q_ASSERT(model);
            Q_ASSERT(part);
            part->fetchFromCache(model);

            bool showDirectly = loadingMode == LOAD_IMMEDIATELY;
            if (!part->fetched())
                showDirectly &= model->isNetworkOnline() || part->octets() <= ExpensiveFetchThreshold;

            QWidget *widget = 0;
            if (showDirectly) {
                widget = new SimplePartWidget(0, manager, partIndex, m_messageView);
            } else if (model->isNetworkAvailable() || part->fetched()) {
                widget = new LoadablePartWidget(0, manager, partIndex, m_messageView,
                                                loadingMode == LOAD_ON_SHOW && part->octets() <= ExpensiveFetchThreshold ?
                                                    LoadablePartWidget::LOAD_ON_SHOW :
                                                    LoadablePartWidget::LOAD_ON_CLICK);
            } else {
                widget = new QLabel(tr("Offline"), 0);
            }
            return widget;
        } else {
            return new AttachmentView(0, manager, partIndex);
        }
    }
    QLabel *lbl = new QLabel(mimeType, 0);
    return lbl;
}