<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#include "ElemLiteralResult.hpp"

#include <algorithm>

#include <sax/AttributeList.hpp>
#include <sax/SAXException.hpp>

#include <PlatformSupport/DoubleSupport.hpp>
#include <PlatformSupport/StringTokenizer.hpp>
#include <PlatformSupport/STLHelper.hpp>

#include <DOMSupport/DOMServices.hpp>

#include "AVT.hpp"
#include "Constants.hpp"
#include "Stylesheet.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"

ElemLiteralResult::ElemLiteralResult(
			StylesheetConstructionContext&	constructionContext,
			Stylesheet&						stylesheetTree,
			const XalanDOMString&			name,
			const AttributeList&			atts,
			int								lineNumber,
			int								columnNumber,
			int								xslToken) :
	ElemUse(constructionContext,
			stylesheetTree,
			name,
			lineNumber,
			columnNumber,
			xslToken),
	m_avts(),
	m_namespacesHandler(stylesheetTree.getNamespacesHandler(),
						stylesheetTree.getNamespaces(),
						stylesheetTree.getXSLTNamespaceURI())
{
	const unsigned int	nAttrs = atts.getLength();

	m_avts.reserve(nAttrs);

	for(unsigned int i = 0; i < nAttrs; i++)
	{
		const XalanDOMChar*	const	aname = atts.getName(i);

		bool						needToProcess = true;
		const unsigned int			indexOfNSSep = indexOf(aname, XalanUnicode::charColon);

		XalanDOMString				prefix;

		if(indexOfNSSep < length(aname))
		{
			prefix = substring(aname, 0, indexOfNSSep);

			if(!equals(prefix, DOMServices::s_XMLNamespace))
			{
				const XalanDOMString	ns = getNamespaceForPrefix(prefix);

				if(equals(ns, stylesheetTree.getXSLTNamespaceURI()))
				{
					const XalanDOMString localName = substring(aname,indexOfNSSep + 1);

					if(processPrefixControl(constructionContext, stylesheetTree, localName, atts.getValue(i)) == true)
					{
						needToProcess = false;
					}
					else if (equals(localName, Constants::ATTRNAME_VERSION) == true)
					{
						const XalanDOMChar*	const	value = atts.getValue(i);

						stylesheetTree.setXSLTVerDeclared(DoubleSupport::toDouble(value));
					}
				}
			}
			else
			{
				// don't process namespace decls
				needToProcess = false;
			}
		}

		if(needToProcess == true)
		{
			processSpaceAttr(aname, atts, i);

			// Add xmlns attribute(except xmlns:xsl), xml:space, etc...
			// Ignore anything with xsl:xxx
			if(! processUseAttributeSets(constructionContext, aname, atts, i) &&
					isAttrOK(aname, atts, i, constructionContext))
			{
				m_avts.push_back(new AVT(aname, atts.getType(i), atts.getValue(i),
							*this, constructionContext));
			}
		}
	}

	// Shrink the vector of AVTS, if necessary...
	if (m_avts.capacity() > m_avts.size())
	{
		// Make a copy that's the exact size, and
		// swap the two...
		AVTVectorType(m_avts).swap(m_avts);
	}
}

ElemLiteralResult::~ElemLiteralResult()
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::for_each;
#endif

	// Clean up all entries in the vector.
	for_each(m_avts.begin(),
			 m_avts.end(),
			 DeleteFunctor<AVT>());
}

const NamespacesHandler&
ElemLiteralResult::getNamespacesHandler() const
{
	return m_namespacesHandler;
}

void
ElemLiteralResult::postConstruction(const NamespacesHandler&	theParentHandler)
{
	const XalanDOMString&	theElementName = getElementName();
	assert(length(theElementName) > 0);

	const unsigned int		indexOfNSSep = indexOf(theElementName, XalanUnicode::charColon);

	const XalanDOMString	thePrefix = indexOfNSSep < length(theElementName) ?
					substring(theElementName, 0, indexOfNSSep) : XalanDOMString();

	m_namespacesHandler.postConstruction(thePrefix, &theParentHandler);

	ElemUse::postConstruction(m_namespacesHandler);
}

void
ElemLiteralResult::execute(
			StylesheetExecutionContext&		executionContext,
			XalanNode*						sourceTree,
			XalanNode*						sourceNode,
			const QName&					mode) const
{
	executionContext.startElement(toCharArray(getElementName()));

	ElemUse::execute(executionContext, sourceTree, sourceNode, mode);

	if(0 != m_avts.size())
	{
		const AVTVectorType::size_type	nAttrs = m_avts.size();

		for(AVTVectorType::size_type i = 0; i < nAttrs; i++)
		{
			const AVT* const	avt = m_avts[i];

			XalanDOMString	theStringedValue;

			avt->evaluate(theStringedValue, sourceNode, *this, executionContext);

			if(isEmpty(theStringedValue) == false)
			{
				XalanDOMString		thePrefix;

				const XalanDOMString&	theName = avt->getName();

				if (startsWith(theName, DOMServices::s_XMLNamespaceWithSeparator) == true)
				{
					thePrefix = substring(theName, DOMServices::s_XMLNamespaceWithSeparatorLength);
				}

				if (isEmpty(thePrefix) == true ||
				    shouldExcludeResultNamespaceNode(
						thePrefix,
						theStringedValue) == false)
				{
					executionContext.replacePendingAttribute(
						c_wstr(avt->getName()),
						c_wstr(avt->getType()),
						c_wstr(theStringedValue));
				}
			}
		}
	}

	m_namespacesHandler.outputResultNamespaces(executionContext);

	executeChildren(executionContext, sourceTree, sourceNode, mode);

	executionContext.endElement(toCharArray(getElementName()));
}

bool
ElemLiteralResult::isAttrOK(
			int						tok,
			const XalanDOMChar*		attrName,
			const AttributeList&	atts,
			int						which) const
{
	return ElemUse::isAttrOK(tok, attrName, atts, which);
}

bool
ElemLiteralResult::isAttrOK(
			const XalanDOMChar*				attrName,
			const AttributeList&			/* atts */,
			int								/* which */,
			StylesheetConstructionContext&	constructionContext) const
{
    bool	isAttrOK = equals(attrName, DOMServices::s_XMLNamespace) ||
					   startsWith(attrName, DOMServices::s_XMLNamespaceWithSeparator);

    if(isAttrOK == false)
    {
		const unsigned int	indexOfNSSep = indexOf(attrName, XalanUnicode::charColon);

		if(indexOfNSSep < length(attrName))
		{
			const XalanDOMString	prefix = substring(attrName, 0, indexOfNSSep);

			const XalanDOMString	ns = getStylesheet().getNamespaceForPrefixFromStack(prefix);

			if (equals(ns, constructionContext.getXSLTNamespaceURI()) == false)
			{
				isAttrOK = true;
			}
		}
		else
		{
			// An empty namespace is OK.
			isAttrOK = true;
		}
    }

    // TODO: Well, process it...
    return isAttrOK;
}

bool
ElemLiteralResult::processPrefixControl(
			StylesheetConstructionContext&	constructionContext,
			const Stylesheet&				stylesheetTree,
			const XalanDOMString&			localName,
			const XalanDOMString&			attrValue)
{
	if(equals(localName, Constants::ATTRNAME_EXTENSIONELEMENTPREFIXES))
	{
		m_namespacesHandler.processExtensionElementPrefixes(c_wstr(attrValue), stylesheetTree.getNamespaces(), constructionContext);

		return true;
	}
	else if (equals(localName, Constants::ATTRNAME_EXCLUDE_RESULT_PREFIXES))
	{
		m_namespacesHandler.processExcludeResultPrefixes(c_wstr(attrValue), stylesheetTree.getNamespaces(), constructionContext);

		return true;
	}
	else
	{
		return false;
	}
}

bool
ElemLiteralResult::shouldExcludeResultNamespaceNode(
			const XalanDOMString&	thePrefix,
			const XalanDOMString&	theURI) const
{
	return m_namespacesHandler.shouldExcludeResultNamespaceNode(
				getStylesheet().getXSLTNamespaceURI(),
				thePrefix,
				theURI);
}
<commit_msg>Fixed bug with calling NamespacesHandler::postConstruction(). (lre15)<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#include "ElemLiteralResult.hpp"

#include <algorithm>

#include <sax/AttributeList.hpp>
#include <sax/SAXException.hpp>

#include <PlatformSupport/DoubleSupport.hpp>
#include <PlatformSupport/StringTokenizer.hpp>
#include <PlatformSupport/STLHelper.hpp>

#include <DOMSupport/DOMServices.hpp>

#include "AVT.hpp"
#include "Constants.hpp"
#include "Stylesheet.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"

ElemLiteralResult::ElemLiteralResult(
			StylesheetConstructionContext&	constructionContext,
			Stylesheet&						stylesheetTree,
			const XalanDOMString&			name,
			const AttributeList&			atts,
			int								lineNumber,
			int								columnNumber,
			int								xslToken) :
	ElemUse(constructionContext,
			stylesheetTree,
			name,
			lineNumber,
			columnNumber,
			xslToken),
	m_avts(),
	m_namespacesHandler(stylesheetTree.getNamespacesHandler(),
						stylesheetTree.getNamespaces(),
						stylesheetTree.getXSLTNamespaceURI())
{
	const unsigned int	nAttrs = atts.getLength();

	m_avts.reserve(nAttrs);

	for(unsigned int i = 0; i < nAttrs; i++)
	{
		const XalanDOMChar*	const	aname = atts.getName(i);

		bool						needToProcess = true;
		const unsigned int			indexOfNSSep = indexOf(aname, XalanUnicode::charColon);

		XalanDOMString				prefix;

		if(indexOfNSSep < length(aname))
		{
			prefix = substring(aname, 0, indexOfNSSep);

			if(!equals(prefix, DOMServices::s_XMLNamespace))
			{
				const XalanDOMString	ns = getNamespaceForPrefix(prefix);

				if(equals(ns, stylesheetTree.getXSLTNamespaceURI()))
				{
					const XalanDOMString localName = substring(aname,indexOfNSSep + 1);

					if(processPrefixControl(constructionContext, stylesheetTree, localName, atts.getValue(i)) == true)
					{
						needToProcess = false;
					}
					else if (equals(localName, Constants::ATTRNAME_VERSION) == true)
					{
						const XalanDOMChar*	const	value = atts.getValue(i);

						stylesheetTree.setXSLTVerDeclared(DoubleSupport::toDouble(value));
					}
				}
			}
			else
			{
				// don't process namespace decls
				needToProcess = false;
			}
		}

		if(needToProcess == true)
		{
			processSpaceAttr(aname, atts, i);

			// Add xmlns attribute(except xmlns:xsl), xml:space, etc...
			// Ignore anything with xsl:xxx
			if(! processUseAttributeSets(constructionContext, aname, atts, i) &&
					isAttrOK(aname, atts, i, constructionContext))
			{
				m_avts.push_back(new AVT(aname, atts.getType(i), atts.getValue(i),
							*this, constructionContext));
			}
		}
	}

	// Shrink the vector of AVTS, if necessary...
	if (m_avts.capacity() > m_avts.size())
	{
		// Make a copy that's the exact size, and
		// swap the two...
		AVTVectorType(m_avts).swap(m_avts);
	}
}

ElemLiteralResult::~ElemLiteralResult()
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::for_each;
#endif

	// Clean up all entries in the vector.
	for_each(m_avts.begin(),
			 m_avts.end(),
			 DeleteFunctor<AVT>());
}

const NamespacesHandler&
ElemLiteralResult::getNamespacesHandler() const
{
	return m_namespacesHandler;
}

void
ElemLiteralResult::postConstruction(const NamespacesHandler&	theParentHandler)
{
	m_namespacesHandler.postConstruction(getElementName(), &theParentHandler);

	ElemUse::postConstruction(m_namespacesHandler);
}

void
ElemLiteralResult::execute(
			StylesheetExecutionContext&		executionContext,
			XalanNode*						sourceTree,
			XalanNode*						sourceNode,
			const QName&					mode) const
{
	executionContext.startElement(toCharArray(getElementName()));

	ElemUse::execute(executionContext, sourceTree, sourceNode, mode);

	if(0 != m_avts.size())
	{
		const AVTVectorType::size_type	nAttrs = m_avts.size();

		for(AVTVectorType::size_type i = 0; i < nAttrs; i++)
		{
			const AVT* const	avt = m_avts[i];

			XalanDOMString	theStringedValue;

			avt->evaluate(theStringedValue, sourceNode, *this, executionContext);

			if(isEmpty(theStringedValue) == false)
			{
				XalanDOMString		thePrefix;

				const XalanDOMString&	theName = avt->getName();

				if (startsWith(theName, DOMServices::s_XMLNamespaceWithSeparator) == true)
				{
					thePrefix = substring(theName, DOMServices::s_XMLNamespaceWithSeparatorLength);
				}

				if (isEmpty(thePrefix) == true ||
				    shouldExcludeResultNamespaceNode(
						thePrefix,
						theStringedValue) == false)
				{
					executionContext.replacePendingAttribute(
						c_wstr(avt->getName()),
						c_wstr(avt->getType()),
						c_wstr(theStringedValue));
				}
			}
		}
	}

	m_namespacesHandler.outputResultNamespaces(executionContext);

	executeChildren(executionContext, sourceTree, sourceNode, mode);

	executionContext.endElement(toCharArray(getElementName()));
}

bool
ElemLiteralResult::isAttrOK(
			int						tok,
			const XalanDOMChar*		attrName,
			const AttributeList&	atts,
			int						which) const
{
	return ElemUse::isAttrOK(tok, attrName, atts, which);
}

bool
ElemLiteralResult::isAttrOK(
			const XalanDOMChar*				attrName,
			const AttributeList&			/* atts */,
			int								/* which */,
			StylesheetConstructionContext&	constructionContext) const
{
    bool	isAttrOK = equals(attrName, DOMServices::s_XMLNamespace) ||
					   startsWith(attrName, DOMServices::s_XMLNamespaceWithSeparator);

    if(isAttrOK == false)
    {
		const unsigned int	indexOfNSSep = indexOf(attrName, XalanUnicode::charColon);

		if(indexOfNSSep < length(attrName))
		{
			const XalanDOMString	prefix = substring(attrName, 0, indexOfNSSep);

			const XalanDOMString	ns = getStylesheet().getNamespaceForPrefixFromStack(prefix);

			if (equals(ns, constructionContext.getXSLTNamespaceURI()) == false)
			{
				isAttrOK = true;
			}
		}
		else
		{
			// An empty namespace is OK.
			isAttrOK = true;
		}
    }

    // TODO: Well, process it...
    return isAttrOK;
}

bool
ElemLiteralResult::processPrefixControl(
			StylesheetConstructionContext&	constructionContext,
			const Stylesheet&				stylesheetTree,
			const XalanDOMString&			localName,
			const XalanDOMString&			attrValue)
{
	if(equals(localName, Constants::ATTRNAME_EXTENSIONELEMENTPREFIXES))
	{
		m_namespacesHandler.processExtensionElementPrefixes(c_wstr(attrValue), stylesheetTree.getNamespaces(), constructionContext);

		return true;
	}
	else if (equals(localName, Constants::ATTRNAME_EXCLUDE_RESULT_PREFIXES))
	{
		m_namespacesHandler.processExcludeResultPrefixes(c_wstr(attrValue), stylesheetTree.getNamespaces(), constructionContext);

		return true;
	}
	else
	{
		return false;
	}
}

bool
ElemLiteralResult::shouldExcludeResultNamespaceNode(
			const XalanDOMString&	thePrefix,
			const XalanDOMString&	theURI) const
{
	return m_namespacesHandler.shouldExcludeResultNamespaceNode(
				getStylesheet().getXSLTNamespaceURI(),
				thePrefix,
				theURI);
}
<|endoftext|>


<commit_before>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
 * Copyright (C) 2012 Daniele E. Domenichelli <daniele.domenichelli@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-list-delegate.h"

#include "edit-display-name-button.h"
#include "change-icon-button.h"

#include <KTp/presence.h>
#include <KTp/Models/accounts-list-model.h>

#include <KDE/KLocale>
#include <KDE/KIconButton>
#include <KDE/KMenu>
#include <KDE/KAction>
#include <KDE/KDebug>

#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QCheckBox>
#include <QtGui/QAbstractItemView>
#include <QtGui/QSortFilterProxyModel>
#include <QtGui/QLabel>
#include <sys/stat.h>

AccountsListDelegate::AccountsListDelegate(QAbstractItemView *itemView, QObject *parent)
    : KWidgetItemDelegate(itemView, parent)
{
}

QSize AccountsListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);

    int iconHeight = option.decorationSize.height() + (m_vpadding*2);  //icon height + padding either side
    int textHeight = option.fontMetrics.height()*2 + (m_vpadding*2) + 10; // text height * 2 + padding + some space between the lines

    return QSize(-1,qMax(iconHeight, textHeight)); //any width,the view should give us the whole thing.
}

QList<QWidget*> AccountsListDelegate::createItemWidgets() const
{
    // Items created by this method and added to the list returned will be
    // deleted by KWidgetItemDelegate

    QCheckBox *checkbox = new QCheckBox();
    connect(checkbox, SIGNAL(clicked(bool)), SLOT(onCheckBoxToggled(bool)));

    ChangeIconButton *changeIconButton = new ChangeIconButton();
    changeIconButton->setFlat(true);
    changeIconButton->setToolTip(i18n("Change account icon"));
    changeIconButton->setWhatsThis(i18n("This button allows to change the icon for your account.
"
                                  "This icon is just used locally on your computer, your contacts will not be able to see it."));

    QLabel *statusTextLabel = new QLabel();
    QLabel *statusIconLabel = new QLabel();

    EditDisplayNameButton *displayNameButton = new EditDisplayNameButton();
    displayNameButton->setFlat(true);
    displayNameButton->setToolTip(i18n("Change account display name"));
    displayNameButton->setWhatsThis(i18n("This button allows to change the display name for your account.
"
                                         "The display name is an alias for your account and is just used locally "
                                         "on your computer, your contacts will not be able to see it."));

    QLabel *connectionErrorLabel = new QLabel();

    return QList<QWidget*>() << checkbox
                             << changeIconButton
                             << statusTextLabel
                             << statusIconLabel
                             << displayNameButton
                             << connectionErrorLabel;
}

void AccountsListDelegate::updateItemWidgets(const QList<QWidget *> widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const
{
    // draws:
    //                   AccountName
    // Checkbox | Icon |              | ConnectionIcon | ConnectionState
    //                   errorMessage

    if (!index.isValid()) {
        return;
    }

    Q_ASSERT(widgets.size() == 6);

    // Get the widgets
    QCheckBox* checkbox = qobject_cast<QCheckBox*>(widgets.at(0));
    ChangeIconButton* changeIconButton = qobject_cast<ChangeIconButton*>(widgets.at(1));
    QLabel *statusTextLabel = qobject_cast<QLabel*>(widgets.at(2));
    QLabel *statusIconLabel = qobject_cast<QLabel*>(widgets.at(3));
    EditDisplayNameButton *displayNameButton = qobject_cast<EditDisplayNameButton*>(widgets.at(4));
    QLabel *connectionErrorLabel = qobject_cast<QLabel*>(widgets.at(5));

    Q_ASSERT(checkbox);
    Q_ASSERT(changeIconButton);
    Q_ASSERT(statusTextLabel);
    Q_ASSERT(statusIconLabel);
    Q_ASSERT(displayNameButton);
    Q_ASSERT(connectionErrorLabel);

    bool isSelected(itemView()->selectionModel()->isSelected(index) && itemView()->hasFocus());
    bool isEnabled(index.data(Qt::CheckStateRole).toBool());
    KIcon accountIcon(index.data(Qt::DecorationRole).value<QIcon>());
    KIcon statusIcon(index.data(AccountsListModel::ConnectionStateIconRole).value<QIcon>());
    QString statusText(index.data(AccountsListModel::ConnectionStateDisplayRole).toString());
    QString displayName(index.data(Qt::DisplayRole).toString());
    QString connectionError(index.data(AccountsListModel::ConnectionErrorMessageDisplayRole).toString());
    Tp::AccountPtr account(index.data(AccountsListModel::AccountRole).value<Tp::AccountPtr>());

    QRect outerRect(0, 0, option.rect.width(), option.rect.height());
    QRect contentRect = outerRect.adjusted(m_hpadding,m_vpadding,-m_hpadding,-m_vpadding); //add some padding

    // checkbox
    if (isEnabled) {
        checkbox->setChecked(true);;
        checkbox->setToolTip(i18n("Disable account"));
    } else {
        checkbox->setChecked(false);
        checkbox->setToolTip(i18n("Enable account"));
    }

    int checkboxLeftMargin = contentRect.left();
    int checkboxTopMargin = (outerRect.height() - checkbox->height()) / 2;
    checkbox->move(checkboxLeftMargin, checkboxTopMargin);

    // changeIconButton
    changeIconButton->setIcon(accountIcon);
    changeIconButton->setAccount(account);
    // At the moment (KDE 4.8.1) decorationSize is not passed from KWidgetItemDelegate
    // through the QStyleOptionViewItem, therefore we leave default size unless
    // the user has a more recent version.
    if (option.decorationSize.width() > -1) {
        changeIconButton->setButtonIconSize(option.decorationSize.width());
    }

    int changeIconButtonLeftMargin = checkboxLeftMargin + checkbox->width();
    int changeIconButtonTopMargin = (outerRect.height() - changeIconButton->height()) / 2;
    changeIconButton->move(changeIconButtonLeftMargin, changeIconButtonTopMargin);

    // statusTextLabel
    QFont statusTextFont = option.font;
    QPalette statusTextLabelPalette = option.palette;
    if (isEnabled) {
        statusTextLabel->setEnabled(true);
        statusTextFont.setItalic(false);
    } else {
        statusTextLabel->setDisabled(true);
        statusTextFont.setItalic(true);
    }
    if (isSelected) {
        statusTextLabelPalette.setColor(QPalette::Text, statusTextLabelPalette.color(QPalette::Active, QPalette::HighlightedText));
    }
    statusTextLabel->setPalette(statusTextLabelPalette);
    statusTextLabel->setFont(statusTextFont);
    statusTextLabel->setText(statusText);
    statusTextLabel->setFixedSize(statusTextLabel->fontMetrics().boundingRect(statusText).width(),
                                  statusTextLabel->height());
    int statusTextLabelLeftMargin = contentRect.right() - statusTextLabel->width();
    int statusTextLabelTopMargin = (outerRect.height() - statusTextLabel->height()) / 2;
    statusTextLabel->move(statusTextLabelLeftMargin, statusTextLabelTopMargin);

    // statusIconLabel
    statusIconLabel->setPixmap(statusIcon.pixmap(KIconLoader::SizeSmall));
    statusIconLabel->setFixedSize(statusIconLabel->minimumSizeHint());
    int statusIconLabelLeftMargin = contentRect.right() - statusTextLabel->width() - statusIconLabel->width() - 6;
    int statusIconLabelTopMargin = (outerRect.height() - statusIconLabel->height()) / 2;
    statusIconLabel->move(statusIconLabelLeftMargin, statusIconLabelTopMargin);

    QRect innerRect = contentRect.adjusted(changeIconButton->geometry().right() - contentRect.left(),
                                           0,
                                           -statusTextLabel->width() - statusIconLabel->width() - 6,
                                           0); // rect containing account name and error message

    // displayNameButton
    QFont displayNameButtonFont = option.font;
    QPalette displayNameButtonPalette = option.palette;
    if (isEnabled) {
        displayNameButtonPalette.setColor(QPalette::WindowText, displayNameButtonPalette.color(QPalette::Active, QPalette::Text));
        displayNameButtonFont.setBold(true);
    } else {
        displayNameButtonFont.setItalic(true);
        // NOTE: Flat QPushButton use WindowText instead of ButtonText for button text color
        displayNameButtonPalette.setColor(QPalette::WindowText, displayNameButtonPalette.color(QPalette::Disabled, QPalette::Text));
    }
    if (isSelected) {
        // Account is selected
        displayNameButtonPalette.setColor(QPalette::WindowText, displayNameButtonPalette.color(QPalette::Active, QPalette::HighlightedText));
    }
    displayNameButton->setFont(displayNameButtonFont);
    displayNameButton->setPalette(displayNameButtonPalette);

    QString displayNameButtonText = displayNameButton->fontMetrics().elidedText(displayName,
                                                                                Qt::ElideRight,
                                                                                innerRect.width() - (m_hpadding*2));
    displayNameButton->setText(displayNameButtonText);
    displayNameButton->setFixedSize(displayNameButton->fontMetrics().boundingRect(displayNameButtonText).width() + (m_hpadding*2),
                                    displayNameButton->minimumSizeHint().height());
    displayNameButton->setAccount(account);

    int displayNameButtonLeftMargin = innerRect.left();
    int displayNameButtonTopMargin = innerRect.top();
    displayNameButton->move(displayNameButtonLeftMargin, displayNameButtonTopMargin);

    // connectionErrorLabel
    QFont connectionErrorLabelFont = option.font;
    QPalette connectionErrorLabelPalette = option.palette;
    if (isEnabled) {
        connectionErrorLabelPalette.setColor(QPalette::WindowText, connectionErrorLabelPalette.color(QPalette::Active, QPalette::Text));
    } else {
        connectionErrorLabelFont.setItalic(true);
        connectionErrorLabelPalette.setColor(QPalette::Text, connectionErrorLabelPalette.color(QPalette::Disabled, QPalette::Text));
    }
    if (isSelected) {
        // Account is selected
        connectionErrorLabelPalette.setColor(QPalette::Text, connectionErrorLabelPalette.color(QPalette::Active, QPalette::HighlightedText));
    }
    connectionErrorLabel->setFont(connectionErrorLabelFont);
    connectionErrorLabel->setPalette(connectionErrorLabelPalette);

    QString connectionErrorLabelText = connectionErrorLabel->fontMetrics().elidedText(connectionError,
                                                                                Qt::ElideRight,
                                                                                innerRect.width() - (m_hpadding*2));
    connectionErrorLabel->setText(connectionErrorLabelText);
    connectionErrorLabel->setFixedSize(connectionErrorLabel->fontMetrics().boundingRect(connectionErrorLabelText).width(),
                                       displayNameButton->height());

    int connectionErrorLabelLeftMargin = innerRect.left() + m_hpadding;
    int connectionErrorLabelTopMargin = contentRect.bottom() - displayNameButton->height();
    connectionErrorLabel->move(connectionErrorLabelLeftMargin, connectionErrorLabelTopMargin);
}

void AccountsListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (!index.isValid()) {
        return;
    }

    QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0);
}

void AccountsListDelegate::onCheckBoxToggled(bool checked)
{
    QModelIndex index = focusedIndex();
    Q_EMIT itemChecked(index, checked);
}
<commit_msg>Add message "click checkbox to enable" if the account is disabled<commit_after>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
 * Copyright (C) 2012 Daniele E. Domenichelli <daniele.domenichelli@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-list-delegate.h"

#include "edit-display-name-button.h"
#include "change-icon-button.h"

#include <KTp/presence.h>
#include <KTp/Models/accounts-list-model.h>

#include <KDE/KLocale>
#include <KDE/KIconButton>
#include <KDE/KMenu>
#include <KDE/KAction>
#include <KDE/KDebug>

#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QCheckBox>
#include <QtGui/QAbstractItemView>
#include <QtGui/QSortFilterProxyModel>
#include <QtGui/QLabel>
#include <sys/stat.h>

AccountsListDelegate::AccountsListDelegate(QAbstractItemView *itemView, QObject *parent)
    : KWidgetItemDelegate(itemView, parent)
{
}

QSize AccountsListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);

    int iconHeight = option.decorationSize.height() + (m_vpadding*2);  //icon height + padding either side
    int textHeight = option.fontMetrics.height()*2 + (m_vpadding*2) + 10; // text height * 2 + padding + some space between the lines

    return QSize(-1,qMax(iconHeight, textHeight)); //any width,the view should give us the whole thing.
}

QList<QWidget*> AccountsListDelegate::createItemWidgets() const
{
    // Items created by this method and added to the list returned will be
    // deleted by KWidgetItemDelegate

    QCheckBox *checkbox = new QCheckBox();
    connect(checkbox, SIGNAL(clicked(bool)), SLOT(onCheckBoxToggled(bool)));

    ChangeIconButton *changeIconButton = new ChangeIconButton();
    changeIconButton->setFlat(true);
    changeIconButton->setToolTip(i18n("Change account icon"));
    changeIconButton->setWhatsThis(i18n("This button allows to change the icon for your account.
"
                                  "This icon is just used locally on your computer, your contacts will not be able to see it."));

    QLabel *statusTextLabel = new QLabel();
    QLabel *statusIconLabel = new QLabel();

    EditDisplayNameButton *displayNameButton = new EditDisplayNameButton();
    displayNameButton->setFlat(true);
    displayNameButton->setToolTip(i18n("Change account display name"));
    displayNameButton->setWhatsThis(i18n("This button allows to change the display name for your account.
"
                                         "The display name is an alias for your account and is just used locally "
                                         "on your computer, your contacts will not be able to see it."));

    QLabel *connectionErrorLabel = new QLabel();

    return QList<QWidget*>() << checkbox
                             << changeIconButton
                             << statusTextLabel
                             << statusIconLabel
                             << displayNameButton
                             << connectionErrorLabel;
}

void AccountsListDelegate::updateItemWidgets(const QList<QWidget *> widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const
{
    // draws:
    //                   AccountName
    // Checkbox | Icon |              | ConnectionIcon | ConnectionState
    //                   errorMessage

    if (!index.isValid()) {
        return;
    }

    Q_ASSERT(widgets.size() == 6);

    // Get the widgets
    QCheckBox* checkbox = qobject_cast<QCheckBox*>(widgets.at(0));
    ChangeIconButton* changeIconButton = qobject_cast<ChangeIconButton*>(widgets.at(1));
    QLabel *statusTextLabel = qobject_cast<QLabel*>(widgets.at(2));
    QLabel *statusIconLabel = qobject_cast<QLabel*>(widgets.at(3));
    EditDisplayNameButton *displayNameButton = qobject_cast<EditDisplayNameButton*>(widgets.at(4));
    QLabel *connectionErrorLabel = qobject_cast<QLabel*>(widgets.at(5));

    Q_ASSERT(checkbox);
    Q_ASSERT(changeIconButton);
    Q_ASSERT(statusTextLabel);
    Q_ASSERT(statusIconLabel);
    Q_ASSERT(displayNameButton);
    Q_ASSERT(connectionErrorLabel);

    bool isSelected(itemView()->selectionModel()->isSelected(index) && itemView()->hasFocus());
    bool isEnabled(index.data(Qt::CheckStateRole).toBool());
    KIcon accountIcon(index.data(Qt::DecorationRole).value<QIcon>());
    KIcon statusIcon(index.data(AccountsListModel::ConnectionStateIconRole).value<QIcon>());
    QString statusText(index.data(AccountsListModel::ConnectionStateDisplayRole).toString());
    QString displayName(index.data(Qt::DisplayRole).toString());
    QString connectionError(index.data(AccountsListModel::ConnectionErrorMessageDisplayRole).toString());
    Tp::AccountPtr account(index.data(AccountsListModel::AccountRole).value<Tp::AccountPtr>());

    if (!account->isEnabled()) {
      connectionError = i18n("Click checkbox to enable");
    }

    QRect outerRect(0, 0, option.rect.width(), option.rect.height());
    QRect contentRect = outerRect.adjusted(m_hpadding,m_vpadding,-m_hpadding,-m_vpadding); //add some padding

    // checkbox
    if (isEnabled) {
        checkbox->setChecked(true);;
        checkbox->setToolTip(i18n("Disable account"));
    } else {
        checkbox->setChecked(false);
        checkbox->setToolTip(i18n("Enable account"));
    }

    int checkboxLeftMargin = contentRect.left();
    int checkboxTopMargin = (outerRect.height() - checkbox->height()) / 2;
    checkbox->move(checkboxLeftMargin, checkboxTopMargin);

    // changeIconButton
    changeIconButton->setIcon(accountIcon);
    changeIconButton->setAccount(account);
    // At the moment (KDE 4.8.1) decorationSize is not passed from KWidgetItemDelegate
    // through the QStyleOptionViewItem, therefore we leave default size unless
    // the user has a more recent version.
    if (option.decorationSize.width() > -1) {
        changeIconButton->setButtonIconSize(option.decorationSize.width());
    }

    int changeIconButtonLeftMargin = checkboxLeftMargin + checkbox->width();
    int changeIconButtonTopMargin = (outerRect.height() - changeIconButton->height()) / 2;
    changeIconButton->move(changeIconButtonLeftMargin, changeIconButtonTopMargin);

    // statusTextLabel
    QFont statusTextFont = option.font;
    QPalette statusTextLabelPalette = option.palette;
    if (isEnabled) {
        statusTextLabel->setEnabled(true);
        statusTextFont.setItalic(false);
    } else {
        statusTextLabel->setDisabled(true);
        statusTextFont.setItalic(true);
    }
    if (isSelected) {
        statusTextLabelPalette.setColor(QPalette::Text, statusTextLabelPalette.color(QPalette::Active, QPalette::HighlightedText));
    }
    statusTextLabel->setPalette(statusTextLabelPalette);
    statusTextLabel->setFont(statusTextFont);
    statusTextLabel->setText(statusText);
    statusTextLabel->setFixedSize(statusTextLabel->fontMetrics().boundingRect(statusText).width(),
                                  statusTextLabel->height());
    int statusTextLabelLeftMargin = contentRect.right() - statusTextLabel->width();
    int statusTextLabelTopMargin = (outerRect.height() - statusTextLabel->height()) / 2;
    statusTextLabel->move(statusTextLabelLeftMargin, statusTextLabelTopMargin);

    // statusIconLabel
    statusIconLabel->setPixmap(statusIcon.pixmap(KIconLoader::SizeSmall));
    statusIconLabel->setFixedSize(statusIconLabel->minimumSizeHint());
    int statusIconLabelLeftMargin = contentRect.right() - statusTextLabel->width() - statusIconLabel->width() - 6;
    int statusIconLabelTopMargin = (outerRect.height() - statusIconLabel->height()) / 2;
    statusIconLabel->move(statusIconLabelLeftMargin, statusIconLabelTopMargin);

    QRect innerRect = contentRect.adjusted(changeIconButton->geometry().right() - contentRect.left(),
                                           0,
                                           -statusTextLabel->width() - statusIconLabel->width() - 6,
                                           0); // rect containing account name and error message

    // displayNameButton
    QFont displayNameButtonFont = option.font;
    QPalette displayNameButtonPalette = option.palette;
    if (isEnabled) {
        displayNameButtonPalette.setColor(QPalette::WindowText, displayNameButtonPalette.color(QPalette::Active, QPalette::Text));
        displayNameButtonFont.setBold(true);
    } else {
        displayNameButtonFont.setItalic(true);
        // NOTE: Flat QPushButton use WindowText instead of ButtonText for button text color
        displayNameButtonPalette.setColor(QPalette::WindowText, displayNameButtonPalette.color(QPalette::Disabled, QPalette::Text));
    }
    if (isSelected) {
        // Account is selected
        displayNameButtonPalette.setColor(QPalette::WindowText, displayNameButtonPalette.color(QPalette::Active, QPalette::HighlightedText));
    }
    displayNameButton->setFont(displayNameButtonFont);
    displayNameButton->setPalette(displayNameButtonPalette);

    QString displayNameButtonText = displayNameButton->fontMetrics().elidedText(displayName,
                                                                                Qt::ElideRight,
                                                                                innerRect.width() - (m_hpadding*2));
    displayNameButton->setText(displayNameButtonText);
    displayNameButton->setFixedSize(displayNameButton->fontMetrics().boundingRect(displayNameButtonText).width() + (m_hpadding*2),
                                    displayNameButton->minimumSizeHint().height());
    displayNameButton->setAccount(account);

    int displayNameButtonLeftMargin = innerRect.left();
    int displayNameButtonTopMargin = innerRect.top();
    displayNameButton->move(displayNameButtonLeftMargin, displayNameButtonTopMargin);

    // connectionErrorLabel
    QFont connectionErrorLabelFont = option.font;
    QPalette connectionErrorLabelPalette = option.palette;
    if (isEnabled) {
        connectionErrorLabelPalette.setColor(QPalette::WindowText, connectionErrorLabelPalette.color(QPalette::Active, QPalette::Text));
    } else {
        connectionErrorLabelFont.setItalic(true);
        connectionErrorLabelPalette.setColor(QPalette::Text, connectionErrorLabelPalette.color(QPalette::Disabled, QPalette::Text));
    }
    if (isSelected) {
        // Account is selected
        connectionErrorLabelPalette.setColor(QPalette::Text, connectionErrorLabelPalette.color(QPalette::Active, QPalette::HighlightedText));
    }
    connectionErrorLabel->setFont(connectionErrorLabelFont);
    connectionErrorLabel->setPalette(connectionErrorLabelPalette);

    QString connectionErrorLabelText = connectionErrorLabel->fontMetrics().elidedText(connectionError,
                                                                                Qt::ElideRight,
                                                                                innerRect.width() - (m_hpadding*2));
    connectionErrorLabel->setText(connectionErrorLabelText);
    connectionErrorLabel->setFixedSize(connectionErrorLabel->fontMetrics().boundingRect(connectionErrorLabelText).width(),
                                       displayNameButton->height());

    int connectionErrorLabelLeftMargin = innerRect.left() + m_hpadding;
    int connectionErrorLabelTopMargin = contentRect.bottom() - displayNameButton->height();
    connectionErrorLabel->move(connectionErrorLabelLeftMargin, connectionErrorLabelTopMargin);
}

void AccountsListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (!index.isValid()) {
        return;
    }

    QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0);
}

void AccountsListDelegate::onCheckBoxToggled(bool checked)
{
    QModelIndex index = focusedIndex();
    Q_EMIT itemChecked(index, checked);
}
<|endoftext|>


<commit_before>#include "yebash.hpp"
#include "History.hpp"

#include "catch.hpp"
#include <iostream>
#include <algorithm>
#include <sstream>

using namespace yb;
using namespace std;

namespace {
void tearDown() {
    std::stringstream output, ss;
    Printer printer(output);
    History history;
    history.read(ss);
    HistorySuggestion suggestion(history);
    yebash(suggestion, printer, '\n');
}
} // anon namespace

TEST_CASE( "No suggestions when history is empty", "[basic.empty_history]"  ) {

    auto testCharacter = [] (char const c) {
        std::stringstream ss;
        std::stringstream output;
        History history;
        history.read(ss);
        HistorySuggestion suggestion(history);
        Printer printer(output);

        auto result = yebash(suggestion, printer, c);

        REQUIRE(result == c);
        REQUIRE(output.str() == "");
    };

    string domain = "abcdefghijklmnopqrstuvwxyz01234567890-_";
    for_each(begin(domain), end(domain), testCharacter);

    tearDown();
}

TEST_CASE( "Order of commands from history is preserved", "[basic.history_order_preserved]"  ) {

    std::stringstream ss;
    ss << "abc1" << std::endl;
    ss << "abc2" << std::endl;

    std::stringstream output;
    History history;
    history.read(ss);
    HistorySuggestion suggestion(history);
    Printer printer(output);

    auto character = 'a';
    auto result = yebash(suggestion, printer, character);

    REQUIRE(result == character);
    REQUIRE(output.str() == "bc2");

    tearDown();
}

<commit_msg>refactored code to avoid code duplication<commit_after>#include "yebash.hpp"
#include "History.hpp"

#include "catch.hpp"
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <sstream>

using namespace yb;
using namespace std;

namespace {

History createHistory(initializer_list<string> const& commands) {
    stringstream ss;
    for (auto && command: commands) {
        ss << command << std::endl;
    }

    History history;
    history.read(ss);
    return history;
}

void tearDown() {
    std::stringstream output, ss;
    Printer printer(output);
    History history;
    history.read(ss);
    HistorySuggestion suggestion(history);
    yebash(suggestion, printer, '\n');
}
} // anon namespace

TEST_CASE( "No suggestions when history is empty", "[basic.empty_history]"  ) {

    auto testCharacter = [] (char const c) {
        History history = createHistory({});
        HistorySuggestion suggestion(history);

        std::stringstream output;
        Printer printer(output);

        auto result = yebash(suggestion, printer, c);

        REQUIRE(result == c);
        REQUIRE(output.str() == "");
    };

    string domain = "abcdefghijklmnopqrstuvwxyz01234567890-_";
    for_each(begin(domain), end(domain), testCharacter);

    tearDown();
}

TEST_CASE( "Order of commands from history is preserved", "[basic.history_order_preserved]"  ) {

    History history = createHistory({"abc1", "abc2"});
    HistorySuggestion suggestion(history);

    std::stringstream output;
    Printer printer(output);

    auto character = 'a';
    auto result = yebash(suggestion, printer, character);

    REQUIRE(result == character);
    REQUIRE(output.str() == "bc2");

    tearDown();
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "window.h"

Window::Window(QWidget *parent)
    : QWidget(parent), m_iconSize(64, 64)
{
    m_ui.setupUi(this);
    QButtonGroup *buttonGroup = qFindChild<QButtonGroup *>(this);     // ### workaround for uic in 4.4
    m_ui.easingCurvePicker->setIconSize(m_iconSize);
    m_ui.easingCurvePicker->setMinimumHeight(m_iconSize.height() + 50);
    buttonGroup->setId(m_ui.lineRadio, 0);
    buttonGroup->setId(m_ui.circleRadio, 1);

    QEasingCurve dummy;
    m_ui.periodSpinBox->setValue(dummy.period());
    m_ui.amplitudeSpinBox->setValue(dummy.amplitude());
    m_ui.overshootSpinBox->setValue(dummy.overshoot());

    connect(m_ui.easingCurvePicker, SIGNAL(currentRowChanged(int)), this, SLOT(curveChanged(int)));
    connect(buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(pathChanged(int)));
    connect(m_ui.periodSpinBox, SIGNAL(valueChanged(double)), this, SLOT(periodChanged(double)));
    connect(m_ui.amplitudeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(amplitudeChanged(double)));
    connect(m_ui.overshootSpinBox, SIGNAL(valueChanged(double)), this, SLOT(overshootChanged(double)));
    createCurveIcons();

    QPixmap pix(QLatin1String(":/images/qt-logo.png"));
    m_item = new PixmapItem(pix);
    m_scene.addItem(m_item);
    m_ui.graphicsView->setScene(&m_scene);

    m_anim = new Animation(m_item, "pos");
    m_anim->setEasingCurve(QEasingCurve::OutBounce);
    m_ui.easingCurvePicker->setCurrentRow(int(QEasingCurve::OutBounce));

    startAnimation();
}

void Window::createCurveIcons()
{
    QPixmap pix(m_iconSize);
    QPainter painter(&pix);
    QLinearGradient gradient(0,0, 0, m_iconSize.height());
    gradient.setColorAt(0.0, QColor(240, 240, 240));
    gradient.setColorAt(1.0, QColor(224, 224, 224));
    QBrush brush(gradient);
    const QMetaObject &mo = QEasingCurve::staticMetaObject;
    QMetaEnum metaEnum = mo.enumerator(mo.indexOfEnumerator("Type"));
    // Skip QEasingCurve::Custom
    for (int i = 0; i < QEasingCurve::NCurveTypes - 1; ++i) {
        painter.fillRect(QRect(QPoint(0, 0), m_iconSize), brush);
        QEasingCurve curve((QEasingCurve::Type)i);
        painter.setPen(QColor(0, 0, 255, 64));
        qreal xAxis = m_iconSize.height()/1.5;
        qreal yAxis = m_iconSize.width()/3;
        painter.drawLine(0, xAxis, m_iconSize.width(),  xAxis);
        painter.drawLine(yAxis, 0, yAxis, m_iconSize.height());
        painter.setPen(Qt::black);

        qreal curveScale = m_iconSize.height()/2;
        QPoint currentPos(yAxis, xAxis);

        for (qreal t = 0; t < 1.0; t+=1.0/curveScale) {
            QPoint to;
            to.setX(yAxis + curveScale * t);
            to.setY(xAxis - curveScale * curve.valueForProgress(t));
            painter.drawLine(currentPos, to);
            currentPos = to;
        }
        QListWidgetItem *item = new QListWidgetItem;
        item->setIcon(QIcon(pix));
        item->setText(metaEnum.key(i));
        m_ui.easingCurvePicker->addItem(item);
    }
}

void Window::startAnimation()
{
    m_anim->setStartValue(QPointF(0, 0));
    m_anim->setEndValue(QPointF(100, 100));
    m_anim->setDuration(2000);
    m_anim->setLoopCount(-1); // forever
    m_anim->start();
}

void Window::curveChanged(int row)
{
    QEasingCurve::Type curveType = (QEasingCurve::Type)row;
    m_anim->setEasingCurve(curveType);
    m_anim->setCurrentTime(0);

    bool isElastic = curveType >= QEasingCurve::InElastic && curveType <= QEasingCurve::OutInElastic;
    bool isBounce = curveType >= QEasingCurve::InBounce && curveType <= QEasingCurve::OutInBounce;
    m_ui.periodSpinBox->setEnabled(isElastic);
    m_ui.amplitudeSpinBox->setEnabled(isElastic || isBounce);
    m_ui.overshootSpinBox->setEnabled(curveType >= QEasingCurve::InBack && curveType <= QEasingCurve::OutInBack);
}

void Window::pathChanged(int index)
{
    m_anim->setPathType((Animation::PathType)index);
}

void Window::periodChanged(double value)
{
    QEasingCurve curve = m_anim->easingCurve();
    curve.setPeriod(value);
    m_anim->setEasingCurve(curve);
}

void Window::amplitudeChanged(double value)
{
    QEasingCurve curve = m_anim->easingCurve();
    curve.setAmplitude(value);
    m_anim->setEasingCurve(curve);
}

void Window::overshootChanged(double value)
{
    QEasingCurve curve = m_anim->easingCurve();
    curve.setOvershoot(value);
    m_anim->setEasingCurve(curve);
}

<commit_msg>Make the easing curve icons more beautiful.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "window.h"

Window::Window(QWidget *parent)
    : QWidget(parent), m_iconSize(64, 64)
{
    m_ui.setupUi(this);
    QButtonGroup *buttonGroup = qFindChild<QButtonGroup *>(this);     // ### workaround for uic in 4.4
    m_ui.easingCurvePicker->setIconSize(m_iconSize);
    m_ui.easingCurvePicker->setMinimumHeight(m_iconSize.height() + 50);
    buttonGroup->setId(m_ui.lineRadio, 0);
    buttonGroup->setId(m_ui.circleRadio, 1);

    QEasingCurve dummy;
    m_ui.periodSpinBox->setValue(dummy.period());
    m_ui.amplitudeSpinBox->setValue(dummy.amplitude());
    m_ui.overshootSpinBox->setValue(dummy.overshoot());

    connect(m_ui.easingCurvePicker, SIGNAL(currentRowChanged(int)), this, SLOT(curveChanged(int)));
    connect(buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(pathChanged(int)));
    connect(m_ui.periodSpinBox, SIGNAL(valueChanged(double)), this, SLOT(periodChanged(double)));
    connect(m_ui.amplitudeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(amplitudeChanged(double)));
    connect(m_ui.overshootSpinBox, SIGNAL(valueChanged(double)), this, SLOT(overshootChanged(double)));
    createCurveIcons();

    QPixmap pix(QLatin1String(":/images/qt-logo.png"));
    m_item = new PixmapItem(pix);
    m_scene.addItem(m_item);
    m_ui.graphicsView->setScene(&m_scene);

    m_anim = new Animation(m_item, "pos");
    m_anim->setEasingCurve(QEasingCurve::OutBounce);
    m_ui.easingCurvePicker->setCurrentRow(int(QEasingCurve::OutBounce));

    startAnimation();
}

void Window::createCurveIcons()
{
    QPixmap pix(m_iconSize);
    QPainter painter(&pix);
    QLinearGradient gradient(0,0, 0, m_iconSize.height());
    gradient.setColorAt(0.0, QColor(240, 240, 240));
    gradient.setColorAt(1.0, QColor(224, 224, 224));
    QBrush brush(gradient);
    const QMetaObject &mo = QEasingCurve::staticMetaObject;
    QMetaEnum metaEnum = mo.enumerator(mo.indexOfEnumerator("Type"));
    // Skip QEasingCurve::Custom
    for (int i = 0; i < QEasingCurve::NCurveTypes - 1; ++i) {
        painter.fillRect(QRect(QPoint(0, 0), m_iconSize), brush);
        QEasingCurve curve((QEasingCurve::Type)i);
        painter.setPen(QColor(0, 0, 255, 64));
        qreal xAxis = m_iconSize.height()/1.5;
        qreal yAxis = m_iconSize.width()/3;
        painter.drawLine(0, xAxis, m_iconSize.width(),  xAxis);
        painter.drawLine(yAxis, 0, yAxis, m_iconSize.height());

        qreal curveScale = m_iconSize.height()/2;

        painter.setPen(Qt::NoPen);

        // start point
        painter.setBrush(Qt::red);
        QPoint start(yAxis, xAxis - curveScale * curve.valueForProgress(0));
        painter.drawRect(start.x() - 1, start.y() - 1, 3, 3);

        // end point
        painter.setBrush(Qt::blue);
        QPoint end(yAxis + curveScale, xAxis - curveScale * curve.valueForProgress(1));
        painter.drawRect(end.x() - 1, end.y() - 1, 3, 3);

        painter.setPen(QColor(32, 32, 32));
        painter.setRenderHint(QPainter::Antialiasing, true);
        QPoint currentPos(start);
        for (qreal t = 0; t < 1.0; t+=1.0/curveScale) {
            QPoint to;
            to.setX(yAxis + curveScale * t);
            to.setY(xAxis - curveScale * curve.valueForProgress(t));
            painter.drawLine(currentPos, to);
            currentPos = to;
        }
        painter.setRenderHint(QPainter::Antialiasing, false);
        QListWidgetItem *item = new QListWidgetItem;
        item->setIcon(QIcon(pix));
        item->setText(metaEnum.key(i));
        m_ui.easingCurvePicker->addItem(item);
    }
}

void Window::startAnimation()
{
    m_anim->setStartValue(QPointF(0, 0));
    m_anim->setEndValue(QPointF(100, 100));
    m_anim->setDuration(2000);
    m_anim->setLoopCount(-1); // forever
    m_anim->start();
}

void Window::curveChanged(int row)
{
    QEasingCurve::Type curveType = (QEasingCurve::Type)row;
    m_anim->setEasingCurve(curveType);
    m_anim->setCurrentTime(0);

    bool isElastic = curveType >= QEasingCurve::InElastic && curveType <= QEasingCurve::OutInElastic;
    bool isBounce = curveType >= QEasingCurve::InBounce && curveType <= QEasingCurve::OutInBounce;
    m_ui.periodSpinBox->setEnabled(isElastic);
    m_ui.amplitudeSpinBox->setEnabled(isElastic || isBounce);
    m_ui.overshootSpinBox->setEnabled(curveType >= QEasingCurve::InBack && curveType <= QEasingCurve::OutInBack);
}

void Window::pathChanged(int index)
{
    m_anim->setPathType((Animation::PathType)index);
}

void Window::periodChanged(double value)
{
    QEasingCurve curve = m_anim->easingCurve();
    curve.setPeriod(value);
    m_anim->setEasingCurve(curve);
}

void Window::amplitudeChanged(double value)
{
    QEasingCurve curve = m_anim->easingCurve();
    curve.setAmplitude(value);
    m_anim->setEasingCurve(curve);
}

void Window::overshootChanged(double value)
{
    QEasingCurve curve = m_anim->easingCurve();
    curve.setOvershoot(value);
    m_anim->setEasingCurve(curve);
}

<|endoftext|>


<commit_before>#ifndef SDD_CG_HPP
#define SDD_CG_HPP

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cmath>

#include <boost/range/algorithm.hpp>

#include <amgcl/amgcl.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/backend/crs_tuple.hpp>
#include <amgcl/coarsening/plain_aggregates.hpp>
#include <amgcl/coarsening/smoothed_aggregation.hpp>
#include <amgcl/relaxation/spai0.hpp>
#include <amgcl/solver/bicgstabl.hpp>
#include <amgcl/mpi/deflation.hpp>
#include <amgcl/profiler.hpp>

#include "domain_partition.hpp"

struct linear_deflation {
    long n;
    double h;
    std::vector<long> idx;

    linear_deflation(long n) : n(n), h(1.0 / (n - 1)), idx(n * n) {}

    size_t dim() const { return 3; }

    double operator()(long i, int j) const {
        switch(j) {
            case 1:
                return h * (idx[i] % n);
            case 2:
                return h * (idx[i] / n);
            case 0:
            default:
                return 1;
        }
    }
};

int main(int argc, char *argv[]) {
    boost::mpi::environment  env;
    boost::mpi::communicator world;

    const long n  = argc > 1 ? atoi(argv[1]) : 1024;
    const long n2 = n * n;

    boost::array<long, 2> lo = { {0, 0} };
    boost::array<long, 2> hi = { {n - 1, n - 1} };

    amgcl::profiler<> prof;

    prof.tic("partition");
    domain_partition<2> part(lo, hi, world.size());
    const long chunk = part.size( world.rank() );

    std::vector<long> domain(world.size() + 1);
    all_gather(world, chunk, &domain[1]);
    boost::partial_sum(domain, domain.begin());

    const long chunk_start = domain[world.rank()];
    const long chunk_end   = domain[world.rank() + 1];

    linear_deflation lindef(n);
    std::vector<long> renum(n2);
    for(long j = 0, idx = 0; j < n; ++j) {
        for(long i = 0; i < n; ++i, ++idx) {
            boost::array<long, 2> p = {{i, j}};
            std::pair<int,long> v = part.index(p);
            renum[idx] = domain[v.first] + v.second;
            lindef.idx[renum[idx]] = idx;
        }
    }
    prof.toc("partition");

    prof.tic("assemble");
    std::vector<long>   ptr;
    std::vector<long>   col;
    std::vector<double> val;
    std::vector<double> rhs;

    ptr.reserve(chunk + 1);
    col.reserve(chunk * 5);
    val.reserve(chunk * 5);
    rhs.reserve(chunk);

    ptr.push_back(0);

    const double h2i = (n - 1) * (n - 1);
    for(long j = 0, idx = 0; j < n; ++j) {
        for(long i = 0; i < n; ++i, ++idx) {
            if (renum[idx] < chunk_start || renum[idx] >= chunk_end) continue;

            if (i == 0 || j == 0 || i + 1 == n || j + 1 == n) {
                col.push_back(renum[idx]);
                val.push_back(1);
                rhs.push_back(0);
            } else {
                if (j > 0)  {
                    col.push_back(renum[idx - n]);
                    val.push_back(-h2i);
                }

                if (i > 0) {
                    col.push_back(renum[idx - 1]);
                    val.push_back(-h2i);
                }

                col.push_back(renum[idx]);
                val.push_back(4 * h2i);

                if (i + 1 < n) {
                    col.push_back(renum[idx + 1]);
                    val.push_back(-h2i);
                }

                if (j + 1 < n) {
                    col.push_back(renum[idx + n]);
                    val.push_back(-h2i);
                }

                rhs.push_back(1);
            }
            ptr.push_back( col.size() );
        }
    }
    prof.toc("assemble");

    prof.tic("setup");
    typedef amgcl::mpi::subdomain_deflation<
        amgcl::backend::builtin<double>,
        amgcl::coarsening::smoothed_aggregation<
            amgcl::coarsening::plain_aggregates
            >,
        amgcl::relaxation::spai0,
        amgcl::solver::bicgstabl
        > Solver;

    typename Solver::AMG_params    amg_prm;
    typename Solver::Solver_params slv_prm(2, 500, 1e-6);
    Solver solve(world,
            boost::tie(chunk, ptr, col, val),
            lindef,
            amg_prm, slv_prm
            );
    prof.toc("setup");

    prof.tic("solve");
    std::vector<double> x(chunk, 0);
    size_t iters;
    double resid;
    boost::tie(iters, resid) = solve(rhs, x);
    prof.toc("solve");

    prof.tic("save");
    if (world.rank() == 0) {
        std::vector<double> X(n2);
        boost::copy(x, X.begin());

        for(int i = 1; i < world.size(); ++i)
            world.recv(i, 42, &X[domain[i]], domain[i+1] - domain[i]);

        std::ofstream f("out.dat", std::ios::binary);
        int m = n2;
        f.write((char*)&m, sizeof(int));
        for(long i = 0; i < n2; ++i)
            f.write((char*)&X[renum[i]], sizeof(double));
    } else {
        world.send(0, 42, x.data(), chunk);
    }
    prof.toc("save");

    if (world.rank() == 0) {
        std::cout
            << "Iterations: " << iters << std::endl
            << "Error:      " << resid << std::endl
            << std::endl
            << prof << std::endl;
    }
}

#endif
<commit_msg>Truly unsymmetric matrix in examples/mpi/subdomain_deflation.cpp<commit_after>#ifndef SDD_CG_HPP
#define SDD_CG_HPP

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cmath>

#include <boost/range/algorithm.hpp>

#include <amgcl/amgcl.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/backend/crs_tuple.hpp>
#include <amgcl/coarsening/plain_aggregates.hpp>
#include <amgcl/coarsening/smoothed_aggregation.hpp>
#include <amgcl/relaxation/spai0.hpp>
#include <amgcl/solver/bicgstabl.hpp>
#include <amgcl/mpi/deflation.hpp>
#include <amgcl/profiler.hpp>

#include "domain_partition.hpp"

#define CONVECTION

struct linear_deflation {
    long n;
    double h;
    std::vector<long> idx;

    linear_deflation(long n) : n(n), h(1.0 / (n - 1)), idx(n * n) {}

    size_t dim() const { return 3; }

    double operator()(long i, int j) const {
        switch(j) {
            case 1:
                return h * (idx[i] % n);
            case 2:
                return h * (idx[i] / n);
            case 0:
            default:
                return 1;
        }
    }
};

int main(int argc, char *argv[]) {
    boost::mpi::environment  env;
    boost::mpi::communicator world;

    const long n  = argc > 1 ? atoi(argv[1]) : 1024;
    const long n2 = n * n;

    boost::array<long, 2> lo = { {0, 0} };
    boost::array<long, 2> hi = { {n - 1, n - 1} };

    amgcl::profiler<> prof;

    prof.tic("partition");
    domain_partition<2> part(lo, hi, world.size());
    const long chunk = part.size( world.rank() );

    std::vector<long> domain(world.size() + 1);
    all_gather(world, chunk, &domain[1]);
    boost::partial_sum(domain, domain.begin());

    const long chunk_start = domain[world.rank()];
    const long chunk_end   = domain[world.rank() + 1];

    linear_deflation lindef(n);
    std::vector<long> renum(n2);
    for(long j = 0, idx = 0; j < n; ++j) {
        for(long i = 0; i < n; ++i, ++idx) {
            boost::array<long, 2> p = {{i, j}};
            std::pair<int,long> v = part.index(p);
            renum[idx] = domain[v.first] + v.second;
            lindef.idx[renum[idx]] = idx;
        }
    }
    prof.toc("partition");

    prof.tic("assemble");
    std::vector<long>   ptr;
    std::vector<long>   col;
    std::vector<double> val;
    std::vector<double> rhs;

    ptr.reserve(chunk + 1);
    col.reserve(chunk * 5);
    val.reserve(chunk * 5);
    rhs.reserve(chunk);

    ptr.push_back(0);

    const double hinv = (n - 1);
    const double h2i  = (n - 1) * (n - 1);
    for(long j = 0, idx = 0; j < n; ++j) {
        for(long i = 0; i < n; ++i, ++idx) {
            if (renum[idx] < chunk_start || renum[idx] >= chunk_end) continue;

            if (j > 0)  {
                col.push_back(renum[idx - n]);
                val.push_back(-h2i);
            }

            if (i > 0) {
                col.push_back(renum[idx - 1]);
                val.push_back(-h2i
#ifdef CONVECTION
                        - hinv
#endif
                        );
            }

            col.push_back(renum[idx]);
            val.push_back(4 * h2i
#ifdef CONVECTION
                    + hinv
#endif
                    );

            if (i + 1 < n) {
                col.push_back(renum[idx + 1]);
                val.push_back(-h2i);
            }

            if (j + 1 < n) {
                col.push_back(renum[idx + n]);
                val.push_back(-h2i);
            }

            rhs.push_back(1);
            ptr.push_back( col.size() );
        }
    }
    prof.toc("assemble");

    prof.tic("setup");
    typedef amgcl::mpi::subdomain_deflation<
        amgcl::backend::builtin<double>,
        amgcl::coarsening::smoothed_aggregation<
            amgcl::coarsening::plain_aggregates
            >,
        amgcl::relaxation::spai0,
        amgcl::solver::bicgstabl
        > Solver;

    typename Solver::AMG_params    amg_prm;
    typename Solver::Solver_params slv_prm(2, 500, 1e-6);
    Solver solve(world,
            boost::tie(chunk, ptr, col, val),
            lindef,
            amg_prm, slv_prm
            );
    prof.toc("setup");

    prof.tic("solve");
    std::vector<double> x(chunk, 0);
    size_t iters;
    double resid;
    boost::tie(iters, resid) = solve(rhs, x);
    prof.toc("solve");

    prof.tic("save");
    if (world.rank() == 0) {
        std::vector<double> X(n2);
        boost::copy(x, X.begin());

        for(int i = 1; i < world.size(); ++i)
            world.recv(i, 42, &X[domain[i]], domain[i+1] - domain[i]);

        std::ofstream f("out.dat", std::ios::binary);
        int m = n2;
        f.write((char*)&m, sizeof(int));
        for(long i = 0; i < n2; ++i)
            f.write((char*)&X[renum[i]], sizeof(double));
    } else {
        world.send(0, 42, x.data(), chunk);
    }
    prof.toc("save");

    if (world.rank() == 0) {
        std::cout
            << "Iterations: " << iters << std::endl
            << "Error:      " << resid << std::endl
            << std::endl
            << prof << std::endl;
    }
}

#endif
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

/// \file StereoSettings.h
///
#include <asp/Core/StereoSettings.h>

#include <vw/Core/Thread.h>
#include <vw/Core/Log.h>
#include <fstream>

namespace po = boost::program_options;
using namespace vw;

// ---------------------------------------------------
// Create a single instance of the StereoSettings
// ---------------------------------------------------
namespace {
  vw::RunOnce stereo_settings_once = VW_RUNONCE_INIT;
  boost::shared_ptr<StereoSettings> stereo_settings_ptr;
  void init_stereo_settings() {
    stereo_settings_ptr = boost::shared_ptr<StereoSettings>(new StereoSettings());
  }
}

StereoSettings& stereo_settings() {
  stereo_settings_once.run( init_stereo_settings );
  return *stereo_settings_ptr;
}

// ----------------------------------------------------------
// Utilities for parsing lines out of the stereo.default file
// ----------------------------------------------------------

// Determine whether the given character is a space character.
inline bool is_space_char(int c) {
  return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}

// Read from stream until (but not including) the next non-space character.
inline void ignorespace(std::istream& s) {
  int c;
  if(s.eof())
    return;
  while((c = s.get()) != EOF && is_space_char(c)){}
  if(c != EOF)
    s.unget();
}

// Read from stream until (but not including) the beginning of the next line.
inline void ignoreline(std::istream& s) {
  int c;
  if(s.eof())
    return;
  while((c = s.get()) != EOF && c != '\n'){}
}

// Read from stream until (but not including) the next space character. Ignores space characters at beginning.
inline void getword(std::istream& s, std::string& str) {
  int c;
  str.clear();
  ignorespace(s);
  if(s.eof())
    return;
  while((c = s.get()) != EOF && !is_space_char(c))
    str.push_back(c);
  if(c != EOF)
    s.unget();
}

//--------------------------------------------------
// StereoSettings Methods
//--------------------------------------------------
StereoSettings::StereoSettings() {

#define ASSOC_INT(X,Y,V,D)             m_desc.add_options()(X, po::value<int>(&(this->Y))->default_value(V), D)
#define ASSOC_FLOAT(X,Y,V,D)           m_desc.add_options()(X, po::value<float>(&(this->Y))->default_value(V), D)
#define ASSOC_DOUBLE(X,Y,V,D)          m_desc.add_options()(X, po::value<double>(&(this->Y))->default_value(V), D)
#define ASSOC_STRING(X,Y,V,D)          m_desc.add_options()(X, po::value<std::string>(&(this->Y))->default_value(V), D)

  // ---------------------
  // Preprocessing options
  // ---------------------

  // Alignment
  ASSOC_INT("DO_INTERESTPOINT_ALIGNMENT", keypoint_alignment, 0, "Align images using the interest point alignment method");
  ASSOC_INT("INTERESTPOINT_ALIGNMENT_SUBSAMPLING", keypoint_align_subsampling, 1, "Image sub-sampling factor for keypoint alignment.");
  ASSOC_INT("DO_EPIPOLAR_ALIGNMENT", epipolar_alignment, 0, "Align images using epipolar constraints");

  // Image normalization
  ASSOC_INT("FORCE_USE_ENTIRE_RANGE", force_max_min, 0, "Use images entire values, otherwise compress image range to -+2.5 sigmas around mean.");
  ASSOC_INT("DO_INDIVIDUAL_NORMALIZATION", individually_normalize, 0, "Normalize each image individually before processsing.");

  // -------------------
  // Correlation Options
  // -------------------

  // Preproc filter
  ASSOC_INT("PREPROCESSING_FILTER_MODE", pre_filter_mode, 3, "selects the preprocessing filter");
  ASSOC_FLOAT("SLOG_KERNEL_WIDTH", slogW, 1.5, "SIGMA for the gaussian blure in LOG and SLOG");

  // Integer correlator
  ASSOC_INT("COST_MODE", cost_mode, 2, "0 - absolute different, 1 - squared difference, 2 - normalized cross correlation");
  ASSOC_FLOAT("XCORR_THRESHOLD", xcorr_threshold, 2.0, "");
  ASSOC_FLOAT("CORRSCORE_REJECTION_THRESHOLD", corrscore_rejection_threshold, 1.1, "");
  ASSOC_INT("COST_BLUR", cost_blur, 0, "Reduces the number of missing pixels by blurring the fitness landscape computed by the cost function.");
  ASSOC_INT("H_KERNEL", kernel[0], 25, "kernel width");
  ASSOC_INT("V_KERNEL", kernel[1], 25, "kernel height");

  ASSOC_INT("H_CORR_MAX", search_range.max()[0], 0, "correlation window size max x");
  ASSOC_INT("H_CORR_MIN", search_range.min()[0], 0, "correlation window size min x");
  ASSOC_INT("V_CORR_MAX", search_range.max()[1], 0, "correlation window size max y");
  ASSOC_INT("V_CORR_MIN", search_range.min()[1], 0, "correlation window size min y");

  ASSOC_INT("SUBPIXEL_MODE", subpixel_mode, 2, "0 - no subpixel, 1 - parabola, 2 - bayes EM");
  ASSOC_INT("SUBPIXEL_H_KERNEL", subpixel_kernel[0], 35, "subpixel kernel width");
  ASSOC_INT("SUBPIXEL_V_KERNEL", subpixel_kernel[1], 35, "subpixel kernel height");
  ASSOC_INT("DO_H_SUBPIXEL", do_h_subpixel, 1, "Do vertical subpixel interpolation.");
  ASSOC_INT("DO_V_SUBPIXEL", do_v_subpixel, 1, "Do horizontal subpixel interpolation.");

  // EMSubpixelCorrelator options
  ASSOC_INT("SUBPIXEL_EM_ITER", subpixel_em_iter, 15, "Maximum number of EM iterations for EMSubpixelCorrelator");
  ASSOC_INT("SUBPIXEL_AFFINE_ITER", subpixel_affine_iter, 5, "Maximum number of affine optimization iterations for EMSubpixelCorrelator");
  ASSOC_INT("SUBPIXEL_PYRAMID_LEVELS", subpixel_pyramid_levels, 3, "Number of pyramid levels for EMSubpixelCorrelator");

  // Filtering Options
  ASSOC_INT("RM_H_HALF_KERN", rm_h_half_kern, 5, "low conf pixel removal kernel half size");
  ASSOC_INT("RM_V_HALF_KERN", rm_v_half_kern, 5, "");
  ASSOC_INT("RM_MIN_MATCHES", rm_min_matches, 60, "min # of pxls to be matched to keep pxl");
  ASSOC_INT("RM_THRESHOLD", rm_threshold, 3, "rm_threshold > disp[n]-disp[m] pixels are not matching");
  ASSOC_INT("RM_CLEANUP_PASSES", rm_cleanup_passes, 1, "number of passes for cleanup during the post-processing phase");
  ASSOC_INT("ERODE_MAX_SIZE", erode_max_size, 1000, "max size of islands that should be removed");
  ASSOC_INT("FILL_HOLES", fill_holes, 1, "fill holes using an inpainting method");
  ASSOC_INT("FILL_HOLE_MAX_SIZE", fill_hole_max_size, 100000, "max size in pixels that should be filled");
  ASSOC_INT("MASK_FLATFIELD", mask_flatfield, 0, "mask pixels that are less than 0. (for use with apollo metric camera only!)");

  // Triangulation Options
  ASSOC_STRING("UNIVERSE_CENTER", universe_center, "NONE", "center for radius measurements [CAMERA, ZERO, NONE]");
  ASSOC_FLOAT("NEAR_UNIVERSE_RADIUS", near_universe_radius, 0.0, "radius of inner boundary of universe [m]");
  ASSOC_FLOAT("FAR_UNIVERSE_RADIUS", far_universe_radius, 0.0, "radius of outer boundary of universe [m]");
  ASSOC_INT("USE_LEAST_SQUARES", use_least_squares, 0, "use a more rigorous triangulation");

  // System Settings
  ASSOC_STRING("CACHE_DIR", cache_dir, "/tmp", "Change if can't write large files to /tmp (i.e. Super Computer)");
  ASSOC_STRING("TIF_COMPRESS", tif_compress, "", "Compression option for TIF");

#undef ASSOC_INT
#undef ASSOC_FLOAT
#undef ASSOC_DOUBLE
#undef ASSOC_STRING

  int argc = 1;
  char* argv[1];
  argv[0] = (char*)malloc(2*sizeof(char));
  argv[0][0] = 'a';
  po::store(po::parse_command_line(argc, argv, m_desc), m_vm);
  po::notify(m_vm);
}

void StereoSettings::read(std::string const& filename) {
  std::ifstream fp(filename.c_str());
  if(!fp) {
    std::cerr << "Error: cannot open stereo default file: " << filename << "\n";
    exit(EXIT_FAILURE);
  }

  std::string name, value, line;
  int c;

  while(!fp.eof()) {
    ignorespace(fp);
    if(!fp.eof() && (c = fp.peek()) != '#') {
      std::istringstream ss; //NOTE: cannot move this up with other
                             //variable declarations because then
                             //calling store(parse_config_file())
                             //multiple times does not work as
                             //expected
      getword(fp, name);
      getword(fp, value);
      line = name.append(" = ").append(value);
      ss.str(line);
      try {
        po::store(po::parse_config_file(ss, m_desc), m_vm);
      } catch (boost::program_options::unknown_option const& e) {
        vw::vw_out() << "\tWARNING --> Unknown stereo settings option: " << line << "\n";
      }
    }
    ignoreline(fp);
  }

  po::notify(m_vm);
  fp.close();
}

void StereoSettings::copy_settings(std::string const& filename, std::string const& destination) {
  std::ifstream in(filename.c_str());
  std::ofstream out(destination.c_str());
  out<<in.rdbuf(); // copy file
  in.close();
  out.close();
}

bool StereoSettings::is_search_defined() const {
  return !( search_range.min() == Vector2i() &&
            search_range.max() == Vector2i() );
}
<commit_msg>stereo: Clean up style of stereo settings<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

/// \file StereoSettings.h
///
#include <asp/Core/StereoSettings.h>

#include <vw/Core/Thread.h>
#include <vw/Core/Log.h>
#include <fstream>

namespace po = boost::program_options;
using namespace vw;

// ---------------------------------------------------
// Create a single instance of the StereoSettings
// ---------------------------------------------------
namespace {
  vw::RunOnce stereo_settings_once = VW_RUNONCE_INIT;
  boost::shared_ptr<StereoSettings> stereo_settings_ptr;
  void init_stereo_settings() {
    stereo_settings_ptr = boost::shared_ptr<StereoSettings>(new StereoSettings());
  }
}

StereoSettings& stereo_settings() {
  stereo_settings_once.run( init_stereo_settings );
  return *stereo_settings_ptr;
}

// ----------------------------------------------------------
// Utilities for parsing lines out of the stereo.default file
// ----------------------------------------------------------

// Determine whether the given character is a space character.
inline bool is_space_char(int c) {
  return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}

// Read from stream until (but not including) the next non-space character.
inline void ignorespace(std::istream& s) {
  int c;
  if(s.eof())
    return;
  while((c = s.get()) != EOF && is_space_char(c)){}
  if(c != EOF)
    s.unget();
}

// Read from stream until (but not including) the beginning of the next line.
inline void ignoreline(std::istream& s) {
  int c;
  if(s.eof())
    return;
  while((c = s.get()) != EOF && c != '\n'){}
}

// Read from stream until (but not including) the next space character. Ignores space characters at beginning.
inline void getword(std::istream& s, std::string& str) {
  int c;
  str.clear();
  ignorespace(s);
  if(s.eof())
    return;
  while((c = s.get()) != EOF && !is_space_char(c))
    str.push_back(c);
  if(c != EOF)
    s.unget();
}

//--------------------------------------------------
// StereoSettings Methods
//--------------------------------------------------
StereoSettings::StereoSettings() {

#define ASSOC(X, Y, V, D)   m_desc.add_options()(X, po::value(&(this->Y))->default_value(V), D)
#define ASSOC_SIMPLE(X, Y)  m_desc.add_options()(X, po::value(&(this->Y)))

  // ---------------------
  // Preprocessing options
  // ---------------------

  // Alignment
  ASSOC("DO_INTERESTPOINT_ALIGNMENT", keypoint_alignment, 0, "Align images using the interest point alignment method");
  ASSOC("INTERESTPOINT_ALIGNMENT_SUBSAMPLING", keypoint_align_subsampling, 1, "Image sub-sampling factor for keypoint alignment.");
  ASSOC("DO_EPIPOLAR_ALIGNMENT", epipolar_alignment, 0, "Align images using epipolar constraints");

  // Image normalization
  ASSOC("FORCE_USE_ENTIRE_RANGE", force_max_min, 0, "Use images entire values, otherwise compress image range to -+2.5 sigmas around mean.");
  ASSOC("DO_INDIVIDUAL_NORMALIZATION", individually_normalize, 0, "Normalize each image individually before processsing.");

  // -------------------
  // Correlation Options
  // -------------------

  // Preproc filter
  ASSOC("PREPROCESSING_FILTER_MODE", pre_filter_mode, 3, "selects the preprocessing filter");
  ASSOC("SLOG_KERNEL_WIDTH", slogW, 1.5, "SIGMA for the gaussian blure in LOG and SLOG");

  // Integer correlator
  ASSOC("COST_MODE", cost_mode, 2, "0 - absolute different, 1 - squared difference, 2 - normalized cross correlation");
  ASSOC("XCORR_THRESHOLD", xcorr_threshold, 2.0, "");
  ASSOC("CORRSCORE_REJECTION_THRESHOLD", corrscore_rejection_threshold, 1.1, "");
  ASSOC("COST_BLUR", cost_blur, 0, "Reduces the number of missing pixels by blurring the fitness landscape computed by the cost function.");
  ASSOC("H_KERNEL", kernel[0], 25, "kernel width");
  ASSOC("V_KERNEL", kernel[1], 25, "kernel height");

  ASSOC("H_CORR_MAX", search_range.max()[0], 0, "correlation window size max x");
  ASSOC("H_CORR_MIN", search_range.min()[0], 0, "correlation window size min x");
  ASSOC("V_CORR_MAX", search_range.max()[1], 0, "correlation window size max y");
  ASSOC("V_CORR_MIN", search_range.min()[1], 0, "correlation window size min y");

  ASSOC("SUBPIXEL_MODE", subpixel_mode, 2, "0 - no subpixel, 1 - parabola, 2 - bayes EM");
  ASSOC("SUBPIXEL_H_KERNEL", subpixel_kernel[0], 35, "subpixel kernel width");
  ASSOC("SUBPIXEL_V_KERNEL", subpixel_kernel[1], 35, "subpixel kernel height");
  ASSOC("DO_H_SUBPIXEL", do_h_subpixel, 1, "Do vertical subpixel interpolation.");
  ASSOC("DO_V_SUBPIXEL", do_v_subpixel, 1, "Do horizontal subpixel interpolation.");

  // EMSubpixelCorrelator options
  ASSOC("SUBPIXEL_EM_ITER", subpixel_em_iter, 15, "Maximum number of EM iterations for EMSubpixelCorrelator");
  ASSOC("SUBPIXEL_AFFINE_ITER", subpixel_affine_iter, 5, "Maximum number of affine optimization iterations for EMSubpixelCorrelator");
  ASSOC("SUBPIXEL_PYRAMID_LEVELS", subpixel_pyramid_levels, 3, "Number of pyramid levels for EMSubpixelCorrelator");

  // Filtering Options
  ASSOC("RM_H_HALF_KERN", rm_h_half_kern, 5, "low conf pixel removal kernel half size");
  ASSOC("RM_V_HALF_KERN", rm_v_half_kern, 5, "");
  ASSOC("RM_MIN_MATCHES", rm_min_matches, 60, "min # of pxls to be matched to keep pxl");
  ASSOC("RM_THRESHOLD", rm_threshold, 3, "rm_threshold > disp[n]-disp[m] pixels are not matching");
  ASSOC("RM_CLEANUP_PASSES", rm_cleanup_passes, 1, "number of passes for cleanup during the post-processing phase");
  ASSOC("ERODE_MAX_SIZE", erode_max_size, 1000, "max size of islands that should be removed");
  ASSOC("FILL_HOLES", fill_holes, 1, "fill holes using an inpainting method");
  ASSOC("FILL_HOLE_MAX_SIZE", fill_hole_max_size, 100000, "max size in pixels that should be filled");
  ASSOC("MASK_FLATFIELD", mask_flatfield, 0, "mask pixels that are less than 0. (for use with apollo metric camera only!)");

  // Triangulation Options
  ASSOC("UNIVERSE_CENTER", universe_center, "NONE", "center for radius measurements [CAMERA, ZERO, NONE]");
  ASSOC("NEAR_UNIVERSE_RADIUS", near_universe_radius, 0.0, "radius of inner boundary of universe [m]");
  ASSOC("FAR_UNIVERSE_RADIUS", far_universe_radius, 0.0, "radius of outer boundary of universe [m]");
  ASSOC("USE_LEAST_SQUARES", use_least_squares, 0, "use a more rigorous triangulation");

  // System Settings
  ASSOC("CACHE_DIR", cache_dir, "/tmp", "Change if can't write large files to /tmp (i.e. Super Computer)");
  ASSOC_SIMPLE("TIF_COMPRESS", tif_compress);

#undef ASSOC
#undef ASSOC_SIMPLE

  int argc = 1;
  char* argv[1];
  argv[0] = (char*)malloc(2*sizeof(char));
  argv[0][0] = 'a';
  po::store(po::parse_command_line(argc, argv, m_desc), m_vm);
  po::notify(m_vm);
}

void StereoSettings::read(std::string const& filename) {
  std::ifstream fp(filename.c_str());
  if(!fp) {
    std::cerr << "Error: cannot open stereo default file: " << filename << "\n";
    exit(EXIT_FAILURE);
  }

  std::string name, value, line;
  int c;

  while(!fp.eof()) {
    ignorespace(fp);
    if(!fp.eof() && (c = fp.peek()) != '#') {
      std::istringstream ss; //NOTE: cannot move this up with other
                             //variable declarations because then
                             //calling store(parse_config_file())
                             //multiple times does not work as
                             //expected
      getword(fp, name);
      getword(fp, value);
      line = name.append(" = ").append(value);
      ss.str(line);
      try {
        po::store(po::parse_config_file(ss, m_desc), m_vm);
      } catch (boost::program_options::unknown_option const& e) {
        vw::vw_out() << "\tWARNING --> Unknown stereo settings option: " << line << "\n";
      }
    }
    ignoreline(fp);
  }

  po::notify(m_vm);
  fp.close();
}

void StereoSettings::copy_settings(std::string const& filename, std::string const& destination) {
  std::ifstream in(filename.c_str());
  std::ofstream out(destination.c_str());
  out<<in.rdbuf(); // copy file
  in.close();
  out.close();
}

bool StereoSettings::is_search_defined() const {
  return !( search_range.min() == Vector2i() &&
            search_range.max() == Vector2i() );
}
<|endoftext|>


<commit_before>/* OpenSceneGraph example, osganimate.
*
*  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 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 <osg/Notify>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>

int main( int argc, char **argv )
{
    osg::ArgumentParser arguments(&argc,argv);

    // initialize the viewer.
    osgViewer::Viewer viewer(arguments);

    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);

    if (!model)
    {
        OSG_NOTICE<<"No models loaded, please specify a model file on the command line"<<std::endl;
        return 1;
    }

    viewer.setSceneData(model.get());

    viewer.setCameraManipulator(new osgGA::TrackballManipulator());

    return viewer.run();
}
<commit_msg>Experiments with modifying the projection matrix to provide keystoning.<commit_after>/* OpenSceneGraph example, osganimate.
*
*  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 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 <osg/Notify>
#include <osg/io_utils>

#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>

int main( int argc, char **argv )
{
    osg::ArgumentParser arguments(&argc,argv);

    // initialize the viewer.
    osgViewer::Viewer viewer(arguments);

    osg::Vec2d translate(0.0,0.0);
    osg::Vec2d scale(1.0,1.0);
    osg::Vec2d taper(1.0,1.0);
    double angle = 0; // osg::inDegrees(45.0);

    if (arguments.read("-a",angle)) { OSG_NOTICE<<"angle = "<<angle<<std::endl; angle = osg::inDegrees(angle); }
    if (arguments.read("-t",translate.x(), translate.y())) { OSG_NOTICE<<"translate = "<<translate<<std::endl;}
    if (arguments.read("-s",scale.x(), scale.y())) { OSG_NOTICE<<"scale = "<<scale<<std::endl;}
    if (arguments.read("-k",taper.x(), taper.y())) { OSG_NOTICE<<"taper = "<<taper<<std::endl;}

    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);

    if (!model)
    {
        OSG_NOTICE<<"No models loaded, please specify a model file on the command line"<<std::endl;
        return 1;
    }

    viewer.setSceneData(model.get());

    viewer.setCameraManipulator(new osgGA::TrackballManipulator());

    viewer.realize();

    viewer.getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);

    osg::Matrixd& pm = viewer.getCamera()->getProjectionMatrix();

    pm.postMultRotate(osg::Quat(angle, osg::Vec3d(0.0,0.0,1.0)));
    pm.postMultScale(osg::Vec3d(scale.x(),scale.y(),1.0));
    pm.postMultTranslate(osg::Vec3d(translate.x(),translate.y(),0.0));

    if (taper.x()!=1.0)
    {
        double x0 = (1.0+taper.x())/(1-taper.x());
        OSG_NOTICE<<"x0 = "<<x0<<std::endl;

        pm.postMult(osg::Matrixd(1.0-x0, 0.0,    0.0,    1.0,
                                 0.0,    1.0-x0, 0.0,    0.0,
                                 0.0,    0.0,    (1.0-x0)*0.5, 0.0,
                                 0.0,    0.0,    0.0,    -x0));
    }

    return viewer.run();
}
<|endoftext|>