<commit_before>//==============================================================================
// Enhanced tree view widget
//==============================================================================

#include "treeviewwidget.h"

//==============================================================================

#include <QDrag>
#include <QHeaderView>
#include <QMouseEvent>
#include <QStandardItemModel>

//==============================================================================

namespace OpenCOR {
namespace Core {

//==============================================================================

TreeViewWidget::TreeViewWidget(QWidget *pParent) :
    QTreeView(pParent),
    CommonWidget(pParent)
{
    // Set some properties for our tree view widget

    setAllColumnsShowFocus(true);
#ifdef Q_OS_MAC
    setAttribute(Qt::WA_MacShowFocusRect, 0);
    // Note: the above removes the focus border since it messes up the look of
    //       our tree view widget...
#endif
    setFrameShape(QFrame::NoFrame);
    setSelectionMode(QAbstractItemView::ExtendedSelection);
    setUniformRowHeights(true);
}

//==============================================================================

void TreeViewWidget::resizeColumnsToContents()
{
    // Resize all our columns to their contents

    for (int i = 0, iMax = header()->count(); i < iMax; ++i)
        resizeColumnToContents(i);
}

//==============================================================================

void TreeViewWidget::selectItem(const int &pRow, const int &pColumn)
{
    // Select the requested item, if any

    QStandardItemModel *treeViewModel = qobject_cast<QStandardItemModel *>(model());

    if (treeViewModel) {
        // The tree view has a model associated with it, so we can retrieve the
        // requested item

        QStandardItem *treeViewItem = treeViewModel->invisibleRootItem()->child(pRow, pColumn);

        if (treeViewItem)
            // The requested item exists, so select it...

            setCurrentIndex(treeViewItem->index());
    }
}

//==============================================================================

void TreeViewWidget::selectFirstItem()
{
    // Select the first item

    selectItem();
}

//==============================================================================

bool TreeViewWidget::isEditing() const
{
    // Return whether our tree view widget is in editing mode

    return state() == QAbstractItemView::EditingState;
}

//==============================================================================

QSize TreeViewWidget::sizeHint() const
{
    // Suggest a default size for our tree view widget
    // Note: this is critical if we want a docked widget, with a tree view
    //       widget on it, to have a decent size when docked to the main window

    return defaultSize(0.15);
}

//==============================================================================

void TreeViewWidget::mouseDoubleClickEvent(QMouseEvent *pEvent)
{
    // Retrieve the index of the item which row is the same as our current item,
    // but which column is 0, so that we can expand/collapse properly
    // Note: to retrieve the current index, we would normally use
    //       currentIndex(), but we may be double clicking on a disabled item,
    //       which means that it will never become the current index, hence we
    //       use indexAt() instead...

    QModelIndex currIndex = indexAt(pEvent->pos());
    QModelIndex index = model()->index(currIndex.row(), 0, currIndex.parent());

    if (model()->hasChildren(index)) {
        // The item has some children, so expand/collapse it

        setExpanded(index, !isExpanded(index));

        // Accept the event

        pEvent->accept();
    } else {
        // Default handling of the event

        QTreeView::mouseDoubleClickEvent(pEvent);
    }
}

//==============================================================================

void TreeViewWidget::startDrag(Qt::DropActions pSupportedActions)
{
    // This a reimplementation of QAbstractItemView::startDrag, so that we can
    // provide OpenCOR with a better pixmap for the drag object
    // Note: indeed, on Windows, the pixmap only shows the dragged item that are
    //       visible in the QTreeView. Also, if there an item covers several
    //       columns, then the pixmap will show several 'cells' some of them
    //       empty if a column is empty, so... instead we want to provide a
    //       generic pixmap which looks 'good' on all platforms...

    // Retrieve the selected draggable items, if any
    // Note: the following code is based on
    //       QAbstractItemViewPrivate::selectedDraggableIndexes...

    QModelIndexList selectedDraggableIndexes = selectedIndexes();

    for (int i = selectedDraggableIndexes.count()-1; i >= 0; --i)
        if (   !(model()->flags(selectedDraggableIndexes[i]) & Qt::ItemIsDragEnabled)
            || selectedDraggableIndexes[i].column())
            // The current selected item is not draggable or is not in the first
            // column
            // Note: regarding the test on the column number, it is because we
            //       may have a model data that requires several columns (e.g.
            //       QFileSystemModel) in which case selectedIndexes would
            //       return a number of indexes equal to the number of rows
            //       times the number of columns while we only want a number of
            //       indexes to be equal to the number of rows (since we have a
            //       selection mode of QAbstractItemView::ExtendedSelection)

            selectedDraggableIndexes.removeAt(i);

    // Start the dragging action is there is at least one selected draggable
    // item

    if (selectedDraggableIndexes.count()) {
        // There is at least one selected draggable item, so create a QMimeData
        // object for it

        QMimeData *mimeData = model()->mimeData(selectedDraggableIndexes);

        if (!mimeData)
            return;

        // Create the pixmap that will be associated with the dragging action

        QPixmap pixmap((selectedDraggableIndexes.count() == 1)?
                           ":oxygen/mimetypes/application-x-zerosize.png":
                           ":oxygen/places/document-multiple.png");

        // Create the drag object

        QDrag *drag = new QDrag(this);

        drag->setMimeData(mimeData);
        drag->setPixmap(pixmap);
        drag->setHotSpot(QPoint(0.5*pixmap.width(), 0.5*pixmap.height()));

        // Do the dragging itself

        Qt::DropAction realDefaultDropAction = Qt::IgnoreAction;

        if (   (defaultDropAction() != Qt::IgnoreAction)
            && (pSupportedActions & defaultDropAction()))
            realDefaultDropAction = defaultDropAction();
        else if (   (pSupportedActions & Qt::CopyAction)
                 && (dragDropMode() != QAbstractItemView::InternalMove))
            realDefaultDropAction = Qt::CopyAction;

        if (drag->exec(pSupportedActions, realDefaultDropAction) == Qt::MoveAction) {
            // We want to move the items
            // Note: the following code is based on
            //       QAbstractItemViewPrivate::clearOrRemove...

            const QItemSelection selection = selectionModel()->selection();

            if (!dragDropOverwriteMode()) {
                foreach (const QItemSelectionRange &itemSelectionRange, selection) {
                    QModelIndex parent = itemSelectionRange.parent();

                    if (itemSelectionRange.left())
                        continue;

                    if (itemSelectionRange.right() != (model()->columnCount(parent)-1))
                        continue;

                    model()->removeRows(itemSelectionRange.top(),
                                        itemSelectionRange.bottom()-itemSelectionRange.top()+1,
                                        parent);
                }
            } else {
                // We can't remove the rows so reset the items (i.e. the view
                // is like a table)

                foreach (const QModelIndex &index, selection.indexes()) {
                    QMap<int, QVariant> roles = model()->itemData(index);

                    for (QMap<int, QVariant>::Iterator iter = roles.begin(),
                                                       iterEnd = roles.end();
                         iter != iterEnd; ++iter)
                        iter.value() = QVariant();

                    model()->setItemData(index, roles);
                }
            }
        }
    }
}

//==============================================================================

}   // namespace Core
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up.<commit_after>//==============================================================================
// Enhanced tree view widget
//==============================================================================

#include "treeviewwidget.h"

//==============================================================================

#include <QDrag>
#include <QHeaderView>
#include <QMouseEvent>
#include <QStandardItemModel>

//==============================================================================

namespace OpenCOR {
namespace Core {

//==============================================================================

TreeViewWidget::TreeViewWidget(QWidget *pParent) :
    QTreeView(pParent),
    CommonWidget(pParent)
{
    // Set some properties for our tree view widget

    setAllColumnsShowFocus(true);
#ifdef Q_OS_MAC
    setAttribute(Qt::WA_MacShowFocusRect, 0);
    // Note: the above removes the focus border since it messes up the look of
    //       our tree view widget...
#endif
    setFrameShape(QFrame::NoFrame);
    setSelectionMode(QAbstractItemView::ExtendedSelection);
    setUniformRowHeights(true);
}

//==============================================================================

void TreeViewWidget::resizeColumnsToContents()
{
    // Resize all our columns to their contents

    for (int i = 0, iMax = header()->count(); i < iMax; ++i)
        resizeColumnToContents(i);
}

//==============================================================================

void TreeViewWidget::selectItem(const int &pRow, const int &pColumn)
{
    // Select the requested item, if any

    QStandardItemModel *treeViewModel = qobject_cast<QStandardItemModel *>(model());

    if (treeViewModel) {
        // The tree view has a model associated with it, so we can retrieve the
        // requested item

        QStandardItem *treeViewItem = treeViewModel->invisibleRootItem()->child(pRow, pColumn);

        if (treeViewItem)
            // The requested item exists, so select it...

            setCurrentIndex(treeViewItem->index());
    }
}

//==============================================================================

void TreeViewWidget::selectFirstItem()
{
    // Select the first item

    selectItem();
}

//==============================================================================

bool TreeViewWidget::isEditing() const
{
    // Return whether our tree view widget is in editing mode

    return state() == QAbstractItemView::EditingState;
}

//==============================================================================

QSize TreeViewWidget::sizeHint() const
{
    // Suggest a default size for our tree view widget
    // Note: this is critical if we want a docked widget, with a tree view
    //       widget on it, to have a decent size when docked to the main window

    return defaultSize(0.15);
}

//==============================================================================

void TreeViewWidget::mouseDoubleClickEvent(QMouseEvent *pEvent)
{
    // Retrieve the index of the item which row is the same as our current item,
    // but which column is 0, so that we can expand/collapse properly

    QModelIndex currIndex = currentIndex();

    if (model()->hasChildren(currIndex)) {
        // The item has some children, so expand/collapse it

        setExpanded(currIndex, !isExpanded(currIndex));

        // Accept the event

        pEvent->accept();
    } else {
        // Default handling of the event

        QTreeView::mouseDoubleClickEvent(pEvent);
    }
}

//==============================================================================

void TreeViewWidget::startDrag(Qt::DropActions pSupportedActions)
{
    // This a reimplementation of QAbstractItemView::startDrag, so that we can
    // provide OpenCOR with a better pixmap for the drag object
    // Note: indeed, on Windows, the pixmap only shows the dragged item that are
    //       visible in the QTreeView. Also, if there an item covers several
    //       columns, then the pixmap will show several 'cells' some of them
    //       empty if a column is empty, so... instead we want to provide a
    //       generic pixmap which looks 'good' on all platforms...

    // Retrieve the selected draggable items, if any
    // Note: the following code is based on
    //       QAbstractItemViewPrivate::selectedDraggableIndexes...

    QModelIndexList selectedDraggableIndexes = selectedIndexes();

    for (int i = selectedDraggableIndexes.count()-1; i >= 0; --i)
        if (   !(model()->flags(selectedDraggableIndexes[i]) & Qt::ItemIsDragEnabled)
            || selectedDraggableIndexes[i].column())
            // The current selected item is not draggable or is not in the first
            // column
            // Note: regarding the test on the column number, it is because we
            //       may have a model data that requires several columns (e.g.
            //       QFileSystemModel) in which case selectedIndexes would
            //       return a number of indexes equal to the number of rows
            //       times the number of columns while we only want a number of
            //       indexes to be equal to the number of rows (since we have a
            //       selection mode of QAbstractItemView::ExtendedSelection)

            selectedDraggableIndexes.removeAt(i);

    // Start the dragging action is there is at least one selected draggable
    // item

    if (selectedDraggableIndexes.count()) {
        // There is at least one selected draggable item, so create a QMimeData
        // object for it

        QMimeData *mimeData = model()->mimeData(selectedDraggableIndexes);

        if (!mimeData)
            return;

        // Create the pixmap that will be associated with the dragging action

        QPixmap pixmap((selectedDraggableIndexes.count() == 1)?
                           ":oxygen/mimetypes/application-x-zerosize.png":
                           ":oxygen/places/document-multiple.png");

        // Create the drag object

        QDrag *drag = new QDrag(this);

        drag->setMimeData(mimeData);
        drag->setPixmap(pixmap);
        drag->setHotSpot(QPoint(0.5*pixmap.width(), 0.5*pixmap.height()));

        // Do the dragging itself

        Qt::DropAction realDefaultDropAction = Qt::IgnoreAction;

        if (   (defaultDropAction() != Qt::IgnoreAction)
            && (pSupportedActions & defaultDropAction()))
            realDefaultDropAction = defaultDropAction();
        else if (   (pSupportedActions & Qt::CopyAction)
                 && (dragDropMode() != QAbstractItemView::InternalMove))
            realDefaultDropAction = Qt::CopyAction;

        if (drag->exec(pSupportedActions, realDefaultDropAction) == Qt::MoveAction) {
            // We want to move the items
            // Note: the following code is based on
            //       QAbstractItemViewPrivate::clearOrRemove...

            const QItemSelection selection = selectionModel()->selection();

            if (!dragDropOverwriteMode()) {
                foreach (const QItemSelectionRange &itemSelectionRange, selection) {
                    QModelIndex parent = itemSelectionRange.parent();

                    if (itemSelectionRange.left())
                        continue;

                    if (itemSelectionRange.right() != (model()->columnCount(parent)-1))
                        continue;

                    model()->removeRows(itemSelectionRange.top(),
                                        itemSelectionRange.bottom()-itemSelectionRange.top()+1,
                                        parent);
                }
            } else {
                // We can't remove the rows so reset the items (i.e. the view
                // is like a table)

                foreach (const QModelIndex &index, selection.indexes()) {
                    QMap<int, QVariant> roles = model()->itemData(index);

                    for (QMap<int, QVariant>::Iterator iter = roles.begin(),
                                                       iterEnd = roles.end();
                         iter != iterEnd; ++iter)
                        iter.value() = QVariant();

                    model()->setItemData(index, roles);
                }
            }
        }
    }
}

//==============================================================================

}   // namespace Core
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/* Copyright 2010 Jukka Jylnki

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

/** @file UnixClock.cpp
	@brief */

#include <cassert>

#include <time.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>

#include "kNet/Clock.h"
#include "kNet/NetworkLogging.h"

namespace kNet
{

tick_t Clock::appStartTime = 0;

Clock impl;

void Clock::InitClockData()
{
	if (appStartTime == 0)
		appStartTime = Tick();
}

Clock::Clock()
{
	InitClockData();
}

void Clock::Sleep(int milliseconds)
{
	// http://linux.die.net/man/2/nanosleep
	timespec ts;
	ts.tv_sec = milliseconds / 1000;
	ts.tv_nsec = (milliseconds - ts.tv_sec * 1000) * 1000 * 1000;
	int ret = nanosleep(&ts, NULL);
	if (ret == -1)
		LOG(LogError, "nanosleep returned -1! Reason: %s(%d).", strerror(errno), (int)errno);
}

int Clock::Year()
{
	///\todo.
	return 0;
}

int Clock::Month()
{
	///\todo.
	return 0;
}

int Clock::Day()
{
	///\todo.
	return 0;
}

int Clock::Hour()
{
	///\todo.
	return 0;
}

int Clock::Min()
{
	///\todo.
	return 0;
}

int Clock::Sec()
{
	///\todo.
	return 0;
}

unsigned long Clock::SystemTime()
{
	return TickU32();
}

unsigned long Clock::Time()
{
	return (unsigned long)(Tick() - appStartTime);
}

tick_t Clock::Tick()
{
#ifdef _POSIX_MONOTONIC_CLOCK
	timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
    return (tick_t)t.tv_sec * 1000 * 1000 * 1000 + (tick_t)t.tv_nsec;
#elif _POSIX_C_SOURCE
	timeval t;
	gettimeofday(&t, NULL);
	return (tick_t)t.tv_sec * 1000 * 1000 + (tick_t)t.tv_usec;
#else
	return (tick_t)time(NULL);
#endif
}

unsigned long Clock::TickU32()
{
	return (unsigned long)Tick();
}

tick_t Clock::TicksPerSec()
{
#ifdef _POSIX_MONOTONIC_CLOCK
    return 1000 * 1000 * 1000;
#elif _POSIX_C_SOURCE
    return 1000 * 1000;
#else
    return 1;
#endif
}

} // ~kNet
<commit_msg>Fixed poor 1-second timer granularity in Clock::Tick() for Mac.<commit_after>/* Copyright 2010 Jukka Jylnki

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

/** @file UnixClock.cpp
	@brief */

#include <cassert>

#include <time.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>

#include "kNet/Clock.h"
#include "kNet/NetworkLogging.h"

namespace kNet
{

tick_t Clock::appStartTime = 0;

Clock impl;

void Clock::InitClockData()
{
	if (appStartTime == 0)
		appStartTime = Tick();
}

Clock::Clock()
{
	InitClockData();
}

void Clock::Sleep(int milliseconds)
{
	// http://linux.die.net/man/2/nanosleep
	timespec ts;
	ts.tv_sec = milliseconds / 1000;
	ts.tv_nsec = (milliseconds - ts.tv_sec * 1000) * 1000 * 1000;
	int ret = nanosleep(&ts, NULL);
	if (ret == -1)
		LOG(LogError, "nanosleep returned -1! Reason: %s(%d).", strerror(errno), (int)errno);
}

int Clock::Year()
{
	///\todo.
	return 0;
}

int Clock::Month()
{
	///\todo.
	return 0;
}

int Clock::Day()
{
	///\todo.
	return 0;
}

int Clock::Hour()
{
	///\todo.
	return 0;
}

int Clock::Min()
{
	///\todo.
	return 0;
}

int Clock::Sec()
{
	///\todo.
	return 0;
}

unsigned long Clock::SystemTime()
{
	return TickU32();
}

unsigned long Clock::Time()
{
	return (unsigned long)(Tick() - appStartTime);
}

tick_t Clock::Tick()
{
#ifdef _POSIX_MONOTONIC_CLOCK
	timespec t;
	clock_gettime(CLOCK_MONOTONIC, &t);
    return (tick_t)t.tv_sec * 1000 * 1000 * 1000 + (tick_t)t.tv_nsec;
//_POSIX_C_SOURCE is not defined on OSX
#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
	timeval t;
	gettimeofday(&t, NULL);
	return (tick_t)t.tv_sec * 1000 * 1000 + (tick_t)t.tv_usec;
#else
	return (tick_t)time(NULL);
#endif
}

unsigned long Clock::TickU32()
{
	return (unsigned long)Tick();
}

tick_t Clock::TicksPerSec()
{
#ifdef _POSIX_MONOTONIC_CLOCK
    return 1000 * 1000 * 1000;
//_POSIX_C_SOURCE is not defined on OSX
#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
    return 1000 * 1000;
#else
    return 1;
#endif
}

} // ~kNet
<|endoftext|>


<commit_before>//
//
// Copyright (C) 2005 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2005 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
//////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES

// APPLICATION INCLUDES
#include <utl/UtlRegex.h>
#include "os/OsDateTime.h"
#include "os/OsSysLog.h"
#include "sipdb/SIPDBManager.h"
#include "sipdb/PermissionDB.h"
#include "sipdb/ResultSet.h"
#include "SipRedirectorMapping.h"

// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS

// Constructor
SipRedirectorMapping::SipRedirectorMapping() :
   mMappingRulesLoaded(OS_FAILED)
{
}

// Destructor
SipRedirectorMapping::~SipRedirectorMapping()
{
}

// Initialize
OsStatus
SipRedirectorMapping::initialize(const UtlHashMap& configParameters,
                                 OsConfigDb& configDb,
                                 SipUserAgent* pSipUserAgent,
                                 int redirectorNo)
{
   UtlString s;
   s = "configDir";
   const UtlString* configDir =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "mediaServer";
   const UtlString* mediaServer =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "voicemailServer";
   const UtlString* voicemailServer =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "localDomainHost";
   const UtlString* localDomainHost =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "mappingRulesFilename";
   const UtlString* mappingRulesFilename =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "reportingName";
   mName = *dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "fallback";
   mFallback =
      (*dynamic_cast<UtlString*> (configParameters.findValue(&s))).
      compareTo("true") == 0;

   UtlString fileName =
      *configDir + OsPathBase::separator + *mappingRulesFilename;
   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                 "SipRedirectorMapping::SipRedirectorMapping Loading mapping rules from '%s'",
                 fileName.data());

   mMappingRulesLoaded = mMap.loadMappings(fileName,
                                           *mediaServer,
                                           *voicemailServer,
                                           *localDomainHost);

   return mMappingRulesLoaded ? OS_SUCCESS : OS_FAILED;
}

// Finalize
void
SipRedirectorMapping::finalize()
{
}

SipRedirector::LookUpStatus
SipRedirectorMapping::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   SipMessage& response,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage)
{
   UtlBoolean isPSTNNumber = false;
   UtlString permissionName;
   ResultSet urlMappingRegistrations;
   ResultSet urlMappingPermissions;

   // Return immediately if this is a "fallback" mapping and there are
   // already contacts.
   if (mFallback &&
       response.getCountHeaderFields(SIP_CONTACT_FIELD) > 0)
   {
      return SipRedirector::LOOKUP_SUCCESS;
   }

   // @JC This variable is strangely overloaded
   // If we have no permissions then add any encountered
   // contacts. If we do have permissions then the
   // permission must match
   UtlBoolean permissionFound = TRUE;

   if (mMappingRulesLoaded == OS_SUCCESS)
   {
      mMap.getContactList(
         requestUri,
         urlMappingRegistrations,
         isPSTNNumber,
         urlMappingPermissions);
   }

   int numUrlMappingPermissions = urlMappingPermissions.getSize();

   OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp "
                  "got %d UrlMapping Permission requirements for %d contacts",
                  numUrlMappingPermissions, urlMappingRegistrations.getSize());

   if (numUrlMappingPermissions > 0)
   {
      // check if we have field parameter that indicates that some permissions should be ignored
      UtlString ignorePermissionStr;
      // :KLUDGE: remove const_cast and uri declaration after XSL-88 gets fixed
      Url& uri = const_cast<Url&>(requestUri);
      uri.getUrlParameter("sipx-noroute", ignorePermissionStr);

      for (int i = 0; i<numUrlMappingPermissions; i++)
      {
         UtlHashMap record;
         urlMappingPermissions.getIndex(i, record);
         UtlString permissionKey("permission");
         UtlString urlMappingPermissionStr =
            *((UtlString*) record.findValue(&permissionKey));

         // Try to match the permission
         // so assume it cannot be found unless we
         // see a match in the IMDB
         permissionFound = FALSE;

         // if the permission we are looking for is the one the we are supposed to ignore,
         // than assume that permission is not found
         if (urlMappingPermissionStr.compareTo(ignorePermissionStr, UtlString::ignoreCase) == 0)
         {
             OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp "
                       "ignoring permission %s", ignorePermissionStr.data());
             continue;
         }

         // See if we can find a matching permission in the IMDB
         ResultSet dbPermissions;

         // check in permission database is user has permisssion for voicemail
         PermissionDB::getInstance()->
            getPermissions(requestUri, dbPermissions);

         int numDBPermissions = dbPermissions.getSize();

         OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp"
                       " %d permissions configured for %s", numDBPermissions,
                       requestUri.toString().data());

         if (numDBPermissions > 0)
         {
            for (int j=0; j<numDBPermissions; j++)
            {
               dbPermissions.getIndex(j, record);
               UtlString dbPermissionStr =
                  *((UtlString*)record.
                    findValue(&permissionKey));

               OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp"
                             " checking '%s'", dbPermissionStr.data());

               if (dbPermissionStr.compareTo(urlMappingPermissionStr, UtlString::ignoreCase) == 0)
               {
                  // matching permission found in IMDB
                  permissionFound = TRUE;
                  break;
               }
               dbPermissionStr.remove(0);
            }
         }

         if (permissionFound)
         {
            break;
         }
         urlMappingPermissionStr.remove(0);
      }
   }

   // either there were no requirements to match against voicemail
   // or there were and we found a match in the IMDB for the URI
   // so now add the contacts to the SIP message
   if (permissionFound)
   {
      int numUrlMappingRegistrations = urlMappingRegistrations.getSize();

      OsSysLog::add(FAC_SIP, PRI_DEBUG,
                    "SipRedirectorMapping::lookUp "
                    "got %d UrlMapping Contacts", numUrlMappingRegistrations);

      if (numUrlMappingRegistrations > 0)
      {
         UtlString requestIdentity;
         requestUri.getIdentity(requestIdentity);

         for (int i = 0; i < numUrlMappingRegistrations; i++)
         {
            UtlHashMap record;
            urlMappingRegistrations.getIndex(i, record);
            UtlString contactKey("contact");
            UtlString contact= *((UtlString*)record.findValue(&contactKey));
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipRedirectorMapping::lookUp "
                          "contact = '%s'", contact.data());
            Url contactUri(contact);
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipRedirectorMapping::lookUp "
                          "contactUri = '%s'", contactUri.toString().data());

            // prevent recursive loops
            if (!contactUri.isUserHostPortEqual(requestUri))
            {
               // Add the contact.
               addContact(response, requestString, contactUri, mName.data());
            }
         }
      }
   }

   return SipRedirector::LOOKUP_SUCCESS;
}
<commit_msg>Check in Hannu's fix to a reported registrar crash<commit_after>//
//
// Copyright (C) 2005 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2005 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
//////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES

// APPLICATION INCLUDES
#include <utl/UtlRegex.h>
#include "os/OsDateTime.h"
#include "os/OsSysLog.h"
#include "sipdb/SIPDBManager.h"
#include "sipdb/PermissionDB.h"
#include "sipdb/ResultSet.h"
#include "SipRedirectorMapping.h"

// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS

// Constructor
SipRedirectorMapping::SipRedirectorMapping() :
   mMappingRulesLoaded(OS_FAILED)
{
}

// Destructor
SipRedirectorMapping::~SipRedirectorMapping()
{
}

// Initialize
OsStatus
SipRedirectorMapping::initialize(const UtlHashMap& configParameters,
                                 OsConfigDb& configDb,
                                 SipUserAgent* pSipUserAgent,
                                 int redirectorNo)
{
   UtlString s;
   s = "configDir";
   const UtlString* configDir =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "mediaServer";
   const UtlString* mediaServer =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "voicemailServer";
   const UtlString* voicemailServer =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "localDomainHost";
   const UtlString* localDomainHost =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "mappingRulesFilename";
   const UtlString* mappingRulesFilename =
      dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "reportingName";
   mName = *dynamic_cast<UtlString*> (configParameters.findValue(&s));
   s = "fallback";
   mFallback =
      (*dynamic_cast<UtlString*> (configParameters.findValue(&s))).
      compareTo("true") == 0;

   UtlString fileName =
      *configDir + OsPathBase::separator + *mappingRulesFilename;
   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                 "SipRedirectorMapping::SipRedirectorMapping Loading mapping rules from '%s'",
                 fileName.data());

   mMappingRulesLoaded = mMap.loadMappings(fileName,
                                           *mediaServer,
                                           *voicemailServer,
                                           *localDomainHost);

   return mMappingRulesLoaded ? OS_SUCCESS : OS_FAILED;
}

// Finalize
void
SipRedirectorMapping::finalize()
{
}

SipRedirector::LookUpStatus
SipRedirectorMapping::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   SipMessage& response,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage)
{
   UtlBoolean isPSTNNumber = false;
   UtlString permissionName;
   ResultSet urlMappingRegistrations;
   ResultSet urlMappingPermissions;

   // Return immediately if this is a "fallback" mapping and there are
   // already contacts.
   if (mFallback &&
       response.getCountHeaderFields(SIP_CONTACT_FIELD) > 0)
   {
      return SipRedirector::LOOKUP_SUCCESS;
   }

   // @JC This variable is strangely overloaded
   // If we have no permissions then add any encountered
   // contacts. If we do have permissions then the
   // permission must match
   UtlBoolean permissionFound = TRUE;

   if (mMappingRulesLoaded == OS_SUCCESS)
   {
      mMap.getContactList(
         requestUri,
         urlMappingRegistrations,
         isPSTNNumber,
         urlMappingPermissions);
   }

   int numUrlMappingPermissions = urlMappingPermissions.getSize();

   OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp "
                  "got %d UrlMapping Permission requirements for %d contacts",
                  numUrlMappingPermissions, urlMappingRegistrations.getSize());

   if (numUrlMappingPermissions > 0)
   {
      // check if we have field parameter that indicates that some permissions should be ignored
      UtlString ignorePermissionStr;
      // :KLUDGE: remove const_cast and uri declaration after XSL-88 gets fixed
      Url& uri = const_cast<Url&>(requestUri);
      uri.getUrlParameter("sipx-noroute", ignorePermissionStr);

      for (int i = 0; i<numUrlMappingPermissions; i++)
      {
         UtlHashMap record;
         urlMappingPermissions.getIndex(i, record);
         UtlString permissionKey("permission");
         UtlString urlMappingPermissionStr =
            *((UtlString*) record.findValue(&permissionKey));

         // Try to match the permission
         // so assume it cannot be found unless we
         // see a match in the IMDB
         permissionFound = FALSE;

         // if the permission we are looking for is the one the we are supposed to ignore,
         // than assume that permission is not found
         if (urlMappingPermissionStr.compareTo(ignorePermissionStr, UtlString::ignoreCase) == 0)
         {
             OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp "
                       "ignoring permission %s", ignorePermissionStr.data());
             continue;
         }

         // See if we can find a matching permission in the IMDB
         ResultSet dbPermissions;

         // check in permission database is user has permisssion for voicemail
         PermissionDB::getInstance()->
            getPermissions(requestUri, dbPermissions);

         int numDBPermissions = dbPermissions.getSize();

         OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp"
                       " %d permissions configured for %s", numDBPermissions,
                       requestUri.toString().data());

         if (numDBPermissions > 0)
         {
            for (int j=0; j<numDBPermissions; j++)
            {
               UtlHashMap record;
               dbPermissions.getIndex(j, record);
               UtlString dbPermissionStr =
                  *((UtlString*)record.
                    findValue(&permissionKey));

               OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRedirectorMapping::lookUp"
                             " checking '%s'", dbPermissionStr.data());

               if (dbPermissionStr.compareTo(urlMappingPermissionStr, UtlString::ignoreCase) == 0)
               {
                  // matching permission found in IMDB
                  permissionFound = TRUE;
                  break;
               }
               dbPermissionStr.remove(0);
            }
         }

         if (permissionFound)
         {
            break;
         }
         urlMappingPermissionStr.remove(0);
      }
   }

   // either there were no requirements to match against voicemail
   // or there were and we found a match in the IMDB for the URI
   // so now add the contacts to the SIP message
   if (permissionFound)
   {
      int numUrlMappingRegistrations = urlMappingRegistrations.getSize();

      OsSysLog::add(FAC_SIP, PRI_DEBUG,
                    "SipRedirectorMapping::lookUp "
                    "got %d UrlMapping Contacts", numUrlMappingRegistrations);

      if (numUrlMappingRegistrations > 0)
      {
         UtlString requestIdentity;
         requestUri.getIdentity(requestIdentity);

         for (int i = 0; i < numUrlMappingRegistrations; i++)
         {
            UtlHashMap record;
            urlMappingRegistrations.getIndex(i, record);
            UtlString contactKey("contact");
            UtlString contact= *((UtlString*)record.findValue(&contactKey));
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipRedirectorMapping::lookUp "
                          "contact = '%s'", contact.data());
            Url contactUri(contact);
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipRedirectorMapping::lookUp "
                          "contactUri = '%s'", contactUri.toString().data());

            // prevent recursive loops
            if (!contactUri.isUserHostPortEqual(requestUri))
            {
               // Add the contact.
               addContact(response, requestString, contactUri, mName.data());
            }
         }
      }
   }

   return SipRedirector::LOOKUP_SUCCESS;
}
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "WeatherPlugin.h"

// Marble
#include "ui_WeatherConfigWidget.h"
#include "WeatherData.h"
#include "WeatherModel.h"
#include "MarbleDirs.h"
#include "MarbleLocale.h"
#include "global.h"
#include "weatherGlobal.h"
#include "MarbleDebug.h"

// Qt
#include <QtGui/QComboBox>
#include <QtGui/QDialog>
#include <QtGui/QIcon>
#include <QtGui/QPushButton>

using namespace Marble;
/* TRANSLATOR Marble::WeatherPlugin */

const quint32 numberOfStationsPerFetch = 20;

WeatherPlugin::WeatherPlugin()
    : m_isInitialized( false ),
      m_updateInterval( 0 ),
      m_icon(),
      m_configDialog( 0 ),
      ui_configWidget( 0 ),
      m_settings()
{
    m_icon.addFile( MarbleDirs::path( "weather/weather-clear.png" ) );
    setNameId( "weather" );
    setVersion( "1.0" );
    setCopyrightYear( 2009 );
    addAuthor( "Bastian Holst", "bastianholst@gmx.de" );
    setDataText( tr( "Supported by backstage.bbc.co.uk.\nWeather data from UK MET Office" ) );

    // Plugin is enabled by default
    setEnabled( true );
    // Plugin is not visible by default
    setVisible( false );

    connect( this, SIGNAL( settingsChanged( QString ) ),
             this, SLOT( updateItemSettings() ) );

    setSettings( QHash<QString,QVariant>() );
}

WeatherPlugin::~WeatherPlugin()
{
    delete m_configDialog;
    delete ui_configWidget;
}

void WeatherPlugin::initialize()
{
    readSettings();

    WeatherModel *model = new WeatherModel( pluginManager(), this );

    setModel( model );
    updateSettings();
    updateItemSettings();

    m_isInitialized = true;
}

bool WeatherPlugin::isInitialized() const
{
    return m_isInitialized;
}

QString WeatherPlugin::name() const
{
    return tr( "Weather" );
}

QString WeatherPlugin::guiString() const
{
    return tr( "&Weather" );
}

QString WeatherPlugin::description() const
{
    return tr( "Download weather information from many weather stations all around the world" );
}

QIcon WeatherPlugin::icon() const
{
    return m_icon;
}

QDialog *WeatherPlugin::configDialog()
{
    if ( !m_configDialog ) {
        // Initializing configuration dialog
        m_configDialog = new QDialog();
        ui_configWidget = new Ui::WeatherConfigWidget;
        ui_configWidget->setupUi( m_configDialog );
        readSettings();
        connect( ui_configWidget->m_buttonBox, SIGNAL( accepted() ),
                                              SLOT( writeSettings() ) );
        connect( ui_configWidget->m_buttonBox, SIGNAL( rejected() ),
                                              SLOT( readSettings() ) );
        QPushButton *applyButton = ui_configWidget->m_buttonBox->button( QDialogButtonBox::Apply );
        connect( applyButton, SIGNAL( clicked() ),
                 this,        SLOT( writeSettings() ) );
    }
    return m_configDialog;
}

QHash<QString,QVariant> WeatherPlugin::settings() const
{
    return m_settings;
}

void WeatherPlugin::setSettings( QHash<QString,QVariant> settings )
{
    // Check if all fields are filled and fill them with default values.
    // Information
    if ( !settings.contains( "showCondition" ) ) {
        settings.insert( "showCondition", showConditionDefault );
    }

    if ( !settings.contains( "showTemperature" ) ) {
        settings.insert( "showTemperature", showTemperatureDefault );
    }

    if ( !settings.contains( "showWindDirection" ) ) {
        settings.insert( "showWindDirection", showWindDirectionDefault );
    }

    if ( !settings.contains( "showWindSpeed" ) ) {
        settings.insert( "showWindSpeed", showWindSpeedDefault );
    }

    // Units
    // The default units depend on the global measure system.
    MarbleLocale *locale = MarbleGlobal::getInstance()->locale();
    if ( !settings.contains( "temperatureUnit" ) ) {
        int temperatureUnit;
        if ( locale->measurementSystem() == QLocale::MetricSystem ) {
            temperatureUnit = WeatherData::Celsius;
        }
        else {
            temperatureUnit = WeatherData::Fahrenheit;
        }
        settings.insert( "temperatureUnit", temperatureUnit );
    }

    if ( !settings.contains( "windSpeedUnit" ) ) {
        int windSpeedUnit;
        if ( locale->measurementSystem() == QLocale::MetricSystem ) {
            windSpeedUnit = WeatherData::kph;
        }
        else {
            windSpeedUnit = WeatherData::mph;
        }
        settings.insert( "windSpeedUnit", windSpeedUnit );
    }

    if ( !settings.contains( "pressureUnit" ) ) {
        int pressureUnit;
        if ( locale->measurementSystem() == QLocale::MetricSystem ) {
            pressureUnit = WeatherData::HectoPascal;
        }
        else {
            pressureUnit = WeatherData::inchHg;
        }
        settings.insert( "pressureUnit", pressureUnit );
    }

    m_settings = settings;
    readSettings();

    emit settingsChanged( nameId() );
    updateSettings();
}

void WeatherPlugin::readSettings()
{
    if ( !m_configDialog ) {
        return;
    }

    // Information
    if ( m_settings.value( "showCondition" ).toBool() )
        ui_configWidget->m_weatherConditionBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_weatherConditionBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "showTemperature" ).toBool() )
        ui_configWidget->m_temperatureBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_temperatureBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "showWindDirection" ).toBool() )
        ui_configWidget->m_windDirectionBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_windDirectionBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "showWindSpeed" ).toBool() )
        ui_configWidget->m_windSpeedBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_windSpeedBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "onlyFavorites" ).toBool() )
        ui_configWidget->m_onlyFavoritesBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_onlyFavoritesBox->setCheckState( Qt::Unchecked );

    // Units
    ui_configWidget->m_temperatureComboBox
        ->setCurrentIndex( m_settings.value( "temperatureUnit" ).toInt() );

    ui_configWidget->m_windSpeedComboBox
        ->setCurrentIndex( m_settings.value( "windSpeedUnit" ).toInt() );

    ui_configWidget->m_pressureComboBox
        ->setCurrentIndex( m_settings.value( "pressureUnit" ).toInt() );

    // Misc
    ui_configWidget->m_updateIntervalBox
        ->setValue( m_settings.value( "updateInterval", 3 ).toInt() );
}

void WeatherPlugin::writeSettings()
{
    // Information
    m_settings.insert( "showCondition",
                       ui_configWidget->m_weatherConditionBox->checkState() == Qt::Checked );
    m_settings.insert( "showTemperature",
                       ui_configWidget->m_temperatureBox->checkState() == Qt::Checked );
    m_settings.insert( "showWindDirection",
                       ui_configWidget->m_windDirectionBox->checkState() == Qt::Checked );
    m_settings.insert( "showWindSpeed",
                       ui_configWidget->m_windSpeedBox->checkState() == Qt::Checked );

    // Units
    m_settings.insert( "temperatureUnit", ui_configWidget->m_temperatureComboBox->currentIndex() );
    m_settings.insert( "windSpeedUnit", ui_configWidget->m_windSpeedComboBox->currentIndex() );
    m_settings.insert( "pressureUnit", ui_configWidget->m_pressureComboBox->currentIndex() );

    // Misc
    bool onlyFavorites = ( ui_configWidget->m_onlyFavoritesBox->checkState() == Qt::Checked );
    m_settings.insert( "onlyFavorites", onlyFavorites );

    m_updateInterval = ui_configWidget->m_updateIntervalBox->value();
    m_settings.insert( "updateInterval", m_updateInterval );

    emit settingsChanged( nameId() );
    updateSettings();
}

void WeatherPlugin::updateSettings()
{
    if ( model() ) {
        bool favoritesOnly = m_settings.value( "onlyFavorites", false ).toBool();
        QList<QString> favoriteItems = m_settings.value( "favoriteItems" ).toString()
                .split(",", QString::SkipEmptyParts);

        model()->setFavoriteItems( favoriteItems );
        setNumberOfItems( favoritesOnly ? favoriteItems.size() : numberOfStationsPerFetch );
        model()->setFavoriteItemsOnly( favoritesOnly );
    }
}

void WeatherPlugin::updateItemSettings()
{
    AbstractDataPluginModel *abstractModel = model();
    if( abstractModel != 0 ) {
        abstractModel->setItemSettings( m_settings );
    }
}

void WeatherPlugin::favoriteItemsChanged( const QStringList& favoriteItems )
{
    m_settings["favoriteItems"] = favoriteItems.join( "," );
    emit settingsChanged( nameId() );
    updateSettings();
}

Q_EXPORT_PLUGIN2(WeatherPlugin, Marble::WeatherPlugin)

#include "WeatherPlugin.moc"
<commit_msg>Add Valery Kharitonov to the plugin authors.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "WeatherPlugin.h"

// Marble
#include "ui_WeatherConfigWidget.h"
#include "WeatherData.h"
#include "WeatherModel.h"
#include "MarbleDirs.h"
#include "MarbleLocale.h"
#include "global.h"
#include "weatherGlobal.h"
#include "MarbleDebug.h"

// Qt
#include <QtGui/QComboBox>
#include <QtGui/QDialog>
#include <QtGui/QIcon>
#include <QtGui/QPushButton>

using namespace Marble;
/* TRANSLATOR Marble::WeatherPlugin */

const quint32 numberOfStationsPerFetch = 20;

WeatherPlugin::WeatherPlugin()
    : m_isInitialized( false ),
      m_updateInterval( 0 ),
      m_icon(),
      m_configDialog( 0 ),
      ui_configWidget( 0 ),
      m_settings()
{
    m_icon.addFile( MarbleDirs::path( "weather/weather-clear.png" ) );
    setNameId( "weather" );
    setVersion( "1.1" );
    setCopyrightYears( QList<int>() << 2009 << 2011 );
    addAuthor( "Bastian Holst", "bastianholst@gmx.de" );
    addAuthor( "Valery Kharitonov", "kharvd@gmail.com" );
    setDataText( tr( "Supported by backstage.bbc.co.uk.\nWeather data from UK MET Office" ) );

    // Plugin is enabled by default
    setEnabled( true );
    // Plugin is not visible by default
    setVisible( false );

    connect( this, SIGNAL( settingsChanged( QString ) ),
             this, SLOT( updateItemSettings() ) );

    setSettings( QHash<QString,QVariant>() );
}

WeatherPlugin::~WeatherPlugin()
{
    delete m_configDialog;
    delete ui_configWidget;
}

void WeatherPlugin::initialize()
{
    readSettings();

    WeatherModel *model = new WeatherModel( pluginManager(), this );

    setModel( model );
    updateSettings();
    updateItemSettings();

    m_isInitialized = true;
}

bool WeatherPlugin::isInitialized() const
{
    return m_isInitialized;
}

QString WeatherPlugin::name() const
{
    return tr( "Weather" );
}

QString WeatherPlugin::guiString() const
{
    return tr( "&Weather" );
}

QString WeatherPlugin::description() const
{
    return tr( "Download weather information from many weather stations all around the world" );
}

QIcon WeatherPlugin::icon() const
{
    return m_icon;
}

QDialog *WeatherPlugin::configDialog()
{
    if ( !m_configDialog ) {
        // Initializing configuration dialog
        m_configDialog = new QDialog();
        ui_configWidget = new Ui::WeatherConfigWidget;
        ui_configWidget->setupUi( m_configDialog );
        readSettings();
        connect( ui_configWidget->m_buttonBox, SIGNAL( accepted() ),
                                              SLOT( writeSettings() ) );
        connect( ui_configWidget->m_buttonBox, SIGNAL( rejected() ),
                                              SLOT( readSettings() ) );
        QPushButton *applyButton = ui_configWidget->m_buttonBox->button( QDialogButtonBox::Apply );
        connect( applyButton, SIGNAL( clicked() ),
                 this,        SLOT( writeSettings() ) );
    }
    return m_configDialog;
}

QHash<QString,QVariant> WeatherPlugin::settings() const
{
    return m_settings;
}

void WeatherPlugin::setSettings( QHash<QString,QVariant> settings )
{
    // Check if all fields are filled and fill them with default values.
    // Information
    if ( !settings.contains( "showCondition" ) ) {
        settings.insert( "showCondition", showConditionDefault );
    }

    if ( !settings.contains( "showTemperature" ) ) {
        settings.insert( "showTemperature", showTemperatureDefault );
    }

    if ( !settings.contains( "showWindDirection" ) ) {
        settings.insert( "showWindDirection", showWindDirectionDefault );
    }

    if ( !settings.contains( "showWindSpeed" ) ) {
        settings.insert( "showWindSpeed", showWindSpeedDefault );
    }

    // Units
    // The default units depend on the global measure system.
    MarbleLocale *locale = MarbleGlobal::getInstance()->locale();
    if ( !settings.contains( "temperatureUnit" ) ) {
        int temperatureUnit;
        if ( locale->measurementSystem() == QLocale::MetricSystem ) {
            temperatureUnit = WeatherData::Celsius;
        }
        else {
            temperatureUnit = WeatherData::Fahrenheit;
        }
        settings.insert( "temperatureUnit", temperatureUnit );
    }

    if ( !settings.contains( "windSpeedUnit" ) ) {
        int windSpeedUnit;
        if ( locale->measurementSystem() == QLocale::MetricSystem ) {
            windSpeedUnit = WeatherData::kph;
        }
        else {
            windSpeedUnit = WeatherData::mph;
        }
        settings.insert( "windSpeedUnit", windSpeedUnit );
    }

    if ( !settings.contains( "pressureUnit" ) ) {
        int pressureUnit;
        if ( locale->measurementSystem() == QLocale::MetricSystem ) {
            pressureUnit = WeatherData::HectoPascal;
        }
        else {
            pressureUnit = WeatherData::inchHg;
        }
        settings.insert( "pressureUnit", pressureUnit );
    }

    m_settings = settings;
    readSettings();

    emit settingsChanged( nameId() );
    updateSettings();
}

void WeatherPlugin::readSettings()
{
    if ( !m_configDialog ) {
        return;
    }

    // Information
    if ( m_settings.value( "showCondition" ).toBool() )
        ui_configWidget->m_weatherConditionBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_weatherConditionBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "showTemperature" ).toBool() )
        ui_configWidget->m_temperatureBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_temperatureBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "showWindDirection" ).toBool() )
        ui_configWidget->m_windDirectionBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_windDirectionBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "showWindSpeed" ).toBool() )
        ui_configWidget->m_windSpeedBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_windSpeedBox->setCheckState( Qt::Unchecked );

    if ( m_settings.value( "onlyFavorites" ).toBool() )
        ui_configWidget->m_onlyFavoritesBox->setCheckState( Qt::Checked );
    else
        ui_configWidget->m_onlyFavoritesBox->setCheckState( Qt::Unchecked );

    // Units
    ui_configWidget->m_temperatureComboBox
        ->setCurrentIndex( m_settings.value( "temperatureUnit" ).toInt() );

    ui_configWidget->m_windSpeedComboBox
        ->setCurrentIndex( m_settings.value( "windSpeedUnit" ).toInt() );

    ui_configWidget->m_pressureComboBox
        ->setCurrentIndex( m_settings.value( "pressureUnit" ).toInt() );

    // Misc
    ui_configWidget->m_updateIntervalBox
        ->setValue( m_settings.value( "updateInterval", 3 ).toInt() );
}

void WeatherPlugin::writeSettings()
{
    // Information
    m_settings.insert( "showCondition",
                       ui_configWidget->m_weatherConditionBox->checkState() == Qt::Checked );
    m_settings.insert( "showTemperature",
                       ui_configWidget->m_temperatureBox->checkState() == Qt::Checked );
    m_settings.insert( "showWindDirection",
                       ui_configWidget->m_windDirectionBox->checkState() == Qt::Checked );
    m_settings.insert( "showWindSpeed",
                       ui_configWidget->m_windSpeedBox->checkState() == Qt::Checked );

    // Units
    m_settings.insert( "temperatureUnit", ui_configWidget->m_temperatureComboBox->currentIndex() );
    m_settings.insert( "windSpeedUnit", ui_configWidget->m_windSpeedComboBox->currentIndex() );
    m_settings.insert( "pressureUnit", ui_configWidget->m_pressureComboBox->currentIndex() );

    // Misc
    bool onlyFavorites = ( ui_configWidget->m_onlyFavoritesBox->checkState() == Qt::Checked );
    m_settings.insert( "onlyFavorites", onlyFavorites );

    m_updateInterval = ui_configWidget->m_updateIntervalBox->value();
    m_settings.insert( "updateInterval", m_updateInterval );

    emit settingsChanged( nameId() );
    updateSettings();
}

void WeatherPlugin::updateSettings()
{
    if ( model() ) {
        bool favoritesOnly = m_settings.value( "onlyFavorites", false ).toBool();
        QList<QString> favoriteItems = m_settings.value( "favoriteItems" ).toString()
                .split(",", QString::SkipEmptyParts);

        model()->setFavoriteItems( favoriteItems );
        setNumberOfItems( favoritesOnly ? favoriteItems.size() : numberOfStationsPerFetch );
        model()->setFavoriteItemsOnly( favoritesOnly );
    }
}

void WeatherPlugin::updateItemSettings()
{
    AbstractDataPluginModel *abstractModel = model();
    if( abstractModel != 0 ) {
        abstractModel->setItemSettings( m_settings );
    }
}

void WeatherPlugin::favoriteItemsChanged( const QStringList& favoriteItems )
{
    m_settings["favoriteItems"] = favoriteItems.join( "," );
    emit settingsChanged( nameId() );
    updateSettings();
}

Q_EXPORT_PLUGIN2(WeatherPlugin, Marble::WeatherPlugin)

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


<commit_before>#pragma once

#include <tuple>
#include <limits>
#include <utility>

namespace mtl {

namespace internal {
    static constexpr std::size_t Max = std::numeric_limits<std::size_t>::max();

    template<typename Target, class Tuple> struct index_of_type;
    template<typename Target>
        struct index_of_type<Target, std::tuple<>> {
            static constexpr auto value = Max;
        };
    template<typename Target, typename... Rest>
        struct index_of_type<Target, std::tuple<Target, Rest...>> {
            static constexpr auto value = 0;
        };
    template<typename Target, typename First, typename... Rest>
        struct index_of_type<Target, std::tuple<First, Rest...>> {
            static constexpr auto next = index_of_type<Target, std::tuple<Rest...>>::value;
            static constexpr auto value = next == Max ? Max : next + 1;
        };

    template <typename Target, class Tuple, std::size_t From = 0>
        struct has_type {
            static constexpr auto value = internal::index_of_type<Target, Tuple>::value != internal::Max;
        };

    template<typename Result, typename... Tuples> struct ConcatHelper;
    template<typename... Result, typename... Types>
        struct ConcatHelper<std::tuple<Result...>, std::tuple<Types...>> {
            using type = std::tuple<Result..., Types...>;
        };
    template<typename... Result, typename... Types, typename... Tuples>
        struct ConcatHelper<std::tuple<Result...>, std::tuple<Types...>, Tuples...> {
            using type = typename ConcatHelper<std::tuple<Result..., Types...>, Tuples...>::type;
        };

    template<typename Tuple> struct TailHelper;
    template<typename First, typename... Params>
        struct TailHelper<std::tuple<First, Params...>> {
            using type = std::tuple<Params...>;
        };

    template<typename Tuple, template<typename> class Operation> struct TransformHelper;
    template<template<typename> class Operation, typename... Params>
        struct TransformHelper<std::tuple<Params...>, Operation> {
            using type = std::tuple<typename Operation<Params>::type...>;
        };

    template<template<typename> class Predicate, typename Tuple, typename Result, typename Enable = void> struct FilterHelper;
    template<template<typename> class Predicate, typename... Done>
        struct FilterHelper<Predicate, std::tuple<>, std::tuple<Done...>> {
            using type = std::tuple<Done...>;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterHelper<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<!Predicate<Head>::value>::type> {
            using type = typename FilterHelper<Predicate, std::tuple<Tail...>, std::tuple<Done...>>::type;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterHelper<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<Predicate<Head>::value>::type> {
            using type = typename FilterHelper<Predicate, std::tuple<Tail...>, std::tuple<Done..., Head>>::type;
        };

    template<typename Tuple, typename Result, typename Enabled = void> struct UniqueHelper;
    template<typename... Result>
        struct UniqueHelper<std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueHelper<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueHelper<std::tuple<Rest...>, std::tuple<Result...>>::type;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueHelper<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<!has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueHelper<std::tuple<Rest...>, std::tuple<Result..., Head>>::type;
        };

    template<typename T>
        struct WithoutFilter {
            template<typename G>
                struct Predicate {
                    static constexpr auto value = !std::is_same<T, G>::value;
                };
        };
    template<typename T, typename Tuple> struct WithoutHelper;
    template<typename T, typename... Params>
        struct WithoutHelper<T, std::tuple<Params...>> {
            using type = typename FilterHelper<WithoutFilter<T>::template Predicate, std::tuple<Params...>, std::tuple<>>::type;
        };

    template<typename A, typename B, typename Result> struct InterleaveHelper;
    template<typename... Result>
        struct InterleaveHelper<std::tuple<>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... AParams, typename... Result>
        struct InterleaveHelper<std::tuple<AParams...>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result..., AParams...>;
        };
    template<typename... BParams, typename... Result>
        struct InterleaveHelper<std::tuple<>, std::tuple<BParams...>, std::tuple<Result...>> {
            using type = std::tuple<Result..., BParams...>;
        };
    template<typename AFirst, typename... AParams, typename BFirst, typename... BParams, typename... Result>
        struct InterleaveHelper<std::tuple<AFirst, AParams...>, std::tuple<BFirst, BParams...>, std::tuple<Result...>> {
            using type = typename InterleaveHelper<std::tuple<AParams...>, std::tuple<BParams...>, std::tuple<Result..., AFirst, BFirst>>::type;
        };

} // namespace internal

template <typename Target, class Tuple, std::size_t From = 0> using has_type = typename internal::has_type<Target, Tuple, From>;
template<typename Tuple, std::size_t... Idx> using select = std::tuple<typename std::tuple_element<Idx, Tuple>::type...>;
template<typename Tuple> using head = typename std::tuple_element<0, Tuple>::type;
template<typename Tuple> using tail = typename internal::TailHelper<Tuple>::type;
template<typename... Tuples> using concat = typename internal::ConcatHelper<std::tuple<>, Tuples...>::type;
template<typename Tuple, template<typename> class Operation> using transform = typename internal::TransformHelper<Tuple, Operation>::type;
template<template<typename> class Predicate, typename Tuple> using filter = typename internal::FilterHelper<Predicate, Tuple, std::tuple<>>::type;
template<typename Tuple> using unique = typename internal::UniqueHelper<Tuple, std::tuple<>>::type;
template<typename T, typename Tuple> using without = typename internal::WithoutHelper<T, Tuple>::type;
template<typename A, typename B> using interleave = typename internal::InterleaveHelper<A, B, std::tuple<>>::type;

} // namespace mtl
<commit_msg>Helper -> Impl<commit_after>#pragma once

#include <tuple>
#include <limits>
#include <utility>

namespace mtl {

namespace internal {
    static constexpr std::size_t Max = std::numeric_limits<std::size_t>::max();

    template<typename Target, class Tuple> struct index_of_type;
    template<typename Target>
        struct index_of_type<Target, std::tuple<>> {
            static constexpr auto value = Max;
        };
    template<typename Target, typename... Rest>
        struct index_of_type<Target, std::tuple<Target, Rest...>> {
            static constexpr auto value = 0;
        };
    template<typename Target, typename First, typename... Rest>
        struct index_of_type<Target, std::tuple<First, Rest...>> {
            static constexpr auto next = index_of_type<Target, std::tuple<Rest...>>::value;
            static constexpr auto value = next == Max ? Max : next + 1;
        };

    template <typename Target, class Tuple, std::size_t From = 0>
        struct has_type {
            static constexpr auto value = internal::index_of_type<Target, Tuple>::value != internal::Max;
        };

    template<typename Result, typename... Tuples> struct ConcatImpl;
    template<typename... Result, typename... Types>
        struct ConcatImpl<std::tuple<Result...>, std::tuple<Types...>> {
            using type = std::tuple<Result..., Types...>;
        };
    template<typename... Result, typename... Types, typename... Tuples>
        struct ConcatImpl<std::tuple<Result...>, std::tuple<Types...>, Tuples...> {
            using type = typename ConcatImpl<std::tuple<Result..., Types...>, Tuples...>::type;
        };

    template<typename Tuple> struct TailImpl;
    template<typename First, typename... Params>
        struct TailImpl<std::tuple<First, Params...>> {
            using type = std::tuple<Params...>;
        };

    template<typename Tuple, template<typename> class Operation> struct TransformImpl;
    template<template<typename> class Operation, typename... Params>
        struct TransformImpl<std::tuple<Params...>, Operation> {
            using type = std::tuple<typename Operation<Params>::type...>;
        };

    template<template<typename> class Predicate, typename Tuple, typename Result, typename Enable = void> struct FilterImpl;
    template<template<typename> class Predicate, typename... Done>
        struct FilterImpl<Predicate, std::tuple<>, std::tuple<Done...>> {
            using type = std::tuple<Done...>;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterImpl<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<!Predicate<Head>::value>::type> {
            using type = typename FilterImpl<Predicate, std::tuple<Tail...>, std::tuple<Done...>>::type;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterImpl<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<Predicate<Head>::value>::type> {
            using type = typename FilterImpl<Predicate, std::tuple<Tail...>, std::tuple<Done..., Head>>::type;
        };

    template<typename Tuple, typename Result, typename Enabled = void> struct UniqueImpl;
    template<typename... Result>
        struct UniqueImpl<std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueImpl<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueImpl<std::tuple<Rest...>, std::tuple<Result...>>::type;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueImpl<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<!has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueImpl<std::tuple<Rest...>, std::tuple<Result..., Head>>::type;
        };

    template<typename T>
        struct WithoutFilter {
            template<typename G>
                struct Predicate {
                    static constexpr auto value = !std::is_same<T, G>::value;
                };
        };
    template<typename T, typename Tuple> struct WithoutImpl;
    template<typename T, typename... Params>
        struct WithoutImpl<T, std::tuple<Params...>> {
            using type = typename FilterImpl<WithoutFilter<T>::template Predicate, std::tuple<Params...>, std::tuple<>>::type;
        };

    template<typename A, typename B, typename Result> struct InterleaveImpl;
    template<typename... Result>
        struct InterleaveImpl<std::tuple<>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... AParams, typename... Result>
        struct InterleaveImpl<std::tuple<AParams...>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result..., AParams...>;
        };
    template<typename... BParams, typename... Result>
        struct InterleaveImpl<std::tuple<>, std::tuple<BParams...>, std::tuple<Result...>> {
            using type = std::tuple<Result..., BParams...>;
        };
    template<typename AFirst, typename... AParams, typename BFirst, typename... BParams, typename... Result>
        struct InterleaveImpl<std::tuple<AFirst, AParams...>, std::tuple<BFirst, BParams...>, std::tuple<Result...>> {
            using type = typename InterleaveImpl<std::tuple<AParams...>, std::tuple<BParams...>, std::tuple<Result..., AFirst, BFirst>>::type;
        };

} // namespace internal

template<typename Target, class Tuple, std::size_t From = 0> using has_type = typename internal::has_type<Target, Tuple, From>;
template<typename Tuple, std::size_t... Idx> using select = std::tuple<typename std::tuple_element<Idx, Tuple>::type...>;
template<typename Tuple> using head = typename std::tuple_element<0, Tuple>::type;
template<typename Tuple> using tail = typename internal::TailImpl<Tuple>::type;
template<typename... Tuples> using concat = typename internal::ConcatImpl<std::tuple<>, Tuples...>::type;
template<typename Tuple, template<typename> class Operation> using transform = typename internal::TransformImpl<Tuple, Operation>::type;
template<template<typename> class Predicate, typename Tuple> using filter = typename internal::FilterImpl<Predicate, Tuple, std::tuple<>>::type;
template<typename Tuple> using unique = typename internal::UniqueImpl<Tuple, std::tuple<>>::type;
template<typename T, typename Tuple> using without = typename internal::WithoutImpl<T, Tuple>::type;
template<typename A, typename B> using interleave = typename internal::InterleaveImpl<A, B, std::tuple<>>::type;

} // namespace mtl
<|endoftext|>


<commit_before>/* libs/graphics/ports/SkFontHost_fontconfig_direct.cpp
**
** Copyright 2009, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include "SkFontHost_fontconfig_direct.h"

#include <unistd.h>
#include <fcntl.h>

#include <fontconfig/fontconfig.h>

FontConfigDirect::FontConfigDirect()
    : next_file_id_(0) {
  FcInit();
}

// -----------------------------------------------------------------------------
// Normally we only return exactly the font asked for. In last-resort cases,
// the request is for one of the basic font names "Sans", "Serif" or
// "Monospace". This function tells you whether a given request is for such a
// fallback.
// -----------------------------------------------------------------------------
static bool IsFallbackFontAllowed(const std::string& family)
{
    const char* family_cstr = family.c_str();
    return strcasecmp(family_cstr, "sans") == 0 ||
           strcasecmp(family_cstr, "serif") == 0 ||
           strcasecmp(family_cstr, "monospace") == 0;
}

bool FontConfigDirect::Match(std::string* result_family,
                             unsigned* result_fileid,
                             bool fileid_valid, unsigned fileid,
                             const std::string& family, bool* is_bold,
                             bool* is_italic) {
    SkAutoMutexAcquire ac(mutex_);
    FcPattern* pattern = FcPatternCreate();

    FcValue fcvalue;
    if (fileid_valid) {
        const std::map<unsigned, std::string>::const_iterator
            i = fileid_to_filename_.find(fileid);
        if (i == fileid_to_filename_.end()) {
            FcPatternDestroy(pattern);
            return false;
        }

        fcvalue.type = FcTypeString;
        fcvalue.u.s = (FcChar8*) i->second.c_str();
        FcPatternAdd(pattern, FC_FILE, fcvalue, 0);
    }
    if (!family.empty()) {
        fcvalue.type = FcTypeString;
        fcvalue.u.s = (FcChar8*) family.c_str();
        FcPatternAdd(pattern, FC_FAMILY, fcvalue, 0);
    }

    fcvalue.type = FcTypeInteger;
    fcvalue.u.i = is_bold && *is_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
    FcPatternAdd(pattern, FC_WEIGHT, fcvalue, 0);

    fcvalue.type = FcTypeInteger;
    fcvalue.u.i = is_italic && *is_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
    FcPatternAdd(pattern, FC_SLANT, fcvalue, 0);

    fcvalue.type = FcTypeBool;
    fcvalue.u.b = FcTrue;
    FcPatternAdd(pattern, FC_SCALABLE, fcvalue, 0);

    FcConfigSubstitute(0, pattern, FcMatchPattern);
    FcDefaultSubstitute(pattern);

    // Font matching:
    // CSS often specifies a fallback list of families:
    //    font-family: a, b, c, serif;
    // However, fontconfig will always do its best to find *a* font when asked
    // for something so we need a way to tell if the match which it has found is
    // "good enough" for us. Otherwise, we can return NULL which gets piped up
    // and lets WebKit know to try the next CSS family name. However, fontconfig
    // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
    // wish to support that.
    //
    // Thus, if a specific family is requested we set @family_requested. Then we
    // record two strings: the family name after config processing and the
    // family name after resolving. If the two are equal, it's a good match.
    //
    // So consider the case where a user has mapped Arial to Helvetica in their
    // config.
    //    requested family: "Arial"
    //    post_config_family: "Helvetica"
    //    post_match_family: "Helvetica"
    //      -> good match
    //
    // and for a missing font:
    //    requested family: "Monaco"
    //    post_config_family: "Monaco"
    //    post_match_family: "Times New Roman"
    //      -> BAD match
    //
    // However, we special-case fallback fonts; see IsFallbackFontAllowed().
    FcChar8* post_config_family;
    FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family);

    FcResult result;
    FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
    if (!font_set) {
        FcPatternDestroy(pattern);
        return false;
    }

    // Older versions of fontconfig have a bug where they cannot select
    // only scalable fonts so we have to manually filter the results.
    FcPattern* match = NULL;
    for (int i = 0; i < font_set->nfont; ++i) {
      FcPattern* current = font_set->fonts[i];
      FcBool is_scalable;

      if (FcPatternGetBool(current, FC_SCALABLE, 0,
                           &is_scalable) != FcResultMatch ||
          !is_scalable) {
        continue;
      }

      // fontconfig can also return fonts which are unreadable
      FcChar8* c_filename;
      if (FcPatternGetString(current, FC_FILE, 0, &c_filename) != FcResultMatch)
        continue;

      if (access(reinterpret_cast<char*>(c_filename), R_OK) != 0)
        continue;

      match = current;
      break;
    }

    if (!match) {
      FcPatternDestroy(pattern);
      FcFontSetDestroy(font_set);
      return false;
    }

    FcChar8* post_match_family;
    FcPatternGetString(match, FC_FAMILY, 0, &post_match_family);
    const bool family_names_match =
        family.empty() ?
        true :
        strcasecmp((char *)post_config_family, (char *)post_match_family) == 0;

    FcPatternDestroy(pattern);

    if (!family_names_match && !IsFallbackFontAllowed(family)) {
        FcFontSetDestroy(font_set);
        return false;
    }

    FcChar8* c_filename;
    if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) {
        FcFontSetDestroy(font_set);
        return false;
    }
    const std::string filename((char *) c_filename);

    unsigned out_fileid;
    if (fileid_valid) {
        out_fileid = fileid;
    } else {
        const std::map<std::string, unsigned>::const_iterator
            i = filename_to_fileid_.find(filename);
        if (i == filename_to_fileid_.end()) {
            out_fileid = next_file_id_++;
            filename_to_fileid_[filename] = out_fileid;
            fileid_to_filename_[out_fileid] = filename;
        } else {
            out_fileid = i->second;
        }
    }

    if (result_fileid)
        *result_fileid = out_fileid;

    FcChar8* c_family;
    if (FcPatternGetString(match, FC_FAMILY, 0, &c_family)) {
        FcFontSetDestroy(font_set);
        return false;
    }

    int resulting_bold;
    if (FcPatternGetInteger(match, FC_WEIGHT, 0, &resulting_bold))
      resulting_bold = FC_WEIGHT_NORMAL;

    int resulting_italic;
    if (FcPatternGetInteger(match, FC_SLANT, 0, &resulting_italic))
      resulting_italic = FC_SLANT_ROMAN;

    // If we ask for an italic font, fontconfig might take a roman font and set
    // the undocumented property FC_MATRIX to a skew matrix. It'll then say
    // that the font is italic or oblique. So, if we see a matrix, we don't
    // believe that it's italic.
    FcValue matrix;
    const bool have_matrix = FcPatternGet(match, FC_MATRIX, 0, &matrix) == 0;

    // If we ask for an italic font, fontconfig might take a roman font and set
    // FC_EMBOLDEN.
    FcValue embolden;
    const bool have_embolden =
        FcPatternGet(match, FC_EMBOLDEN, 0, &embolden) == 0;

    if (is_bold)
      *is_bold = resulting_bold >= FC_WEIGHT_BOLD && !have_embolden;
    if (is_italic)
      *is_italic = resulting_italic > FC_SLANT_ROMAN && !have_matrix;

    if (result_family)
        *result_family = (char *) c_family;

    FcFontSetDestroy(font_set);

    return true;
}

int FontConfigDirect::Open(unsigned fileid) {
    SkAutoMutexAcquire ac(mutex_);
    const std::map<unsigned, std::string>::const_iterator
        i = fileid_to_filename_.find(fileid);
    if (i == fileid_to_filename_.end())
        return -1;

    return open(i->second.c_str(), O_RDONLY);
}
<commit_msg>Tries to retrieve all post_match_families in the font file to support non-ascii fonts. This patch should fix CHECK failures like this:<commit_after>/* libs/graphics/ports/SkFontHost_fontconfig_direct.cpp
**
** Copyright 2009, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include "SkFontHost_fontconfig_direct.h"

#include <unistd.h>
#include <fcntl.h>

#include <fontconfig/fontconfig.h>

FontConfigDirect::FontConfigDirect()
    : next_file_id_(0) {
  FcInit();
}

// -----------------------------------------------------------------------------
// Normally we only return exactly the font asked for. In last-resort cases,
// the request is for one of the basic font names "Sans", "Serif" or
// "Monospace". This function tells you whether a given request is for such a
// fallback.
// -----------------------------------------------------------------------------
static bool IsFallbackFontAllowed(const std::string& family)
{
    const char* family_cstr = family.c_str();
    return strcasecmp(family_cstr, "sans") == 0 ||
           strcasecmp(family_cstr, "serif") == 0 ||
           strcasecmp(family_cstr, "monospace") == 0;
}

bool FontConfigDirect::Match(std::string* result_family,
                             unsigned* result_fileid,
                             bool fileid_valid, unsigned fileid,
                             const std::string& family, bool* is_bold,
                             bool* is_italic) {
    SkAutoMutexAcquire ac(mutex_);
    FcPattern* pattern = FcPatternCreate();

    FcValue fcvalue;
    if (fileid_valid) {
        const std::map<unsigned, std::string>::const_iterator
            i = fileid_to_filename_.find(fileid);
        if (i == fileid_to_filename_.end()) {
            FcPatternDestroy(pattern);
            return false;
        }

        fcvalue.type = FcTypeString;
        fcvalue.u.s = (FcChar8*) i->second.c_str();
        FcPatternAdd(pattern, FC_FILE, fcvalue, 0);
    }
    if (!family.empty()) {
        fcvalue.type = FcTypeString;
        fcvalue.u.s = (FcChar8*) family.c_str();
        FcPatternAdd(pattern, FC_FAMILY, fcvalue, 0);
    }

    fcvalue.type = FcTypeInteger;
    fcvalue.u.i = is_bold && *is_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
    FcPatternAdd(pattern, FC_WEIGHT, fcvalue, 0);

    fcvalue.type = FcTypeInteger;
    fcvalue.u.i = is_italic && *is_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
    FcPatternAdd(pattern, FC_SLANT, fcvalue, 0);

    fcvalue.type = FcTypeBool;
    fcvalue.u.b = FcTrue;
    FcPatternAdd(pattern, FC_SCALABLE, fcvalue, 0);

    FcConfigSubstitute(0, pattern, FcMatchPattern);
    FcDefaultSubstitute(pattern);

    // Font matching:
    // CSS often specifies a fallback list of families:
    //    font-family: a, b, c, serif;
    // However, fontconfig will always do its best to find *a* font when asked
    // for something so we need a way to tell if the match which it has found is
    // "good enough" for us. Otherwise, we can return NULL which gets piped up
    // and lets WebKit know to try the next CSS family name. However, fontconfig
    // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
    // wish to support that.
    //
    // Thus, if a specific family is requested we set @family_requested. Then we
    // record two strings: the family name after config processing and the
    // family name after resolving. If the two are equal, it's a good match.
    //
    // So consider the case where a user has mapped Arial to Helvetica in their
    // config.
    //    requested family: "Arial"
    //    post_config_family: "Helvetica"
    //    post_match_family: "Helvetica"
    //      -> good match
    //
    // and for a missing font:
    //    requested family: "Monaco"
    //    post_config_family: "Monaco"
    //    post_match_family: "Times New Roman"
    //      -> BAD match
    //
    // However, we special-case fallback fonts; see IsFallbackFontAllowed().
    FcChar8* post_config_family;
    FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family);

    FcResult result;
    FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
    if (!font_set) {
        FcPatternDestroy(pattern);
        return false;
    }

    // Older versions of fontconfig have a bug where they cannot select
    // only scalable fonts so we have to manually filter the results.
    FcPattern* match = NULL;
    for (int i = 0; i < font_set->nfont; ++i) {
      FcPattern* current = font_set->fonts[i];
      FcBool is_scalable;

      if (FcPatternGetBool(current, FC_SCALABLE, 0,
                           &is_scalable) != FcResultMatch ||
          !is_scalable) {
        continue;
      }

      // fontconfig can also return fonts which are unreadable
      FcChar8* c_filename;
      if (FcPatternGetString(current, FC_FILE, 0, &c_filename) != FcResultMatch)
        continue;

      if (access(reinterpret_cast<char*>(c_filename), R_OK) != 0)
        continue;

      match = current;
      break;
    }

    if (!match) {
      FcPatternDestroy(pattern);
      FcFontSetDestroy(font_set);
      return false;
    }

    if (!IsFallbackFontAllowed(family)) {
      bool family_names_match = false;
      for (int id = 0; id < 255; ++id) {
        FcChar8* post_match_family;
        if (FcPatternGetString(match, FC_FAMILY, id, &post_match_family) !=
            FcResultMatch)
          break;
        family_names_match =
          family.empty() ?
          true :
          strcasecmp((char *)post_config_family,
                     (char *)post_match_family) == 0;
        if (family_names_match)
          break;
      }
      if (!family.empty() && !family_names_match) {
        FcPatternDestroy(pattern);
        FcFontSetDestroy(font_set);
        return false;
      }
    }

    FcPatternDestroy(pattern);

    FcChar8* c_filename;
    if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) {
        FcFontSetDestroy(font_set);
        return false;
    }
    const std::string filename((char *) c_filename);

    unsigned out_fileid;
    if (fileid_valid) {
        out_fileid = fileid;
    } else {
        const std::map<std::string, unsigned>::const_iterator
            i = filename_to_fileid_.find(filename);
        if (i == filename_to_fileid_.end()) {
            out_fileid = next_file_id_++;
            filename_to_fileid_[filename] = out_fileid;
            fileid_to_filename_[out_fileid] = filename;
        } else {
            out_fileid = i->second;
        }
    }

    if (result_fileid)
        *result_fileid = out_fileid;

    FcChar8* c_family;
    if (FcPatternGetString(match, FC_FAMILY, 0, &c_family)) {
        FcFontSetDestroy(font_set);
        return false;
    }

    int resulting_bold;
    if (FcPatternGetInteger(match, FC_WEIGHT, 0, &resulting_bold))
      resulting_bold = FC_WEIGHT_NORMAL;

    int resulting_italic;
    if (FcPatternGetInteger(match, FC_SLANT, 0, &resulting_italic))
      resulting_italic = FC_SLANT_ROMAN;

    // If we ask for an italic font, fontconfig might take a roman font and set
    // the undocumented property FC_MATRIX to a skew matrix. It'll then say
    // that the font is italic or oblique. So, if we see a matrix, we don't
    // believe that it's italic.
    FcValue matrix;
    const bool have_matrix = FcPatternGet(match, FC_MATRIX, 0, &matrix) == 0;

    // If we ask for an italic font, fontconfig might take a roman font and set
    // FC_EMBOLDEN.
    FcValue embolden;
    const bool have_embolden =
        FcPatternGet(match, FC_EMBOLDEN, 0, &embolden) == 0;

    if (is_bold)
      *is_bold = resulting_bold >= FC_WEIGHT_BOLD && !have_embolden;
    if (is_italic)
      *is_italic = resulting_italic > FC_SLANT_ROMAN && !have_matrix;

    if (result_family)
        *result_family = (char *) c_family;

    FcFontSetDestroy(font_set);

    return true;
}

int FontConfigDirect::Open(unsigned fileid) {
    SkAutoMutexAcquire ac(mutex_);
    const std::map<unsigned, std::string>::const_iterator
        i = fileid_to_filename_.find(fileid);
    if (i == fileid_to_filename_.end())
        return -1;

    return open(i->second.c_str(), O_RDONLY);
}
<|endoftext|>