<commit_before>/* This file is part of Zanshin Todo.

   Copyright 2011 Christian Mollekopf <chrigi_1@fastmail.fm>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "incidenceitem.h"

#include <Akonadi/EntityDisplayAttribute>

#include <kcalcore/event.h>
#include <kcalcore/incidence.h>
#include <kcalcore/journal.h>
#include <kcalcore/todo.h>

template<class T>
T unwrap(const Akonadi::Item &item)
{
    Q_ASSERT(item.hasPayload<T>());
    return item.hasPayload<T>() ? item.payload<T>() : T();
}

IncidenceItem::IncidenceItem(AbstractPimItem::ItemType type, QObject *parent)
: AbstractPimItem(parent)
{
    KCalCore::Incidence *newItem = 0;
    if (type == AbstractPimItem::Todo) {
        newItem = new KCalCore::Todo();
    } else if (type == AbstractPimItem::Event) {
        newItem = new KCalCore::Event();
    }
    Q_ASSERT(newItem);
    KCalCore::Incidence::Ptr newPtr(newItem);
    m_item.setPayload<KCalCore::Incidence::Ptr>(newPtr);
    m_item.setMimeType(mimeType());
    commitData();
}

IncidenceItem::IncidenceItem(const Akonadi::Item &item, QObject *parent)
:   AbstractPimItem(item, parent)
{
    fetchData();
}

IncidenceItem::IncidenceItem(AbstractPimItem::ItemType type, AbstractPimItem &item, QObject* parent)
:   AbstractPimItem(item, parent)
{
    KCalCore::Incidence *newItem = 0;
    if (type == AbstractPimItem::Todo) {
        newItem = new KCalCore::Todo();
    } else if (type == AbstractPimItem::Event) {
        newItem = new KCalCore::Event();
    }
    Q_ASSERT(newItem);
    KCalCore::Incidence::Ptr newPtr(newItem);
    m_item.setPayload<KCalCore::Incidence::Ptr>(newPtr);
    m_item.setMimeType(mimeType());
    commitData();
}

void IncidenceItem::commitData()
{
    KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item);
    if (!old) {
        kDebug() << "invalid item, cannot commit data";
        return;
    }

    old->setDescription(m_text, m_textIsRich);
    old->setSummary(m_title, m_titleIsRich);
    if (m_creationDate.isValid()) {
        old->setCreated(m_creationDate);
    }

    m_item.setPayload<KCalCore::Incidence::Ptr>(old); //TODO probably not required (shared ptr)
    m_item.setMimeType(mimeType());

    //kDebug() << m_title;
    Akonadi::EntityDisplayAttribute *eda = new Akonadi::EntityDisplayAttribute();
    eda->setIconName(getIconName());
    eda->setDisplayName(m_title);
    m_item.addAttribute(eda);
}

bool IncidenceItem::hasValidPayload()
{
    return m_item.hasPayload<KCalCore::Incidence::Ptr>();
}

void IncidenceItem::fetchData()
{
    if (m_dataFetched) {
        //kDebug() << "payload already fetched";
        return;
    }

    if (!hasValidPayload()) {
        kDebug() << "invalid payload" << m_item.payloadData();
        return;
    }

    KCalCore::Incidence::Ptr inc = m_item.payload<KCalCore::Incidence::Ptr>();
    Q_ASSERT(inc);

    m_uid = inc->uid();
    m_title = inc->summary();
    m_titleIsRich = inc->summaryIsRich();
    m_text = inc->description();
    m_textIsRich = inc->descriptionIsRich();
    m_creationDate = inc->created();
    m_dataFetched = true;
}

QString IncidenceItem::mimeType()
{
    const KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item); //same as hasValidPayload + getting payload
    if (!old) {
        kWarning() << "invalid item";
        return QString();
    }
    return old->mimeType();
}

bool IncidenceItem::hasStartDate() const
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
    }
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        return t->dtStart().isValid();
    }
    return false;
}

KDateTime IncidenceItem::getEventStart()
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        return t->dtStart();
    }
    kWarning() << "not an event, or no start date";
    return KDateTime();
}

void IncidenceItem::setEventStart(const KDateTime &date)
{
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        t->setDtStart(date);
    }
}

void IncidenceItem::setParentTodo(const IncidenceItem &parent)
{
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        const KCalCore::Todo::Ptr p = unwrap<KCalCore::Todo::Ptr>(parent.getItem());
        t->setRelatedTo(p->uid());
    }
}

void IncidenceItem::setDueDate(const KDateTime &date, bool hasDueDate)
{
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        t->setDtDue(date);
        t->setHasDueDate(hasDueDate);
    }
}

KDateTime IncidenceItem::getDueDate()
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        if (t->hasDueDate()) {
            //kDebug() << "due date: " << t->dtDue();
            return t->dtDue();
        }
    }
    kWarning() << "not a todo, or no due date";
    return KDateTime();
}

bool IncidenceItem::hasDueDate() const
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        return t->hasDueDate();
    }
    return false;
}

/*
bool IncidenceItem::isComplete()
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        return t->isCompleted();
    }
    kWarning() << "not a todo";
    return false;
}

void IncidenceItem::setComplete(bool state)
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        return t->setCompleted(state);
    }
    kWarning() << "not a todo";
}*/

void IncidenceItem::setTodoStatus(AbstractPimItem::ItemStatus status)
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    //kDebug() << status;
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        switch (status) {
            case NotComplete:
                t->setCompleted(false);
                break;
            case Complete:
                t->setCompleted(true);
                break;
            case Later:
                t->setCompleted(false);
                t->setHasStartDate(false);
                break;
            case Now:
                t->setCompleted(false);
                t->setDtStart(KDateTime::currentLocalDateTime());
                break;
            default:
                kDebug() << "tried to set unhandled status: " << status;
        }
        return;
    }
    kWarning() << "not a todo";
}

AbstractPimItem::ItemStatus IncidenceItem::getStatus() const
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        if (t->isCompleted()) {
            //kDebug() << "iscomplete";
            return Complete;
        }
        if (t->hasStartDate() && (t->dtStart() <= KDateTime::currentLocalDateTime())) {
            //kDebug() << "Now";
            return Now;
        }
        if (t->hasDueDate() && (t->dtDue() <= KDateTime::currentLocalDateTime())) {
            return Attention;
        }
        //kDebug() << "Later";
        return Later;
    }
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        if (!t->dtStart().isValid() || t->dtStart() > KDateTime::currentLocalDateTime()) {
            return Later;
        }
        if (t->dtEnd() > KDateTime::currentLocalDateTime()) {
            return Now;
        }
        return Complete;
    }
    kWarning() << "not a todo/event";
    return Later;
}

KDateTime IncidenceItem::getPrimaryDate()
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
//        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        if (t->hasDueDate()) {
            //kDebug() << "due date: " << t->dtDue();
            return t->dtDue();
        } else {
            //kDebug() << "mod date: " << modificationTime();
            return getLastModifiedDate();
        }
    } else if ( const KCalCore::Event::Ptr e = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        //if ( !e->recurs() && !e->isMultiDay() ) {
            return e->dtStart();
        //}
    } else if ( const KCalCore::Journal::Ptr j = unwrap<KCalCore::Journal::Ptr>(m_item) ) {
        return j->dtStart();
    }
    kWarning() << "unknown item";
    return KDateTime();
}

QString IncidenceItem::getIconName()
{
    KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item);
    if (!old) {
        kWarning() << "invalid item";
        return QLatin1String( "network-wired" );
    }
    if ( old->type() == KCalCore::IncidenceBase::TypeTodo ) {
        return QLatin1String( "view-pim-tasks" );
    } else if ( old->type() == KCalCore::IncidenceBase::TypeJournal ) {
        return QLatin1String( "view-pim-journal" );
    } else if ( old->type() == KCalCore::IncidenceBase::TypeEvent ) {
        return QLatin1String( "view-calendar" );
    }
    kWarning() << "unknown item";
    return QLatin1String( "network-wired" );
}

AbstractPimItem::ItemType IncidenceItem::itemType()
{
    KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item);
    if (!old) {
        kWarning() << "invalid item";
        return AbstractPimItem::Incidence;
    }
    if ( old->type() == KCalCore::IncidenceBase::TypeTodo ) {
        return AbstractPimItem::Todo;
    } else if ( old->type() == KCalCore::IncidenceBase::TypeJournal ) {
        return AbstractPimItem::Journal;
    } else if ( old->type() == KCalCore::IncidenceBase::TypeEvent ) {
        return AbstractPimItem::Event;
    }
    return AbstractPimItem::Incidence;
}

void IncidenceItem::setRelations(const QList< PimItemRelation > &relations)
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    QMap<QByteArray, QString> map = i->customProperties();
    map.remove("X-pimitemrelation");
    i->removeNonKDECustomProperty("X-pimitemrelation");
    foreach (const PimItemRelation &rel, relations) {
        if (rel.parentNodes.isEmpty()) {
            continue;
        }
        if (rel.type == PimItemRelation::Project) {
            i->setRelatedTo(rel.parentNodes.first().uid);
        } else {
            map.insertMulti("X-pimitemrelation", relationToXML(rel));
        }
    }
    i->setCustomProperties(map);
}

QList< PimItemRelation > IncidenceItem::getRelations()
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    QList<PimItemRelation> relations;
    if (!i->relatedTo().isEmpty()) {
        relations << PimItemRelation(PimItemRelation::Project, QList<PimItemTreeNode>() << PimItemTreeNode(i->relatedTo().toUtf8()));
    }
    foreach(const QByteArray &key, i->customProperties().keys()) {
//         kDebug() <<  key << i->customProperties().value(key);
        if (key != "X-pimitemrelation") {
            continue;
        }
        const PimItemRelation &rel = relationFromXML(i->customProperties().value(key).toLatin1());
        relations << rel;
    }
    return relations;
}

void IncidenceItem::setCategories(const QStringList &categories)
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    i->setCategories(categories);
}

QStringList IncidenceItem::getCategories()
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    return i->categories();
}

void IncidenceItem::setProject()
{
    if (isProject()) {
        return;
    }
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    return  i->addComment("X-Zanshin-Project");
}

bool IncidenceItem::isProject() const
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    return  i->comments().contains("X-Zanshin-Project");
}

<commit_msg>Use a special property to set the project status and don't hijack the comment property.<commit_after>/* This file is part of Zanshin Todo.

   Copyright 2011 Christian Mollekopf <chrigi_1@fastmail.fm>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "incidenceitem.h"

#include <Akonadi/EntityDisplayAttribute>

#include <kcalcore/event.h>
#include <kcalcore/incidence.h>
#include <kcalcore/journal.h>
#include <kcalcore/todo.h>

template<class T>
T unwrap(const Akonadi::Item &item)
{
    Q_ASSERT(item.hasPayload<T>());
    return item.hasPayload<T>() ? item.payload<T>() : T();
}

IncidenceItem::IncidenceItem(AbstractPimItem::ItemType type, QObject *parent)
: AbstractPimItem(parent)
{
    KCalCore::Incidence *newItem = 0;
    if (type == AbstractPimItem::Todo) {
        newItem = new KCalCore::Todo();
    } else if (type == AbstractPimItem::Event) {
        newItem = new KCalCore::Event();
    }
    Q_ASSERT(newItem);
    KCalCore::Incidence::Ptr newPtr(newItem);
    m_item.setPayload<KCalCore::Incidence::Ptr>(newPtr);
    m_item.setMimeType(mimeType());
    commitData();
}

IncidenceItem::IncidenceItem(const Akonadi::Item &item, QObject *parent)
:   AbstractPimItem(item, parent)
{
    fetchData();
}

IncidenceItem::IncidenceItem(AbstractPimItem::ItemType type, AbstractPimItem &item, QObject* parent)
:   AbstractPimItem(item, parent)
{
    KCalCore::Incidence *newItem = 0;
    if (type == AbstractPimItem::Todo) {
        newItem = new KCalCore::Todo();
    } else if (type == AbstractPimItem::Event) {
        newItem = new KCalCore::Event();
    }
    Q_ASSERT(newItem);
    KCalCore::Incidence::Ptr newPtr(newItem);
    m_item.setPayload<KCalCore::Incidence::Ptr>(newPtr);
    m_item.setMimeType(mimeType());
    commitData();
}

void IncidenceItem::commitData()
{
    KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item);
    if (!old) {
        kDebug() << "invalid item, cannot commit data";
        return;
    }

    old->setDescription(m_text, m_textIsRich);
    old->setSummary(m_title, m_titleIsRich);
    if (m_creationDate.isValid()) {
        old->setCreated(m_creationDate);
    }

    m_item.setPayload<KCalCore::Incidence::Ptr>(old); //TODO probably not required (shared ptr)
    m_item.setMimeType(mimeType());

    //kDebug() << m_title;
    Akonadi::EntityDisplayAttribute *eda = new Akonadi::EntityDisplayAttribute();
    eda->setIconName(getIconName());
    eda->setDisplayName(m_title);
    m_item.addAttribute(eda);
}

bool IncidenceItem::hasValidPayload()
{
    return m_item.hasPayload<KCalCore::Incidence::Ptr>();
}

void IncidenceItem::fetchData()
{
    if (m_dataFetched) {
        //kDebug() << "payload already fetched";
        return;
    }

    if (!hasValidPayload()) {
        kDebug() << "invalid payload" << m_item.payloadData();
        return;
    }

    KCalCore::Incidence::Ptr inc = m_item.payload<KCalCore::Incidence::Ptr>();
    Q_ASSERT(inc);

    m_uid = inc->uid();
    m_title = inc->summary();
    m_titleIsRich = inc->summaryIsRich();
    m_text = inc->description();
    m_textIsRich = inc->descriptionIsRich();
    m_creationDate = inc->created();
    m_dataFetched = true;
}

QString IncidenceItem::mimeType()
{
    const KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item); //same as hasValidPayload + getting payload
    if (!old) {
        kWarning() << "invalid item";
        return QString();
    }
    return old->mimeType();
}

bool IncidenceItem::hasStartDate() const
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
    }
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        return t->dtStart().isValid();
    }
    return false;
}

KDateTime IncidenceItem::getEventStart()
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        return t->dtStart();
    }
    kWarning() << "not an event, or no start date";
    return KDateTime();
}

void IncidenceItem::setEventStart(const KDateTime &date)
{
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        t->setDtStart(date);
    }
}

void IncidenceItem::setParentTodo(const IncidenceItem &parent)
{
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        const KCalCore::Todo::Ptr p = unwrap<KCalCore::Todo::Ptr>(parent.getItem());
        t->setRelatedTo(p->uid());
    }
}

void IncidenceItem::setDueDate(const KDateTime &date, bool hasDueDate)
{
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        t->setDtDue(date);
        t->setHasDueDate(hasDueDate);
    }
}

KDateTime IncidenceItem::getDueDate()
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        if (t->hasDueDate()) {
            //kDebug() << "due date: " << t->dtDue();
            return t->dtDue();
        }
    }
    kWarning() << "not a todo, or no due date";
    return KDateTime();
}

bool IncidenceItem::hasDueDate() const
{
    if (!m_item.hasPayload()) {
        kWarning() << "no payload";
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        return t->hasDueDate();
    }
    return false;
}

/*
bool IncidenceItem::isComplete()
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        return t->isCompleted();
    }
    kWarning() << "not a todo";
    return false;
}

void IncidenceItem::setComplete(bool state)
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        return t->setCompleted(state);
    }
    kWarning() << "not a todo";
}*/

void IncidenceItem::setTodoStatus(AbstractPimItem::ItemStatus status)
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    //kDebug() << status;
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        switch (status) {
            case NotComplete:
                t->setCompleted(false);
                break;
            case Complete:
                t->setCompleted(true);
                break;
            case Later:
                t->setCompleted(false);
                t->setHasStartDate(false);
                break;
            case Now:
                t->setCompleted(false);
                t->setDtStart(KDateTime::currentLocalDateTime());
                break;
            default:
                kDebug() << "tried to set unhandled status: " << status;
        }
        return;
    }
    kWarning() << "not a todo";
}

AbstractPimItem::ItemStatus IncidenceItem::getStatus() const
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
        //        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        if (t->isCompleted()) {
            //kDebug() << "iscomplete";
            return Complete;
        }
        if (t->hasStartDate() && (t->dtStart() <= KDateTime::currentLocalDateTime())) {
            //kDebug() << "Now";
            return Now;
        }
        if (t->hasDueDate() && (t->dtDue() <= KDateTime::currentLocalDateTime())) {
            return Attention;
        }
        //kDebug() << "Later";
        return Later;
    }
    if ( const KCalCore::Event::Ptr t = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        if (!t->dtStart().isValid() || t->dtStart() > KDateTime::currentLocalDateTime()) {
            return Later;
        }
        if (t->dtEnd() > KDateTime::currentLocalDateTime()) {
            return Now;
        }
        return Complete;
    }
    kWarning() << "not a todo/event";
    return Later;
}

KDateTime IncidenceItem::getPrimaryDate()
{
    if (!m_item.hasPayload()) {
        kDebug() << "no payload";
//        fetchPayload(true);
    }
    if ( const KCalCore::Todo::Ptr t = unwrap<KCalCore::Todo::Ptr>(m_item) ) {
        if (t->hasDueDate()) {
            //kDebug() << "due date: " << t->dtDue();
            return t->dtDue();
        } else {
            //kDebug() << "mod date: " << modificationTime();
            return getLastModifiedDate();
        }
    } else if ( const KCalCore::Event::Ptr e = unwrap<KCalCore::Event::Ptr>(m_item) ) {
        //if ( !e->recurs() && !e->isMultiDay() ) {
            return e->dtStart();
        //}
    } else if ( const KCalCore::Journal::Ptr j = unwrap<KCalCore::Journal::Ptr>(m_item) ) {
        return j->dtStart();
    }
    kWarning() << "unknown item";
    return KDateTime();
}

QString IncidenceItem::getIconName()
{
    KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item);
    if (!old) {
        kWarning() << "invalid item";
        return QLatin1String( "network-wired" );
    }
    if ( old->type() == KCalCore::IncidenceBase::TypeTodo ) {
        return QLatin1String( "view-pim-tasks" );
    } else if ( old->type() == KCalCore::IncidenceBase::TypeJournal ) {
        return QLatin1String( "view-pim-journal" );
    } else if ( old->type() == KCalCore::IncidenceBase::TypeEvent ) {
        return QLatin1String( "view-calendar" );
    }
    kWarning() << "unknown item";
    return QLatin1String( "network-wired" );
}

AbstractPimItem::ItemType IncidenceItem::itemType()
{
    KCalCore::Incidence::Ptr old = unwrap<KCalCore::Incidence::Ptr>(m_item);
    if (!old) {
        kWarning() << "invalid item";
        return AbstractPimItem::Incidence;
    }
    if ( old->type() == KCalCore::IncidenceBase::TypeTodo ) {
        return AbstractPimItem::Todo;
    } else if ( old->type() == KCalCore::IncidenceBase::TypeJournal ) {
        return AbstractPimItem::Journal;
    } else if ( old->type() == KCalCore::IncidenceBase::TypeEvent ) {
        return AbstractPimItem::Event;
    }
    return AbstractPimItem::Incidence;
}

void IncidenceItem::setRelations(const QList< PimItemRelation > &relations)
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    QMap<QByteArray, QString> map = i->customProperties();
    map.remove("X-pimitemrelation");
    i->removeNonKDECustomProperty("X-pimitemrelation");
    foreach (const PimItemRelation &rel, relations) {
        if (rel.parentNodes.isEmpty()) {
            continue;
        }
        if (rel.type == PimItemRelation::Project) {
            i->setRelatedTo(rel.parentNodes.first().uid);
        } else {
            map.insertMulti("X-pimitemrelation", relationToXML(rel));
        }
    }
    i->setCustomProperties(map);
}

QList< PimItemRelation > IncidenceItem::getRelations()
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    QList<PimItemRelation> relations;
    if (!i->relatedTo().isEmpty()) {
        relations << PimItemRelation(PimItemRelation::Project, QList<PimItemTreeNode>() << PimItemTreeNode(i->relatedTo().toUtf8()));
    }
    foreach(const QByteArray &key, i->customProperties().keys()) {
//         kDebug() <<  key << i->customProperties().value(key);
        if (key != "X-pimitemrelation") {
            continue;
        }
        const PimItemRelation &rel = relationFromXML(i->customProperties().value(key).toLatin1());
        relations << rel;
    }
    return relations;
}

void IncidenceItem::setCategories(const QStringList &categories)
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    i->setCategories(categories);
}

QStringList IncidenceItem::getCategories()
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    return i->categories();
}

void IncidenceItem::setProject()
{
    if (isProject()) {
        return;
    }
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    i->setCustomProperty("Zanshin", "Project", "true");
}

bool IncidenceItem::isProject() const
{
    KCalCore::Incidence::Ptr i = unwrap<KCalCore::Incidence::Ptr>(m_item);
    if (i->comments().contains("X-Zanshin-Project")) {
        return true;
    }
    return !i->customProperty("Zanshin", "Project").isEmpty();
}

<|endoftext|>


<commit_before>/*
 * -----------------------------------------------------------------------------
 * This source file is part of OGRE
 * (Object-oriented Graphics Rendering Engine)
 * For the latest info, see http://www.ogre3d.org/
 *
 * Copyright (c) 2000-2013 Torus Knot Software Ltd
 *
 * 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 "OgreLodInputProvider.h"
#include "OgreLodData.h"

#include "OgreLogManager.h"

namespace Ogre
{

	void LodInputProvider::printTriangle(LodData::Triangle* triangle, stringstream& str)
{
	for (int i = 0; i < 3; i++) {
		str << (i + 1) << ". vertex position: ("
			<< triangle->vertex[i]->position.x << ", "
			<< triangle->vertex[i]->position.y << ", "
			<< triangle->vertex[i]->position.z << ") "
			<< "vertex ID: " << triangle->vertexID[i] << std::endl;
	}
}

bool LodInputProvider::isDuplicateTriangle(LodData::Triangle* triangle, LodData::Triangle* triangle2)
{
	for (int i = 0; i < 3; i++) {
		if (triangle->vertex[i] != triangle2->vertex[0] ||
			triangle->vertex[i] != triangle2->vertex[1] ||
			triangle->vertex[i] != triangle2->vertex[2]) {
				return false;
		}
	}
	return true;
}

LodData::Triangle* LodInputProvider::isDuplicateTriangle(LodData::Triangle* triangle)
{
	// duplicate triangle detection (where all vertices has the same position)
	LodData::VTriangles::iterator itEnd = triangle->vertex[0]->triangles.end();
	LodData::VTriangles::iterator it = triangle->vertex[0]->triangles.begin();
	for (; it != itEnd; it++) {
		LodData::Triangle* t = *it;
		if (isDuplicateTriangle(triangle, t)) {
			return *it;
		}
	}
	return NULL;
}
void LodInputProvider::addTriangleToEdges(LodData* data, LodData::Triangle* triangle)
{
	if(MESHLOD_QUALITY >= 3) {
		LodData::Triangle* duplicate = isDuplicateTriangle(triangle);
		if (duplicate != NULL) {
#if OGRE_DEBUG_MODE
			stringstream str;
			str << "In " << data->mMeshName << " duplicate triangle found." << std::endl;
			str << "Triangle " << LodData::getVectorIDFromPointer(data->mTriangleList, triangle) << " positions:" << std::endl;
			printTriangle(triangle, str);
			str << "Triangle " << LodData::getVectorIDFromPointer(data->mTriangleList, duplicate) << " positions:" << std::endl;
			printTriangle(duplicate, str);
			str << "Triangle " << LodData::getVectorIDFromPointer(data->mTriangleList, triangle) << " will be excluded from Lod level calculations.";
			LogManager::getSingleton().stream() << str;
#endif
			triangle->isRemoved = true;
			data->mIndexBufferInfoList[triangle->submeshID].indexCount -= 3;
			return;
		}
	}
	for (int i = 0; i < 3; i++) {
		triangle->vertex[i]->triangles.addNotExists(triangle);
	}
	for (int i = 0; i < 3; i++) {
		for (int n = 0; n < 3; n++) {
			if (i != n) {
				triangle->vertex[i]->addEdge(LodData::Edge(triangle->vertex[n]));
			}
		}
	}
}

}<commit_msg>Add as string to LogManager.<commit_after>/*
 * -----------------------------------------------------------------------------
 * This source file is part of OGRE
 * (Object-oriented Graphics Rendering Engine)
 * For the latest info, see http://www.ogre3d.org/
 *
 * Copyright (c) 2000-2013 Torus Knot Software Ltd
 *
 * 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 "OgreLodInputProvider.h"
#include "OgreLodData.h"

#include "OgreLogManager.h"

namespace Ogre
{

	void LodInputProvider::printTriangle(LodData::Triangle* triangle, stringstream& str)
{
	for (int i = 0; i < 3; i++) {
		str << (i + 1) << ". vertex position: ("
			<< triangle->vertex[i]->position.x << ", "
			<< triangle->vertex[i]->position.y << ", "
			<< triangle->vertex[i]->position.z << ") "
			<< "vertex ID: " << triangle->vertexID[i] << std::endl;
	}
}

bool LodInputProvider::isDuplicateTriangle(LodData::Triangle* triangle, LodData::Triangle* triangle2)
{
	for (int i = 0; i < 3; i++) {
		if (triangle->vertex[i] != triangle2->vertex[0] ||
			triangle->vertex[i] != triangle2->vertex[1] ||
			triangle->vertex[i] != triangle2->vertex[2]) {
				return false;
		}
	}
	return true;
}

LodData::Triangle* LodInputProvider::isDuplicateTriangle(LodData::Triangle* triangle)
{
	// duplicate triangle detection (where all vertices has the same position)
	LodData::VTriangles::iterator itEnd = triangle->vertex[0]->triangles.end();
	LodData::VTriangles::iterator it = triangle->vertex[0]->triangles.begin();
	for (; it != itEnd; it++) {
		LodData::Triangle* t = *it;
		if (isDuplicateTriangle(triangle, t)) {
			return *it;
		}
	}
	return NULL;
}
void LodInputProvider::addTriangleToEdges(LodData* data, LodData::Triangle* triangle)
{
	if(MESHLOD_QUALITY >= 3) {
		LodData::Triangle* duplicate = isDuplicateTriangle(triangle);
		if (duplicate != NULL) {
#if OGRE_DEBUG_MODE
			stringstream str;
			str << "In " << data->mMeshName << " duplicate triangle found." << std::endl;
			str << "Triangle " << LodData::getVectorIDFromPointer(data->mTriangleList, triangle) << " positions:" << std::endl;
			printTriangle(triangle, str);
			str << "Triangle " << LodData::getVectorIDFromPointer(data->mTriangleList, duplicate) << " positions:" << std::endl;
			printTriangle(duplicate, str);
			str << "Triangle " << LodData::getVectorIDFromPointer(data->mTriangleList, triangle) << " will be excluded from Lod level calculations.";
			LogManager::getSingleton().stream() << str.str();
#endif
			triangle->isRemoved = true;
			data->mIndexBufferInfoList[triangle->submeshID].indexCount -= 3;
			return;
		}
	}
	for (int i = 0; i < 3; i++) {
		triangle->vertex[i]->triangles.addNotExists(triangle);
	}
	for (int i = 0; i < 3; i++) {
		for (int n = 0; n < 3; n++) {
			if (i != n) {
				triangle->vertex[i]->addEdge(LodData::Edge(triangle->vertex[n]));
			}
		}
	}
}

}<|endoftext|>


<commit_before>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

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 the author 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.

*/

#ifndef TORRENT_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/packet_buffer.hpp"
#include "libtorrent/error_code.hpp"

#include <boost/bind.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>

#define CCONTROL_TARGET 100

namespace libtorrent
{
	struct utp_socket_manager;

	// the point of the bif_endian_int is two-fold
	// one purpuse is to not have any alignment requirements
	// so that any byffer received from the network can be cast
	// to it and read as an integer of various sizes without
	// triggering a bus error. The other purpose is to convert
	// from network byte order to host byte order when read and
	// written, to offer a convenient interface to both interpreting
	// and writing network packets
	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			const char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

	0       4       8               16              24              32
	+-------+-------+---------------+---------------+---------------+
	| ver   | type  | extension     | connection_id                 |
	+-------+-------+---------------+---------------+---------------+
	| timestamp_microseconds                                        |
	+---------------+---------------+---------------+---------------+
	| timestamp_difference_microseconds                             |
	+---------------+---------------+---------------+---------------+
	| wnd_size                                                      |
	+---------------+---------------+---------------+---------------+
	| seq_nr                        | ack_nr                        |
	+---------------+---------------+---------------+---------------+

*/

	enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };

	struct utp_header
	{
		unsigned char ver:4;
		unsigned char type:4;
		unsigned char extension;
		be_uint16 connection_id;
		be_uint32 timestamp_microseconds;
		be_uint32 timestamp_difference_microseconds;
		be_uint32 wnd_size;
		be_uint16 seq_nr;
		be_uint16 ack_nr;
	};

struct utp_socket_impl;

utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
	, boost::uint16_t send_id, void* userdata
	, utp_socket_manager* sm);
void detach_utp_impl(utp_socket_impl* s);
void delete_utp_impl(utp_socket_impl* s);
bool should_delete(utp_socket_impl* s);
void tick_utp_impl(utp_socket_impl* s, ptime const& now);
bool utp_incoming_packet(utp_socket_impl* s, char const* p
	, int size, udp::endpoint const& ep, ptime receive_time);
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id);
udp::endpoint utp_remote_endpoint(utp_socket_impl* s);
boost::uint16_t utp_receive_id(utp_socket_impl* s);
int utp_socket_state(utp_socket_impl const* s);

#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
int socket_impl_size();
#endif

// this is the user-level stream interface to utp sockets.
// the reason why it's split up in a utp_stream class and
// an implementation class is because the socket state has
// to be able to out-live the user level socket. For instance
// when sending data on a stream and then closing it, the
// state holding the send buffer has to be kept around until
// it has been flushed, which may be longer than the client
// will keep the utp_stream object around for.
// for more details, see utp_socket_impl, which is analogous
// to the kernel state for a socket. It's defined in utp_stream.cpp
class utp_stream
{
public:

	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit utp_stream(asio::io_service& io_service);
	~utp_stream();

	// used for incoming connections
	void set_impl(utp_socket_impl* s);
	utp_socket_impl* get_impl();

#ifndef BOOST_NO_EXCEPTIONS
	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc) {}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec) {}

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint) {}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec);

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt) {}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; }

	void close();
	void close(error_code const& ec) { close(); }
	bool is_open() const { return m_open; }

	int read_buffer_size() const;
	static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_connect(void* self, error_code const& ec, bool kill);

	typedef void(*handler_t)(void*, size_t, error_code const&, bool);
	typedef void(*connect_handler_t)(void*, error_code const&, bool);

	void add_read_buffer(void* buf, size_t len);
	void set_read_handler(handler_t h);
	void add_write_buffer(void const* buf, size_t len);
	void set_write_handler(handler_t h);
	size_t read_some(bool clear_buffers);

	void do_connect(tcp::endpoint const& ep, connect_handler_t h);

	endpoint_type local_endpoint() const
	{
		error_code ec;
		return local_endpoint(ec);
	}

	endpoint_type local_endpoint(error_code& ec) const;

	endpoint_type remote_endpoint() const
	{
		error_code ec;
		return remote_endpoint(ec);
	}

	endpoint_type remote_endpoint(error_code& ec) const;

	std::size_t available() const;
	std::size_t available(error_code& ec) const { return available(); }

	asio::io_service& io_service()
	{ return m_io_service; }

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		if (!endpoint.address().is_v4())
		{
			error_code ec = asio::error::operation_not_supported;
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		m_connect_handler = handler;
		do_connect(endpoint, &utp_stream::on_connect);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_read_handler);
		if (m_read_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}
		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
		}
		m_read_handler = handler;
		set_read_handler(&utp_stream::on_read);
	}

	void do_async_connect(endpoint_type const& ep
		, boost::function<void(error_code const&)> const& handler);

	template <class Protocol>
	void open(Protocol const& p, error_code& ec)
	{ m_open = true; }

	template <class Protocol>
	void open(Protocol const& p)
	{ m_open = true; }

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		TORRENT_ASSERT(!m_read_handler);
		if (m_impl == 0)
		{
			ec = asio::error::not_connected;
			return 0;
		}

		if (read_buffer_size() == 0)
		{
			ec = asio::error::would_block;
			return 0;
		}
#ifndef NDEBUG
		int buf_size = 0;
#endif

		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
#ifndef NDEBUG
			buf_size += buffer_size(*i);
#endif
		}
		std::size_t ret = read_some(true);
		TORRENT_ASSERT(ret <= buf_size);
		return ret;
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		// TODO: implement
		return 0;
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_write_handler);
		if (m_write_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		for (typename Const_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_write_buffer((void*)buffer_cast<void const*>(*i), buffer_size(*i));
		}
		m_write_handler = handler;
		set_write_handler(&utp_stream::on_write);
	}

//private:

	void cancel_handlers(error_code const&);

	boost::function1<void, error_code const&> m_connect_handler;
	boost::function2<void, error_code const&, std::size_t> m_read_handler;
	boost::function2<void, error_code const&, std::size_t> m_write_handler;

	asio::io_service& m_io_service;
	utp_socket_impl* m_impl;
	bool m_open;
};

}

#endif
<commit_msg>fixed minor utp typo<commit_after>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

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 the author 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.

*/

#ifndef TORRENT_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/packet_buffer.hpp"
#include "libtorrent/error_code.hpp"

#include <boost/bind.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>

#define CCONTROL_TARGET 100

namespace libtorrent
{
	struct utp_socket_manager;

	// the point of the bif_endian_int is two-fold
	// one purpuse is to not have any alignment requirements
	// so that any byffer received from the network can be cast
	// to it and read as an integer of various sizes without
	// triggering a bus error. The other purpose is to convert
	// from network byte order to host byte order when read and
	// written, to offer a convenient interface to both interpreting
	// and writing network packets
	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			const char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

	0       4       8               16              24              32
	+-------+-------+---------------+---------------+---------------+
	| ver   | type  | extension     | connection_id                 |
	+-------+-------+---------------+---------------+---------------+
	| timestamp_microseconds                                        |
	+---------------+---------------+---------------+---------------+
	| timestamp_difference_microseconds                             |
	+---------------+---------------+---------------+---------------+
	| wnd_size                                                      |
	+---------------+---------------+---------------+---------------+
	| seq_nr                        | ack_nr                        |
	+---------------+---------------+---------------+---------------+

*/

	enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };

	struct utp_header
	{
		unsigned char ver:4;
		unsigned char type:4;
		unsigned char extension;
		be_uint16 connection_id;
		be_uint32 timestamp_microseconds;
		be_uint32 timestamp_difference_microseconds;
		be_uint32 wnd_size;
		be_uint16 seq_nr;
		be_uint16 ack_nr;
	};

struct utp_socket_impl;

utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
	, boost::uint16_t send_id, void* userdata
	, utp_socket_manager* sm);
void detach_utp_impl(utp_socket_impl* s);
void delete_utp_impl(utp_socket_impl* s);
bool should_delete(utp_socket_impl* s);
void tick_utp_impl(utp_socket_impl* s, ptime const& now);
bool utp_incoming_packet(utp_socket_impl* s, char const* p
	, int size, udp::endpoint const& ep, ptime receive_time);
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id);
udp::endpoint utp_remote_endpoint(utp_socket_impl* s);
boost::uint16_t utp_receive_id(utp_socket_impl* s);
int utp_socket_state(utp_socket_impl const* s);

#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
int socket_impl_size();
#endif

// this is the user-level stream interface to utp sockets.
// the reason why it's split up in a utp_stream class and
// an implementation class is because the socket state has
// to be able to out-live the user level socket. For instance
// when sending data on a stream and then closing it, the
// state holding the send buffer has to be kept around until
// it has been flushed, which may be longer than the client
// will keep the utp_stream object around for.
// for more details, see utp_socket_impl, which is analogous
// to the kernel state for a socket. It's defined in utp_stream.cpp
class utp_stream
{
public:

	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit utp_stream(asio::io_service& io_service);
	~utp_stream();

	// used for incoming connections
	void set_impl(utp_socket_impl* s);
	utp_socket_impl* get_impl();

#ifndef BOOST_NO_EXCEPTIONS
	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc) {}
#endif

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, error_code& ec) {}

#ifndef BOOST_NO_EXCEPTIONS
	void bind(endpoint_type const& endpoint) {}
#endif

	void bind(endpoint_type const& endpoint, error_code& ec);

#ifndef BOOST_NO_EXCEPTIONS
	template <class SettableSocketOption>
	void set_option(SettableSocketOption const& opt) {}
#endif

	template <class SettableSocketOption>
	error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; }

	void close();
	void close(error_code const& ec) { close(); }
	bool is_open() const { return m_open; }

	int read_buffer_size() const;
	static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
	static void on_connect(void* self, error_code const& ec, bool kill);

	typedef void(*handler_t)(void*, size_t, error_code const&, bool);
	typedef void(*connect_handler_t)(void*, error_code const&, bool);

	void add_read_buffer(void* buf, size_t len);
	void set_read_handler(handler_t h);
	void add_write_buffer(void const* buf, size_t len);
	void set_write_handler(handler_t h);
	size_t read_some(bool clear_buffers);

	void do_connect(tcp::endpoint const& ep, connect_handler_t h);

	endpoint_type local_endpoint() const
	{
		error_code ec;
		return local_endpoint(ec);
	}

	endpoint_type local_endpoint(error_code& ec) const;

	endpoint_type remote_endpoint() const
	{
		error_code ec;
		return remote_endpoint(ec);
	}

	endpoint_type remote_endpoint(error_code& ec) const;

	std::size_t available() const;
	std::size_t available(error_code& ec) const { return available(); }

	asio::io_service& io_service()
	{ return m_io_service; }

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		if (!endpoint.address().is_v4())
		{
			error_code ec = asio::error::operation_not_supported;
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		m_connect_handler = handler;
		do_connect(endpoint, &utp_stream::on_connect);
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_read_handler);
		if (m_read_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}
		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
		}
		m_read_handler = handler;
		set_read_handler(&utp_stream::on_read);
	}

	void do_async_connect(endpoint_type const& ep
		, boost::function<void(error_code const&)> const& handler);

	template <class Protocol>
	void open(Protocol const& p, error_code& ec)
	{ m_open = true; }

	template <class Protocol>
	void open(Protocol const& p)
	{ m_open = true; }

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
	{
		TORRENT_ASSERT(!m_read_handler);
		if (m_impl == 0)
		{
			ec = asio::error::not_connected;
			return 0;
		}

		if (read_buffer_size() == 0)
		{
			ec = asio::error::would_block;
			return 0;
		}
#ifdef TORRENT_DEBUG
		int buf_size = 0;
#endif

		for (typename Mutable_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
#ifdef TORRENT_DEBUG
			buf_size += buffer_size(*i);
#endif
		}
		std::size_t ret = read_some(true);
		TORRENT_ASSERT(ret <= buf_size);
		return ret;
	}

	template <class Const_Buffers>
	std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
	{
		// TODO: implement
		return 0;
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		if (m_impl == 0)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
			return;
		}

		TORRENT_ASSERT(!m_write_handler);
		if (m_write_handler)
		{
			m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
			return;
		}

		for (typename Const_Buffers::const_iterator i = buffers.begin()
			, end(buffers.end()); i != end; ++i)
		{
			using asio::buffer_cast;
			using asio::buffer_size;
			add_write_buffer((void*)buffer_cast<void const*>(*i), buffer_size(*i));
		}
		m_write_handler = handler;
		set_write_handler(&utp_stream::on_write);
	}

//private:

	void cancel_handlers(error_code const&);

	boost::function1<void, error_code const&> m_connect_handler;
	boost::function2<void, error_code const&, std::size_t> m_read_handler;
	boost::function2<void, error_code const&, std::size_t> m_write_handler;

	asio::io_service& m_io_service;
	utp_socket_impl* m_impl;
	bool m_open;
};

}

#endif
<|endoftext|>


<commit_before>#include "core/tz.hpp"
#include "core/vector.hpp"
#include "core/matrix_transform.hpp"
#include "gl/device.hpp"
#include "gl/renderer.hpp"
#include "gl/resource.hpp"
#include "gl/input.hpp"
#include "gl/shader.hpp"

float get_aspect_ratio()
{
    return tz::window().get_width() / tz::window().get_height();
}

int main()
{
    tz::initialise({"tz_triangle_demo", tz::Version{1, 0, 0}, tz::info()});
    {
        tz::gl::DeviceBuilder device_builder;
        tz::gl::Device device{device_builder};

        tz::gl::ShaderBuilder shader_builder;
        shader_builder.set_shader_file(tz::gl::ShaderType::VertexShader, ".\\demo\\gl\\triangle_demo.vertex.tzsl");
        shader_builder.set_shader_file(tz::gl::ShaderType::FragmentShader, ".\\demo\\gl\\triangle_demo.fragment.tzsl");

        tz::gl::Shader shader = device.create_shader(shader_builder);

        tz::gl::RendererBuilder renderer_builder;
        tz::gl::Mesh mesh;
        mesh.vertices =
            {
                tz::gl::Vertex{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f}, {}, {}, {}},
                tz::gl::Vertex{{0.5f, -0.5f, 0.0f}, {0.0f, 0.0f}, {}, {}, {}},
                tz::gl::Vertex{{0.5f, 0.5f, 0.0f}, {0.0f, 1.0f}, {}, {}, {}}
            };
        mesh.indices = {0, 1, 2};
        tz::gl::MeshInput mesh_input{mesh};
        // Note: Window is resizeable but we don't amend the aspect-ratio if it does. This is for simplicity's sake -- This is done properly in tz_dynamic_triangle_demo.
        tz::gl::BufferResource buf_res{tz::gl::BufferData::from_array<tz::Mat4>
        ({{
            tz::model({0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}),
            tz::view({0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}),
            tz::perspective(1.27f, get_aspect_ratio(), 0.1f, 1000.0f)
        }})};

        renderer_builder.add_input(mesh_input);
        renderer_builder.set_output(tz::window());
        renderer_builder.add_resource(buf_res);
        renderer_builder.set_pass(tz::gl::RenderPassAttachment::Colour);
        renderer_builder.set_shader(shader);
        tz::gl::Renderer renderer = device.create_renderer(renderer_builder);
        renderer.set_clear_colour({0.1f, 0.2f, 0.4f, 1.0f});
        while(!tz::window().is_close_requested())
        {
            tz::window().update();
            renderer.render();
        }
    }
    tz::terminate();
}<commit_msg>* tz_triangle_demo is no longer resizeable<commit_after>#include "core/tz.hpp"
#include "core/vector.hpp"
#include "core/matrix_transform.hpp"
#include "gl/device.hpp"
#include "gl/renderer.hpp"
#include "gl/resource.hpp"
#include "gl/input.hpp"
#include "gl/shader.hpp"

float get_aspect_ratio()
{
    return tz::window().get_width() / tz::window().get_height();
}

int main()
{
    tz::WindowInitArgs wargs = tz::default_args;
    wargs.resizeable = false;
    tz::initialise({"tz_triangle_demo", tz::Version{1, 0, 0}, tz::info()}, tz::ApplicationType::WindowApplication, wargs);
    {
        tz::gl::DeviceBuilder device_builder;
        tz::gl::Device device{device_builder};

        tz::gl::ShaderBuilder shader_builder;
        shader_builder.set_shader_file(tz::gl::ShaderType::VertexShader, ".\\demo\\gl\\triangle_demo.vertex.tzsl");
        shader_builder.set_shader_file(tz::gl::ShaderType::FragmentShader, ".\\demo\\gl\\triangle_demo.fragment.tzsl");

        tz::gl::Shader shader = device.create_shader(shader_builder);

        tz::gl::RendererBuilder renderer_builder;
        tz::gl::Mesh mesh;
        mesh.vertices =
            {
                tz::gl::Vertex{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f}, {}, {}, {}},
                tz::gl::Vertex{{0.5f, -0.5f, 0.0f}, {0.0f, 0.0f}, {}, {}, {}},
                tz::gl::Vertex{{0.5f, 0.5f, 0.0f}, {0.0f, 1.0f}, {}, {}, {}}
            };
        mesh.indices = {0, 1, 2};
        tz::gl::MeshInput mesh_input{mesh};
        // Note: Window is resizeable but we don't amend the aspect-ratio if it does. This is for simplicity's sake -- This is done properly in tz_dynamic_triangle_demo.
        tz::gl::BufferResource buf_res{tz::gl::BufferData::from_array<tz::Mat4>
        ({{
            tz::model({0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}),
            tz::view({0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}),
            tz::perspective(1.27f, get_aspect_ratio(), 0.1f, 1000.0f)
        }})};

        renderer_builder.add_input(mesh_input);
        renderer_builder.set_output(tz::window());
        renderer_builder.add_resource(buf_res);
        renderer_builder.set_pass(tz::gl::RenderPassAttachment::Colour);
        renderer_builder.set_shader(shader);
        tz::gl::Renderer renderer = device.create_renderer(renderer_builder);
        renderer.set_clear_colour({0.1f, 0.2f, 0.4f, 1.0f});
        while(!tz::window().is_close_requested())
        {
            tz::window().update();
            renderer.render();
        }
    }
    tz::terminate();
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: invmerge.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: ihi $ $Date: 2006-11-14 15:57:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"

#include <vcl/window.hxx>
#include <tools/debug.hxx>

#include "invmerge.hxx"

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

ScInvertMerger::ScInvertMerger( Window* pWindow ) :
    pWin( pWindow ),
    pRects( NULL )
{
    //  both rectangles empty
}

ScInvertMerger::ScInvertMerger( ::std::vector< Rectangle >* pRectangles ) :
    pWin( NULL ),
    pRects( pRectangles )
{
    //  collect rectangles instead of inverting
}

ScInvertMerger::~ScInvertMerger()
{
    Flush();
}

void ScInvertMerger::Flush()
{
    FlushLine();
    FlushTotal();

    DBG_ASSERT( aLineRect.IsEmpty() && aTotalRect.IsEmpty(), "Flush: not empty" );

    if ( pRects )
    {
        //
        // also join vertically if there are non-adjacent columns involved
        //

        size_t nComparePos = 0;
        while ( nComparePos < pRects->size() )
        {
            Rectangle aCompRect = (*pRects)[nComparePos];
            sal_Int32 nBottom = aCompRect.Bottom();
            size_t nOtherPos = nComparePos + 1;

            while ( nOtherPos < pRects->size() )
            {
                Rectangle aOtherRect = (*pRects)[nOtherPos];
                if ( aOtherRect.Top() > nBottom + 1 )
                {
                    // rectangles are sorted, so we can stop searching
                    break;
                }
                if ( aOtherRect.Top() == nBottom + 1 &&
                     aOtherRect.Left() == aCompRect.Left() &&
                     aOtherRect.Right() == aCompRect.Right() )
                {
                    // extend first rectangle
                    nBottom = aOtherRect.Bottom();
                    aCompRect.Bottom() = nBottom;
                    (*pRects)[nComparePos].Bottom() = nBottom;

                    // remove second rectangle
                    pRects->erase( pRects->begin() + nOtherPos );

                    // continue at unmodified nOtherPos
                }
                else
                    ++nOtherPos;
            }

            ++nComparePos;
        }
    }
}

void ScInvertMerger::FlushTotal()
{
    if( aTotalRect.IsEmpty() )
        return;                         // nothing to do

    if ( pWin )
        pWin->Invert( aTotalRect, INVERT_HIGHLIGHT );
    else if ( pRects )
        pRects->push_back( aTotalRect );

    aTotalRect.SetEmpty();
}

void ScInvertMerger::FlushLine()
{
    if( aLineRect.IsEmpty() )
        return;                         // nothing to do

    if ( aTotalRect.IsEmpty() )
    {
        aTotalRect = aLineRect;         // start new total rect
    }
    else
    {
        if ( aLineRect.Left()  == aTotalRect.Left()  &&
             aLineRect.Right() == aTotalRect.Right() &&
             aLineRect.Top()   == aTotalRect.Bottom() + 1 )
        {
            // extend total rect
            aTotalRect.Bottom() = aLineRect.Bottom();
        }
        else
        {
            FlushTotal();                   // draw old total rect
            aTotalRect = aLineRect;         // and start new one
        }
    }

    aLineRect.SetEmpty();
}

void ScInvertMerger::AddRect( const Rectangle& rRect )
{
    if ( aLineRect.IsEmpty() )
    {
        aLineRect = rRect;          // start new line rect
    }
    else
    {
        Rectangle aJustified = rRect;
        if ( rRect.Left() > rRect.Right() )     // switch for RTL layout
        {
            aJustified.Left() = rRect.Right();
            aJustified.Right() = rRect.Left();
        }

        BOOL bDone = FALSE;
        if ( aJustified.Top()    == aLineRect.Top()    &&
             aJustified.Bottom() == aLineRect.Bottom() )
        {
            // try to extend line rect
            if ( aJustified.Left() == aLineRect.Right() + 1 )
            {
                aLineRect.Right() = aJustified.Right();
                bDone = TRUE;
            }
            else if ( aJustified.Right() + 1 == aLineRect.Left() )  // for RTL layout
            {
                aLineRect.Left() = aJustified.Left();
                bDone = TRUE;
            }
        }
        if (!bDone)
        {
            FlushLine();                // use old line rect for total rect
            aLineRect = aJustified;     // and start new one
        }
    }
}

<commit_msg>INTEGRATION: CWS calcselection (1.5.358); FILE MERGED 2008/02/13 13:56:00 nn 1.5.358.1: #i86069# transparent cell selection<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: invmerge.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2008-02-19 15:35:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"

#include <vcl/window.hxx>
#include <tools/debug.hxx>

#include "invmerge.hxx"

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

ScInvertMerger::ScInvertMerger( Window* pWindow ) :
    pWin( pWindow ),
    pRects( NULL )
{
    //  both rectangles empty
}

ScInvertMerger::ScInvertMerger( ::std::vector< Rectangle >* pRectangles ) :
    pWin( NULL ),
    pRects( pRectangles )
{
    //  collect rectangles instead of inverting
}

ScInvertMerger::~ScInvertMerger()
{
    Flush();
}

void ScInvertMerger::Flush()
{
    FlushLine();
    FlushTotal();

    DBG_ASSERT( aLineRect.IsEmpty() && aTotalRect.IsEmpty(), "Flush: not empty" );

    if ( pRects )
    {
        //
        // also join vertically if there are non-adjacent columns involved
        //

        size_t nComparePos = 0;
        while ( nComparePos < pRects->size() )
        {
            Rectangle aCompRect = (*pRects)[nComparePos];
            sal_Int32 nBottom = aCompRect.Bottom();
            size_t nOtherPos = nComparePos + 1;

            while ( nOtherPos < pRects->size() )
            {
                Rectangle aOtherRect = (*pRects)[nOtherPos];
                if ( aOtherRect.Top() > nBottom + 1 )
                {
                    // rectangles are sorted, so we can stop searching
                    break;
                }
                if ( aOtherRect.Top() == nBottom + 1 &&
                     aOtherRect.Left() == aCompRect.Left() &&
                     aOtherRect.Right() == aCompRect.Right() )
                {
                    // extend first rectangle
                    nBottom = aOtherRect.Bottom();
                    aCompRect.Bottom() = nBottom;
                    (*pRects)[nComparePos].Bottom() = nBottom;

                    // remove second rectangle
                    pRects->erase( pRects->begin() + nOtherPos );

                    // continue at unmodified nOtherPos
                }
                else
                    ++nOtherPos;
            }

            ++nComparePos;
        }
    }
}

void ScInvertMerger::FlushTotal()
{
    if( aTotalRect.IsEmpty() )
        return;                         // nothing to do

    if ( pWin )
        pWin->Invert( aTotalRect, INVERT_HIGHLIGHT );
    else if ( pRects )
        pRects->push_back( aTotalRect );

    aTotalRect.SetEmpty();
}

void ScInvertMerger::FlushLine()
{
    if( aLineRect.IsEmpty() )
        return;                         // nothing to do

    if ( aTotalRect.IsEmpty() )
    {
        aTotalRect = aLineRect;         // start new total rect
    }
    else
    {
        if ( aLineRect.Left()  == aTotalRect.Left()  &&
             aLineRect.Right() == aTotalRect.Right() &&
             aLineRect.Top()   == aTotalRect.Bottom() + 1 )
        {
            // extend total rect
            aTotalRect.Bottom() = aLineRect.Bottom();
        }
        else
        {
            FlushTotal();                   // draw old total rect
            aTotalRect = aLineRect;         // and start new one
        }
    }

    aLineRect.SetEmpty();
}

void ScInvertMerger::AddRect( const Rectangle& rRect )
{
    Rectangle aJustified = rRect;
    if ( rRect.Left() > rRect.Right() )     // switch for RTL layout
    {
        aJustified.Left() = rRect.Right();
        aJustified.Right() = rRect.Left();
    }

    if ( aLineRect.IsEmpty() )
    {
        aLineRect = aJustified;             // start new line rect
    }
    else
    {
        BOOL bDone = FALSE;
        if ( aJustified.Top()    == aLineRect.Top()    &&
             aJustified.Bottom() == aLineRect.Bottom() )
        {
            // try to extend line rect
            if ( aJustified.Left() == aLineRect.Right() + 1 )
            {
                aLineRect.Right() = aJustified.Right();
                bDone = TRUE;
            }
            else if ( aJustified.Right() + 1 == aLineRect.Left() )  // for RTL layout
            {
                aLineRect.Left() = aJustified.Left();
                bDone = TRUE;
            }
        }
        if (!bDone)
        {
            FlushLine();                // use old line rect for total rect
            aLineRect = aJustified;     // and start new one
        }
    }
}

<|endoftext|>


<commit_before>/*
 * CategoryStream.hh
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#ifndef _LOG4CPP_CATEGORYSTREAM_HH
#define _LOG4CPP_CATEGORYSTREAM_HH

#include <log4cpp/Portability.hh>
#include <log4cpp/Priority.hh>
#ifdef LOG4CPP_HAVE_SSTREAM
#include <sstream>
#endif

namespace log4cpp {

    class LOG4CPP_EXPORT Category;

    /**
     * This class enables streaming simple types and objects to a category.
     * Use category.errorStream(), etc. to obtain a CategoryStream class.
     **/
    class LOG4CPP_EXPORT CategoryStream {
        public:

        /**
         * Enumeration of special 'Separators'. Currently only contains the
         * 'ENDLINE' separator, which separates two log messages.
         **/
        typedef enum {
            ENDLINE
        } Separator;

        /**
         * Construct a CategoryStream for given Category with given priority.
         * @param category The category this stream will send log messages to.
         * @param priority The priority the log messages will get or
         * Priority::NOTSET to silently discard any streamed in messages.
         **/
        CategoryStream(Category& category, Priority::Value priority);

        /**
         * Destructor for CategoryStream
         **/
        ~CategoryStream();

        /**
         * Returns the destination Category for this stream.
         * @returns The Category.
         **/
        inline Category& getCategory() const { return _category; };

        /**
         * Returns the priority for this stream.
         * @returns The priority.
         **/
        inline Priority::Value getPriority() const throw() {
            return _priority;
        };

        /**
         * Streams in a Separator. If the separator equals
         * CategoryStream::ENDLINE it sends the contents of the stream buffer
         * to the Category with set priority and empties the buffer.
         * @param separator The Separator
         * @returns A reference to itself.
         **/
        CategoryStream& operator<<(Separator separator);

        /**
         * Flush the contents of the stream buffer to the Category and
         * empties the buffer.
         **/
        void flush();

        /**
         * Stream in arbitrary types and objects.
         * @param t The value or object to stream in.
         * @returns A reference to itself.
         **/
        template<typename T> CategoryStream& operator<<(const T& t) {
            if (getPriority() != Priority::NOTSET) {
                if (!_buffer) {
                    if (!(_buffer = new std::ostringstream)) {
                        // XXX help help help
                    }
                }
                (*_buffer) << t;
            }
            return *this;
        }

        private:
        Category& _category;
        Priority::Value _priority;
        std::ostringstream* _buffer;
    };

}
#endif // _LOG4CPP_CATEGORYSTREAM_HH
<commit_msg>Add CategoryStream::width() member Add alias of EOL, eol as ENDOFLINE<commit_after>/*
 * CategoryStream.hh
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#ifndef _LOG4CPP_CATEGORYSTREAM_HH
#define _LOG4CPP_CATEGORYSTREAM_HH

#include <log4cpp/Portability.hh>
#include <log4cpp/Priority.hh>
#include <ios>
#ifdef LOG4CPP_HAVE_SSTREAM
#include <sstream>
#endif

namespace log4cpp {

    class LOG4CPP_EXPORT Category;

    /**
     * This class enables streaming simple types and objects to a category.
     * Use category.errorStream(), etc. to obtain a CategoryStream class.
     **/
    class LOG4CPP_EXPORT CategoryStream {
        public:

        /**
         * Enumeration of special 'Separators'. Currently only contains the
         * 'ENDLINE' separator, which separates two log messages.
         **/
        typedef enum {
            ENDLINE = 0,
			EOL		= 0,
			eol		= 0
        } Separator;

        /**
         * Construct a CategoryStream for given Category with given priority.
         * @param category The category this stream will send log messages to.
         * @param priority The priority the log messages will get or
         * Priority::NOTSET to silently discard any streamed in messages.
         **/
        CategoryStream(Category& category, Priority::Value priority);

        /**
         * Destructor for CategoryStream
         **/
        ~CategoryStream();

        /**
         * Returns the destination Category for this stream.
         * @returns The Category.
         **/
        inline Category& getCategory() const { return _category; };

        /**
         * Returns the priority for this stream.
         * @returns The priority.
         **/
        inline Priority::Value getPriority() const throw() {
            return _priority;
        };

        /**
         * Streams in a Separator. If the separator equals
         * CategoryStream::ENDLINE it sends the contents of the stream buffer
         * to the Category with set priority and empties the buffer.
         * @param separator The Separator
         * @returns A reference to itself.
         **/
        CategoryStream& operator<<(Separator separator);

        /**
         * Flush the contents of the stream buffer to the Category and
         * empties the buffer.
         **/
        void flush();

        /**
         * Stream in arbitrary types and objects.
         * @param t The value or object to stream in.
         * @returns A reference to itself.
         **/
        template<typename T> CategoryStream& operator<<(const T& t) {
            if (getPriority() != Priority::NOTSET) {
                if (!_buffer) {
                    if (!(_buffer = new std::ostringstream)) {
                        // XXX help help help
                    }
                }
                (*_buffer) << t;
            }
            return *this;
        }
		std::streamsize width(std::streamsize wide ) {
            if (getPriority() != Priority::NOTSET) {
                if (!_buffer) {
                    if (!(_buffer = new std::ostringstream)) {
                        // XXX help help help
                    }
                }
            }
			return _buffer->width(wide);
		}
        CategoryStream& left() {
			_buffer->setf(std::ios_base::left, std::ios_base::adjustfield);
			return *this;
		}

        private:
        Category& _category;
        Priority::Value _priority;
        std::ostringstream* _buffer;
    };

}
#endif // _LOG4CPP_CATEGORYSTREAM_HH
<|endoftext|>