<commit_before>/*
  This file is part of KOrganizer.

  Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
  Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventviewer.h"
#include "urihandler.h"
#include "korganizerinterface.h"
#include "koglobals.h"

#include <libkdepim/kdepimprotocols.h>

#include <kcal/incidence.h>
#include <kcal/incidenceformatter.h>

#include <kapplication.h>
#include <kdebug.h>
#include <ktoolinvocation.h>
#include <kconfiggroup.h>

#include <QRegExp>

KOEventViewer::KOEventViewer( QWidget *parent )
  : KTextBrowser( parent ), mDefaultText( "" )
{
  mIncidence = 0;
  setNotifyClick( true );
}

KOEventViewer::~KOEventViewer()
{
}

void KOEventViewer::readSettings( KConfig *config )
{
  if ( config ) {
// With each restart of KOrganizer the font site gets halfed. What should this
// be good for?
#if 0
    config->setGroup( QString( "EventViewer-%1" ).arg( name() ) );
    int zoomFactor = config->readEntry( "ZoomFactor", fontPointSize() );
    zoomTo( zoomFactor / 2 );
    kDebug(5850) << " KOEventViewer: restoring the fontPointSize:" << fontPointSize()
                 << ", zoomFactor: " << zoomFactor;
#endif
  }
}

void KOEventViewer::writeSettings( KConfig *config )
{
  if ( config ) {
    kDebug(5850) << " KOEventViewer: saving the zoomFactor:" << fontPointSize();
    KConfigGroup configGroup( config, QString( "EventViewer-%1" ).arg( objectName() ) );
    configGroup.writeEntry( "ZoomFactor", fontPointSize() );
  }
}

void KOEventViewer::setSource( const QUrl &name )
{
  QString uri = name.toString();
  // QTextBrowser for some reason insists on putting // in links,
  // this is a crude workaround
  if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ||
       uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ||
       uri.startsWith( QString( KDEPIMPROTOCOL_INCIDENCE ).section( ':', 0, 0 ) ) ||
       uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
    uri.replace( QRegExp( "^([^:]*:)//" ), "\\1" );
  }

  UriHandler::process( uri );
}

bool KOEventViewer::appendIncidence( Incidence *incidence )
{
  QString codeForIncidence = IncidenceFormatter::extensiveDisplayString( incidence );
  addText( codeForIncidence );
  return true;
}

void KOEventViewer::setIncidence( Incidence *incidence )
{
  clearEvents();
  if( incidence ) {
    appendIncidence( incidence );
    mIncidence = incidence;
  } else {
    clearEvents( true );
    mIncidence = 0;
  }
}

void KOEventViewer::clearEvents( bool now )
{
  mText = "";
  if ( now ) {
    setText( mDefaultText );
  }
}

void KOEventViewer::addText( const QString &text )
{
  mText.append( text );
  setText( mText );
}

void KOEventViewer::setDefaultText( const QString &text )
{
  mDefaultText = text;
}

void KOEventViewer::changeIncidenceDisplay( Incidence *incidence, int action )
{
  if ( mIncidence && ( incidence->uid() == mIncidence->uid() ) ) {
    switch ( action ) {
    case KOGlobals::INCIDENCEEDITED:
    {
      setIncidence( incidence );
      break;
    }
    case KOGlobals::INCIDENCEDELETED:
    {
      setIncidence( 0 );
      break;
    }
    }
  }
}

void KOEventViewer::editIncidence()
{
  if ( mIncidence ) {
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath( "korganizer" );

    OrgKdeKorganizerKorganizerInterface korganizerIface(
      "org.kde.korganizer.Korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.editIncidence( mIncidence->uid() );
  }
}

void KOEventViewer::showIncidenceContext()
{
  if ( mIncidence ) {
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath( "korganizer" );

    OrgKdeKorganizerKorganizerInterface korganizerIface(
      "org.kde.korganizer.Korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.showIncidenceContext( mIncidence->uid() );
  }
}

#include "koeventviewer.moc"
<commit_msg>Fix D-Bus calls for editing and showing incidences. Thanks to Kevin.<commit_after>/*
  This file is part of KOrganizer.

  Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
  Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventviewer.h"
#include "urihandler.h"
#include "korganizerinterface.h"
#include "koglobals.h"

#include <libkdepim/kdepimprotocols.h>

#include <kcal/incidence.h>
#include <kcal/incidenceformatter.h>

#include <kapplication.h>
#include <kdebug.h>
#include <ktoolinvocation.h>
#include <kconfiggroup.h>

#include <QRegExp>

KOEventViewer::KOEventViewer( QWidget *parent )
  : KTextBrowser( parent ), mDefaultText( "" )
{
  mIncidence = 0;
  setNotifyClick( true );
}

KOEventViewer::~KOEventViewer()
{
}

void KOEventViewer::readSettings( KConfig *config )
{
  if ( config ) {
// With each restart of KOrganizer the font site gets halfed. What should this
// be good for?
#if 0
    config->setGroup( QString( "EventViewer-%1" ).arg( name() ) );
    int zoomFactor = config->readEntry( "ZoomFactor", fontPointSize() );
    zoomTo( zoomFactor / 2 );
    kDebug(5850) << " KOEventViewer: restoring the fontPointSize:" << fontPointSize()
                 << ", zoomFactor: " << zoomFactor;
#endif
  }
}

void KOEventViewer::writeSettings( KConfig *config )
{
  if ( config ) {
    kDebug(5850) << " KOEventViewer: saving the zoomFactor:" << fontPointSize();
    KConfigGroup configGroup( config, QString( "EventViewer-%1" ).arg( objectName() ) );
    configGroup.writeEntry( "ZoomFactor", fontPointSize() );
  }
}

void KOEventViewer::setSource( const QUrl &name )
{
  QString uri = name.toString();
  // QTextBrowser for some reason insists on putting // in links,
  // this is a crude workaround
  if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ||
       uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ||
       uri.startsWith( QString( KDEPIMPROTOCOL_INCIDENCE ).section( ':', 0, 0 ) ) ||
       uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
    uri.replace( QRegExp( "^([^:]*:)//" ), "\\1" );
  }

  UriHandler::process( uri );
}

bool KOEventViewer::appendIncidence( Incidence *incidence )
{
  QString codeForIncidence = IncidenceFormatter::extensiveDisplayString( incidence );
  addText( codeForIncidence );
  return true;
}

void KOEventViewer::setIncidence( Incidence *incidence )
{
  clearEvents();
  if( incidence ) {
    appendIncidence( incidence );
    mIncidence = incidence;
  } else {
    clearEvents( true );
    mIncidence = 0;
  }
}

void KOEventViewer::clearEvents( bool now )
{
  mText = "";
  if ( now ) {
    setText( mDefaultText );
  }
}

void KOEventViewer::addText( const QString &text )
{
  mText.append( text );
  setText( mText );
}

void KOEventViewer::setDefaultText( const QString &text )
{
  mDefaultText = text;
}

void KOEventViewer::changeIncidenceDisplay( Incidence *incidence, int action )
{
  if ( mIncidence && ( incidence->uid() == mIncidence->uid() ) ) {
    switch ( action ) {
    case KOGlobals::INCIDENCEEDITED:
    {
      setIncidence( incidence );
      break;
    }
    case KOGlobals::INCIDENCEDELETED:
    {
      setIncidence( 0 );
      break;
    }
    }
  }
}

void KOEventViewer::editIncidence()
{
  if ( mIncidence ) {
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath( "korganizer" );

    OrgKdeKorganizerKorganizerInterface korganizerIface(
      "org.kde.korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.editIncidence( mIncidence->uid() );
  }
}

void KOEventViewer::showIncidenceContext()
{
  if ( mIncidence ) {
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath( "korganizer" );

    OrgKdeKorganizerKorganizerInterface korganizerIface(
      "org.kde.korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.showIncidenceContext( mIncidence->uid() );
  }
}

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


<commit_before>#include <DuiLocale>
#include <DuiTheme>

#include <QDBusConnection>
#include <QDebug>

#include "sysuid.h"
#include "systemuigconf.h"
#include "pincodequerybusinesslogic.h"
#include "batterybusinesslogic.h"
#include "batterybusinesslogicadaptor.h"
#include "lockscreenbusinesslogic.h"
#include "lockscreenbusinesslogicadaptor.h"
#include "notifier.h"
#include "notificationtype.h"
#include "shutdownbusinesslogic.h"
#include "cellularui.h"

namespace
{
const QString themeDir = "/usr/share/sysuid/themes/";
const QString styleDir = themeDir + "style/";
const QString svgDir = themeDir + "svg/";
}

Sysuid* Sysuid::_sysuid = NULL;

Sysuid::Sysuid() :
        QObject(),
        notifier(NULL)
{
    qDebug() << "starting sysuidaemon";

    _sysuid = this;

    /* themes */
    DuiTheme::addPixmapDirectory(svgDir); // or ..(themeDir, true); ?
    DuiTheme::loadCSS(styleDir + "sysuid.css");
    DuiTheme::loadCSS(styleDir + "unlocksliderstyle.css");

    /* Notifier */
    notifier = new Notifier(this);

    /* GConf interface */
    systemUIGConf = new SystemUIGConf(this);

    /* Pincode query variables */
    pinCodeQueryLogic = new PinCodeQueryBusinessLogic(this);
    connect(notifier->responseObject(), SIGNAL(pinQueryCanceled()), pinCodeQueryLogic, SLOT(cancelQuery()));
    connect(notifier->responseObject(), SIGNAL(doSimLockRetry()), pinCodeQueryLogic, SLOT(resendSimLockCode()));
    connect(pinCodeQueryLogic, SIGNAL(showNotification(QString, NotificationType::Type)), notifier, SLOT(showNotification(QString, NotificationType::Type)));
    connect(pinCodeQueryLogic, SIGNAL(showConfirmation(QString, QString)), notifier, SLOT(showConfirmation(QString, QString)));

    /* Shutdown */
    shutdownLogic = new ShutdownBusinessLogic(this);
    connect(shutdownLogic, SIGNAL(showNotification(QString, NotificationType::Type)),
            notifier, SLOT(showNotification(QString, NotificationType::Type)));

    /* Lockscreen */
    lockScreenLogic = new LockScreenBusinessLogic(this);

    /* Battery */
    batteryLogic = new BatteryBusinessLogic(systemUIGConf, this);
    connect(batteryLogic, SIGNAL(showNotification(QString)), notifier, SLOT(showNotification(QString)));

    /* Cellular UI */
    cellUI = new CellularUI(this);
    connect(cellUI, SIGNAL(showNotification(QString, NotificationType::Type)),
            notifier, SLOT(showNotification(QString, NotificationType::Type)));
    connect(cellUI, SIGNAL(showConfirmation(QString, QString)),
            notifier, SLOT(showConfirmation(QString, QString)));

    // D-Bus registration and stuff.
    new BatteryBusinessLogicAdaptor(this, batteryLogic);
    new LockScreenBusinessLogicAdaptor(this, lockScreenLogic);

    QDBusConnection bus = QDBusConnection::sessionBus();
    if (!bus.registerService(dbusService())) {
        qDebug() << "failed to register dbus service";
        abort();
    }
    if (!bus.registerObject(dbusPath(), sysuid())) {
        qDebug() << "failed to register dbus objects";
        abort();
    }
}

Sysuid::~Sysuid()
{
    _sysuid = NULL;
}

Sysuid* Sysuid::sysuid()
{
    return _sysuid;
}

QString Sysuid::dbusService()
{
    return QString("com.nokia.systemui");
}

QString Sysuid::dbusPath()
{
    return QString("/");
}

<commit_msg>Removed some test code<commit_after>#include <DuiLocale>
#include <DuiTheme>

#include <QDBusConnection>
#include <QDebug>

#include "sysuid.h"
#include "systemuigconf.h"
#include "pincodequerybusinesslogic.h"
#include "batterybusinesslogic.h"
#include "batterybusinesslogicadaptor.h"
#include "lockscreenbusinesslogic.h"
#include "lockscreenbusinesslogicadaptor.h"
#include "notifier.h"
#include "notificationtype.h"
#include "shutdownbusinesslogic.h"
#include "cellularui.h"

namespace
{
const QString themeDir = "/usr/share/sysuid/themes/";
const QString styleDir = themeDir + "style/";
const QString svgDir = themeDir + "svg/";
}

Sysuid* Sysuid::_sysuid = NULL;

Sysuid::Sysuid() :
        QObject(),
        notifier(NULL)
{
    qDebug() << "starting sysuidaemon";

    _sysuid = this;

    /* themes */
    DuiTheme::addPixmapDirectory(svgDir); // or ..(themeDir, true); ?
    DuiTheme::loadCSS(styleDir + "sysuid.css");
    DuiTheme::loadCSS(styleDir + "unlocksliderstyle.css");

    /* Notifier */
    notifier = new Notifier(this);

    /* GConf interface */
    systemUIGConf = new SystemUIGConf(this);

    /* Pincode query variables */
    pinCodeQueryLogic = new PinCodeQueryBusinessLogic(this);
    connect(notifier->responseObject(), SIGNAL(pinQueryCanceled()), pinCodeQueryLogic, SLOT(cancelQuery()));
    connect(notifier->responseObject(), SIGNAL(doSimLockRetry()), pinCodeQueryLogic, SLOT(resendSimLockCode()));
    connect(pinCodeQueryLogic, SIGNAL(showNotification(QString, NotificationType::Type)), notifier, SLOT(showNotification(QString, NotificationType::Type)));
    connect(pinCodeQueryLogic, SIGNAL(showConfirmation(QString, QString)), notifier, SLOT(showConfirmation(QString, QString)));

    /* Shutdown */
    shutdownLogic = new ShutdownBusinessLogic(this);
    connect(shutdownLogic, SIGNAL(showNotification(QString, NotificationType::Type)),
            notifier, SLOT(showNotification(QString, NotificationType::Type)));

    /* Lockscreen */
    lockScreenLogic = new LockScreenBusinessLogic(this);

    /* Battery */
    batteryLogic = new BatteryBusinessLogic(systemUIGConf, this);
    connect(batteryLogic, SIGNAL(showNotification(QString)), notifier, SLOT(showNotification(QString)));

    /* Cellular UI */
    cellUI = new CellularUI(this);
    connect(cellUI, SIGNAL(showNotification(QString, NotificationType::Type)),
            notifier, SLOT(showNotification(QString, NotificationType::Type)));

    // D-Bus registration and stuff.
    new BatteryBusinessLogicAdaptor(this, batteryLogic);
    new LockScreenBusinessLogicAdaptor(this, lockScreenLogic);

    QDBusConnection bus = QDBusConnection::sessionBus();
    if (!bus.registerService(dbusService())) {
        qDebug() << "failed to register dbus service";
        abort();
    }
    if (!bus.registerObject(dbusPath(), sysuid())) {
        qDebug() << "failed to register dbus objects";
        abort();
    }
}

Sysuid::~Sysuid()
{
    _sysuid = NULL;
}

Sysuid* Sysuid::sysuid()
{
    return _sysuid;
}

QString Sysuid::dbusService()
{
    return QString("com.nokia.systemui");
}

QString Sysuid::dbusPath()
{
    return QString("/");
}

<|endoftext|>


<commit_before>#include <sdk.h>
#include <configurationpanel.h>
#include <logmanager.h>
#include <git2.h>
#include "plugin.h"
#include "gui/gitimportdialog.h"
#include "gui/gitcommitdialog.h"

namespace {
    PluginRegistrant<GitPlugin> reg(_T("Codeblocks_Git_Plugin"));
}

// IDs
int idGitImportEntry = wxNewId();
int idGitCommitEntry = wxNewId();

// Event table
BEGIN_EVENT_TABLE(GitPlugin, cbPlugin)
    EVT_MENU(idGitImportEntry, GitPlugin::OnMenuImport)
    EVT_MENU(idGitCommitEntry, GitPlugin::OnMenuCommit)
END_EVENT_TABLE()

// Constructor, load resources
GitPlugin::GitPlugin() {
    if(!Manager::LoadResource(_T("Codeblocks_Git_Plugin.zip"))) {
        NotifyMissingFile(_T("Codeblocks_Git_Plugin.zip"));
    }
}

GitPlugin::~GitPlugin() {
}

void GitPlugin::OnAttach() {
    git_threads_init();
}

void GitPlugin::OnRelease(bool appShutDown) {
    git_threads_shutdown();
}

int GitPlugin::Configure() {
    if(!IsAttached()) return -1;

    cbConfigurationDialog dlg(Manager::Get()->GetAppWindow(), wxID_ANY, _("GIT Plugin Configuration"));
    cbConfigurationPanel* panel = GetConfigurationPanel(&dlg);
    if(panel) {
        dlg.AttachConfigurationPanel(panel);
        PlaceWindow(&dlg);
        return dlg.ShowModal() == wxID_OK ? 0 : -1;
    }
    return -1;
}

void GitPlugin::BuildMenu(wxMenuBar* menuBar) {
    if(!IsAttached()) return;

    // Find import menu
    wxMenu* fileMenu = menuBar->GetMenu(0);
    int importMenuPos = fileMenu->FindItem(_("Import project"));
    if(importMenuPos == wxNOT_FOUND) {
        return;
    }
    wxMenu* importMenu = fileMenu->FindItem(importMenuPos, NULL)->GetSubMenu();

    // Add import item for Git
    wxMenuItem* gitItem = new wxMenuItem(importMenu, idGitImportEntry, _("Git Repository ..."));
    wxMenuItem* spacer = new wxMenuItem(importMenu, wxID_SEPARATOR, _(""), _(""), wxITEM_SEPARATOR);
    importMenu->Append(spacer);
    importMenu->Append(gitItem);
}

void GitPlugin::OnMenuImport(wxCommandEvent& event) {
    GitImportDialog dialog(Manager::Get()->GetAppWindow());
    if(dialog.run()) {

    }
}

void GitPlugin::OnMenuCommit(wxCommandEvent& event) {
    GitCommitDialog dialog(Manager::Get()->GetAppWindow());
    if(dialog.ShowModal() == wxID_OK) {

    }
}

void GitPlugin::buildFileMenu(wxMenu* menu) {
    // TODO: File menu
}

void GitPlugin::buildFolderMenu(wxMenu* menu) {
    // TODO: Folder menu
}

void GitPlugin::buildProjectMenu(wxMenu* menu) {
    wxMenu* gitMenu = new wxMenu();
    wxMenuItem* initItem = new wxMenuItem(gitMenu, wxID_ANY, _("Init"));
    wxMenuItem* commitItem = new wxMenuItem(gitMenu, idGitCommitEntry, _("Commit"));
    wxMenuItem* pushItem = new wxMenuItem(gitMenu, wxID_ANY, _("Push"));
    wxMenuItem* pullItem = new wxMenuItem(gitMenu, wxID_ANY, _("Pull"));

    gitMenu->Append(initItem);
    gitMenu->Append(commitItem);
    gitMenu->Append(pushItem);
    gitMenu->Append(pullItem);

    menu->AppendSubMenu(gitMenu, _("Git"));
}

void GitPlugin::BuildModuleMenu(const ModuleType type, wxMenu* menu, const FileTreeData* data) {
    if(!IsAttached()) return;
    if(type != mtProjectManager) return;

    switch(data->GetKind()) {
        case FileTreeData::ftdkProject: buildProjectMenu(menu); break;
        case FileTreeData::ftdkFile:    buildFileMenu(menu);    break;
        case FileTreeData::ftdkFolder:  buildFolderMenu(menu);  break;
    }
}
<commit_msg>Add some IDs<commit_after>#include <sdk.h>
#include <configurationpanel.h>
#include <logmanager.h>
#include <git2.h>
#include "plugin.h"
#include "gui/gitimportdialog.h"
#include "gui/gitcommitdialog.h"

namespace {
    PluginRegistrant<GitPlugin> reg(_T("Codeblocks_Git_Plugin"));
}

// IDs
int idGitImportEntry = wxNewId();
int idGitCommitEntry = wxNewId();
int idGitPushEntry = wxNewId();
int idGitPullEntry = wxNewId();
int idGitInitEntry = wxNewId();

// Event table
BEGIN_EVENT_TABLE(GitPlugin, cbPlugin)
    EVT_MENU(idGitImportEntry, GitPlugin::OnMenuImport)
    EVT_MENU(idGitCommitEntry, GitPlugin::OnMenuCommit)
END_EVENT_TABLE()

// Constructor, load resources
GitPlugin::GitPlugin() {
    if(!Manager::LoadResource(_T("Codeblocks_Git_Plugin.zip"))) {
        NotifyMissingFile(_T("Codeblocks_Git_Plugin.zip"));
    }
}

GitPlugin::~GitPlugin() {
}

void GitPlugin::OnAttach() {
    git_threads_init();
}

void GitPlugin::OnRelease(bool appShutDown) {
    git_threads_shutdown();
}

int GitPlugin::Configure() {
    if(!IsAttached()) return -1;

    cbConfigurationDialog dlg(Manager::Get()->GetAppWindow(), wxID_ANY, _("GIT Plugin Configuration"));
    cbConfigurationPanel* panel = GetConfigurationPanel(&dlg);
    if(panel) {
        dlg.AttachConfigurationPanel(panel);
        PlaceWindow(&dlg);
        return dlg.ShowModal() == wxID_OK ? 0 : -1;
    }
    return -1;
}

void GitPlugin::BuildMenu(wxMenuBar* menuBar) {
    if(!IsAttached()) return;

    // Find import menu
    wxMenu* fileMenu = menuBar->GetMenu(0);
    int importMenuPos = fileMenu->FindItem(_("Import project"));
    if(importMenuPos == wxNOT_FOUND) {
        return;
    }
    wxMenu* importMenu = fileMenu->FindItem(importMenuPos, NULL)->GetSubMenu();

    // Add import item for Git
    wxMenuItem* gitItem = new wxMenuItem(importMenu, idGitImportEntry, _("Git Repository ..."));
    wxMenuItem* spacer = new wxMenuItem(importMenu, wxID_SEPARATOR, _(""), _(""), wxITEM_SEPARATOR);
    importMenu->Append(spacer);
    importMenu->Append(gitItem);
}

void GitPlugin::OnMenuImport(wxCommandEvent& event) {
    GitImportDialog dialog(Manager::Get()->GetAppWindow());
    if(dialog.run()) {

    }
}

void GitPlugin::OnMenuCommit(wxCommandEvent& event) {
    GitCommitDialog dialog(Manager::Get()->GetAppWindow());
    if(dialog.ShowModal() == wxID_OK) {

    }
}

void GitPlugin::buildFileMenu(wxMenu* menu) {
    // TODO: File menu
}

void GitPlugin::buildFolderMenu(wxMenu* menu) {
    // TODO: Folder menu
}

void GitPlugin::buildProjectMenu(wxMenu* menu) {
    wxMenu* gitMenu = new wxMenu();
    wxMenuItem* initItem = new wxMenuItem(gitMenu, idGitInitEntry, _("Init"));
    wxMenuItem* commitItem = new wxMenuItem(gitMenu, idGitCommitEntry, _("Commit"));
    wxMenuItem* pushItem = new wxMenuItem(gitMenu, idGitPushEntry, _("Push"));
    wxMenuItem* pullItem = new wxMenuItem(gitMenu, idGitPullEntry, _("Pull"));

    gitMenu->Append(initItem);
    gitMenu->Append(commitItem);
    gitMenu->Append(pushItem);
    gitMenu->Append(pullItem);

    menu->AppendSubMenu(gitMenu, _("Git"));
}

void GitPlugin::BuildModuleMenu(const ModuleType type, wxMenu* menu, const FileTreeData* data) {
    if(!IsAttached()) return;
    if(type != mtProjectManager) return;

    switch(data->GetKind()) {
        case FileTreeData::ftdkProject: buildProjectMenu(menu); break;
        case FileTreeData::ftdkFile:    buildFileMenu(menu);    break;
        case FileTreeData::ftdkFolder:  buildFolderMenu(menu);  break;
    }
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

// Disable "'this': used in base member initializer list"
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning(disable: 4355)
#endif

#ifdef ANDROID
#include <linux/in.h> // for  IPPROTO_TCP
#endif

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/make_shared.hpp>

#include "tcptransportsocket.hpp"

#include <qi/log.hpp>

qiLogCategory("qimessaging.transportsocket");

/**
 * ###
 * connect/disconnect promise could be called multiple times.
 * (error could be handled twice for example)
 * so catch the error and continue, only the first set is taken into account
 */

static void pSetError(qi::Promise<void> prom, const std::string &error) {
  try { //could have already been set.
    prom.setError(error);
  } catch (const qi::FutureException &fe) {
    if (fe.state() != qi::FutureException::ExceptionState_PromiseAlreadySet)
      throw;
    qiLogVerbose() << "Error already set on promise.";
  }
}

static void pSetValue(qi::Promise<void> prom) {
  try { //could have already been set.
    prom.setValue(0);
  } catch (const qi::FutureException &fe) {
    if (fe.state() != qi::FutureException::ExceptionState_PromiseAlreadySet)
      throw;
    qiLogVerbose() << "Value already set on promise.";
  }
}

namespace qi
{
  TcpTransportSocket::TcpTransportSocket(EventLoop* eventLoop, bool ssl, void* s)
    : TransportSocket()
    , _ssl(ssl)
    , _sslHandshake(false)
#ifdef WITH_SSL
    , _sslContext(boost::asio::ssl::context::sslv23)
#endif
    , _abort(false)
    , _msg(0)
    , _connecting(false)
    , _sending(false)
  {
    _eventLoop = eventLoop;
    _err = 0;
    _status = qi::TransportSocket::Status_Disconnected;

    if (s != 0)
    {
#ifdef WITH_SSL
      _socket = SocketPtr((boost::asio::ssl::stream<boost::asio::ip::tcp::socket>*) s);
#else
      _socket = SocketPtr((boost::asio::ip::tcp::socket*) s);
#endif
      _status = qi::TransportSocket::Status_Connected;

      // Transmit each Message without delay
      const boost::asio::ip::tcp::no_delay option( true );
      _socket->lowest_layer().set_option(option);
    }
    else
    {
      pSetValue(_disconnectPromise); // not connected, so we are finished disconnecting
    }
  }

  TcpTransportSocket::~TcpTransportSocket()
  {
    qiLogDebug() << this;
    boost::system::error_code erc;
    error(erc);
    delete _msg;
    qiLogVerbose() << "deleted " << this;
  }

  void TcpTransportSocket::startReading()
  {
    qiLogDebug() << this;

    _msg = new qi::Message();

    boost::recursive_mutex::scoped_lock l(_closingMutex);

    if (_abort)
    {
      boost::system::error_code erc;
      error(erc);
      return;
    }

#ifdef WITH_SSL
    if (_ssl)
    {
      if (!_sslHandshake)
      {
        _socket->async_handshake(boost::asio::ssl::stream_base::server,
          boost::bind(&TcpTransportSocket::handshake, shared_from_this(), _1));
        return;
      }

      boost::asio::async_read(*_socket,
        boost::asio::buffer(_msg->_p->getHeader(), sizeof(MessagePrivate::MessageHeader)),
        boost::bind(&TcpTransportSocket::onReadHeader, shared_from_this(), _1, _2));
    }
    else
    {
      boost::asio::async_read(_socket->next_layer(),
        boost::asio::buffer(_msg->_p->getHeader(), sizeof(MessagePrivate::MessageHeader)),
        boost::bind(&TcpTransportSocket::onReadHeader, shared_from_this(), _1, _2));
    }
#else
    boost::asio::async_read(*_socket,
      boost::asio::buffer(_msg->_p->getHeader(), sizeof(MessagePrivate::MessageHeader)),
      boost::bind(&TcpTransportSocket::onReadHeader, shared_from_this(), _1, _2));
#endif
  }

  void TcpTransportSocket::onReadHeader(const boost::system::error_code& erc,
    std::size_t len)
  {
    if (erc)
    {
      error(erc);
      return;
    }
    size_t payload = _msg->_p->header.size;
    if (payload)
    {
      void* ptr = _msg->_p->buffer.reserve(payload);

      boost::recursive_mutex::scoped_lock l(_closingMutex);

      if (_abort)
      {
        boost::system::error_code erc;
        error(erc);
        return;
      }

#ifdef WITH_SSL
      if (_ssl)
      {
        boost::asio::async_read(*_socket,
          boost::asio::buffer(ptr, payload),
          boost::bind(&TcpTransportSocket::onReadData, shared_from_this(), _1, _2));
      }
      else
      {
        boost::asio::async_read(_socket->next_layer(),
          boost::asio::buffer(ptr, payload),
          boost::bind(&TcpTransportSocket::onReadData, shared_from_this(), _1, _2));
      }
#else
      boost::asio::async_read(*_socket,
        boost::asio::buffer(ptr, payload),
        boost::bind(&TcpTransportSocket::onReadData, shared_from_this(), _1, _2));
#endif
    }
    else
      onReadData(boost::system::error_code(), 0);
  }

  void TcpTransportSocket::onReadData(const boost::system::error_code& erc,
    std::size_t len)
  {
    if (erc)
    {
      error(erc);
      return;
    }
      qiLogDebug() << this << " Recv (" << _msg->type() << "):" << _msg->address();
    static int usWarnThreshold = os::getenv("QIMESSAGING_SOCKET_DISPATCH_TIME_WARN_THRESHOLD").empty()?0:strtol(os::getenv("QIMESSAGING_SOCKET_DISPATCH_TIME_WARN_THRESHOLD").c_str(),0,0);
    qi::int64_t start = 0;
    if (usWarnThreshold)
      start = os::ustime(); // call might be not that cheap
    messageReady(*_msg);
    _dispatcher.dispatch(*_msg);
    if (usWarnThreshold)
    {
      qi::int64_t duration = os::ustime() - start;
      if (duration > usWarnThreshold)
        qiLogWarning() << "Dispatch to user took " << duration << "us";
    }
    delete _msg;
    startReading();
  }

  void TcpTransportSocket::error(const boost::system::error_code& erc)
  {
    boost::recursive_mutex::scoped_lock lock(_closingMutex);
    _abort = true;
    _status = qi::TransportSocket::Status_Disconnected;
    disconnected(erc.value());

    if (_connecting)
    {
      _connecting = false;
      pSetError(_connectPromise, std::string("Connection error: ") + erc.message());
    }

    {
      boost::mutex::scoped_lock l(_sendQueueMutex);
      boost::system::error_code er;
      if (_socket && _socket->lowest_layer().is_open())
      {
        _socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, er);
        _socket->lowest_layer().close(er);

      }
    }
    _socket.reset();
    pSetValue(_disconnectPromise);
  }

  qi::FutureSync<void> TcpTransportSocket::connect(const qi::Url &url)
  {
    boost::recursive_mutex::scoped_lock l(_closingMutex);

    if (_status == qi::TransportSocket::Status_Connected || _connecting)
    {
      const char* s = "connection already in progress";
      qiLogError() << s;
      return makeFutureError<void>(s);
    }
#ifdef WITH_SSL
    if (_ssl)
    {
      _sslContext.set_verify_mode(boost::asio::ssl::verify_none);
    }
    _socket = SocketPtr(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>((*(boost::asio::io_service*)_eventLoop->nativeHandle()), _sslContext));
#else
    _socket = SocketPtr(new boost::asio::ip::tcp::socket(*(boost::asio::io_service*)_eventLoop->nativeHandle()));
#endif
    _url = url;
    _connectPromise.reset();
    _disconnectPromise.reset();
    _status = qi::TransportSocket::Status_Connecting;
    _connecting = true;
    _err = 0;
    if (_url.port() == 0) {
      qiLogError() << "Error try to connect to a bad address: " << _url.str();
      pSetError(_connectPromise, std::string("Bad address ") + _url.str());

      _status = qi::TransportSocket::Status_Disconnected;
      _connecting = false;
      pSetValue(_disconnectPromise);
      return _connectPromise.future();
    }
    qiLogVerbose() << "Trying to connect to " << _url.host() << ":" << _url.port();
    using namespace boost::asio;
    // Resolve url
    ip::tcp::resolver r(_socket->get_io_service());
    ip::tcp::resolver::query q(_url.host(), boost::lexical_cast<std::string>(_url.port()));
    // Synchronous resolution

    try
    {
      ip::tcp::resolver::iterator it = r.resolve(q);
      // asynchronous connect
      _socket->lowest_layer().async_connect(*it,
        boost::bind(&TcpTransportSocket::onConnected, shared_from_this(), _1));
      return _connectPromise.future();
    }
    catch (const std::exception& e)
    {
      const char* s = e.what();
      qiLogError() << s;
      pSetError(_connectPromise, s);
      return _connectPromise.future();
    }
  }

  void TcpTransportSocket::handshake(const boost::system::error_code& erc)
  {
    if (erc)
    {
      qiLogWarning() << "connect: " << erc.message();
      _status = qi::TransportSocket::Status_Disconnected;
      pSetError(_connectPromise, erc.message());
      pSetValue(_disconnectPromise);
    }
    else
    {
      _status = qi::TransportSocket::Status_Connected;
      pSetValue(_connectPromise);
      connected();
      _sslHandshake = true;

      {
        boost::recursive_mutex::scoped_lock l(_closingMutex);

        if (_abort)
        {
          return;
        }
        // Transmit each Message without delay
        const boost::asio::ip::tcp::no_delay option( true );
        _socket->lowest_layer().set_option(option);
      }

      startReading();
    }
  }

  void TcpTransportSocket::onConnected(const boost::system::error_code& erc)
  {
    _connecting = false;
    if (erc)
    {
      qiLogWarning("qimessaging.TransportSocketLibEvent") << "connect: " << erc.message();
      _status = qi::TransportSocket::Status_Disconnected;
      pSetError(_connectPromise, erc.message());
      pSetValue(_disconnectPromise);
    }
    else
    {
      if (_ssl)
      {
#ifdef WITH_SSL
        _socket->async_handshake(boost::asio::ssl::stream_base::client,
          boost::bind(&TcpTransportSocket::handshake, shared_from_this(), _1));
#endif
      }
      else
      {
        _status = qi::TransportSocket::Status_Connected;
        pSetValue(_connectPromise);
        connected();

        {
          boost::recursive_mutex::scoped_lock l(_closingMutex);

          if (_abort)
          {
            return;
          }
          // Transmit each Message without delay
          const boost::asio::ip::tcp::no_delay option( true );
          _socket->lowest_layer().set_option(option);
        }

        startReading();
      }
    }
  }

  qi::FutureSync<void> TcpTransportSocket::disconnect()
  {
    boost::system::error_code erc;
    _eventLoop->post(boost::bind(&TcpTransportSocket::error,
                                 boost::static_pointer_cast<TcpTransportSocket>(shared_from_this()),
                                 erc));
    return _disconnectPromise.future();
  }

  bool TcpTransportSocket::send(const qi::Message &msg)
  {
    // Check that once before locking in case some idiot tries to send
    // from a disconnect notification.
    if (_status != qi::TransportSocket::Status_Connected)
      return false;
    boost::recursive_mutex::scoped_lock lockc(_closingMutex);

    if (!_socket || _status != qi::TransportSocket::Status_Connected)
    {
      qiLogDebug() << this << "Send on closed socket";
      return false;
    }

    qiLogDebug() << this << " Send (" << msg.type() << "):" << msg.address();
    boost::mutex::scoped_lock lock(_sendQueueMutex);

    if (!_sending)
    {
      _sending = true;
      send_(msg);
    }
    else
      _sendQueue.push_back(msg);
    return true;
  }

  void TcpTransportSocket::send_(qi::Message msg)
  {
    using boost::asio::buffer;
    std::vector<boost::asio::const_buffer> b;
    msg._p->complete();
    // Send header
    b.push_back(buffer(msg._p->getHeader(), sizeof(qi::MessagePrivate::MessageHeader)));
    const qi::Buffer& buf = msg.buffer();
    size_t sz = buf.size();
    const std::vector<std::pair<size_t, Buffer> >& subs = buf.subBuffers();
    size_t pos = 0;
    // Handle subbuffers
    for (unsigned i=0; i< subs.size(); ++i)
    {
      // Send parent buffer between pos and start of sub
      size_t end = subs[i].first+4;
      if (end != pos)
        b.push_back(buffer((const char*)buf.data() + pos, end-pos));
      pos = end;
      // Send subbuffer
      b.push_back(buffer(subs[i].second.data(), subs[i].second.size()));
    }
    b.push_back(buffer((const char*)buf.data() + pos, sz - pos));

    boost::recursive_mutex::scoped_lock l(_closingMutex);

    if (_abort)
    {
      qiLogWarning() << "send aborted";
      return;
    }

    _dispatcher.sent(msg);

#ifdef WITH_SSL
    if (_ssl)
    {
      boost::asio::async_write(*_socket, b,
        boost::bind(&TcpTransportSocket::sendCont, shared_from_this(), _1, msg));
    }
    else
    {
      boost::asio::async_write(_socket->next_layer(), b,
        boost::bind(&TcpTransportSocket::sendCont, shared_from_this(), _1, msg));
    }
#else
    boost::asio::async_write(*_socket, b,
      boost::bind(&TcpTransportSocket::sendCont, shared_from_this(), _1, msg));
#endif
  }

  /*
   * warning: msg is given to the callback so as not to drop buffers refcount
   */
  void TcpTransportSocket::sendCont(const boost::system::error_code& erc, qi::Message msg)
  {
    // The class does not wait for us to terminate, but it will set abort to true.
    // So do not use this before checking abort.
    if (erc || _abort)
      return; // read-callback will also get the error, avoid dup and ignore it
    boost::mutex::scoped_lock lock(_sendQueueMutex);
    if (_sendQueue.empty())
      _sending = false;
    else
    {
      qi::Message msg = _sendQueue.front();
      _sendQueue.pop_front();
      send_(msg);
    }
  }

}

<commit_msg>Drop send queue lock sooner when sending message<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

// Disable "'this': used in base member initializer list"
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning(disable: 4355)
#endif

#ifdef ANDROID
#include <linux/in.h> // for  IPPROTO_TCP
#endif

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/make_shared.hpp>

#include "tcptransportsocket.hpp"

#include <qi/log.hpp>

qiLogCategory("qimessaging.transportsocket");

/**
 * ###
 * connect/disconnect promise could be called multiple times.
 * (error could be handled twice for example)
 * so catch the error and continue, only the first set is taken into account
 */

static void pSetError(qi::Promise<void> prom, const std::string &error) {
  try { //could have already been set.
    prom.setError(error);
  } catch (const qi::FutureException &fe) {
    if (fe.state() != qi::FutureException::ExceptionState_PromiseAlreadySet)
      throw;
    qiLogVerbose() << "Error already set on promise.";
  }
}

static void pSetValue(qi::Promise<void> prom) {
  try { //could have already been set.
    prom.setValue(0);
  } catch (const qi::FutureException &fe) {
    if (fe.state() != qi::FutureException::ExceptionState_PromiseAlreadySet)
      throw;
    qiLogVerbose() << "Value already set on promise.";
  }
}

namespace qi
{
  TcpTransportSocket::TcpTransportSocket(EventLoop* eventLoop, bool ssl, void* s)
    : TransportSocket()
    , _ssl(ssl)
    , _sslHandshake(false)
#ifdef WITH_SSL
    , _sslContext(boost::asio::ssl::context::sslv23)
#endif
    , _abort(false)
    , _msg(0)
    , _connecting(false)
    , _sending(false)
  {
    _eventLoop = eventLoop;
    _err = 0;
    _status = qi::TransportSocket::Status_Disconnected;

    if (s != 0)
    {
#ifdef WITH_SSL
      _socket = SocketPtr((boost::asio::ssl::stream<boost::asio::ip::tcp::socket>*) s);
#else
      _socket = SocketPtr((boost::asio::ip::tcp::socket*) s);
#endif
      _status = qi::TransportSocket::Status_Connected;

      // Transmit each Message without delay
      const boost::asio::ip::tcp::no_delay option( true );
      _socket->lowest_layer().set_option(option);
    }
    else
    {
      pSetValue(_disconnectPromise); // not connected, so we are finished disconnecting
    }
  }

  TcpTransportSocket::~TcpTransportSocket()
  {
    qiLogDebug() << this;
    boost::system::error_code erc;
    error(erc);
    delete _msg;
    qiLogVerbose() << "deleted " << this;
  }

  void TcpTransportSocket::startReading()
  {
    qiLogDebug() << this;

    _msg = new qi::Message();

    boost::recursive_mutex::scoped_lock l(_closingMutex);

    if (_abort)
    {
      boost::system::error_code erc;
      error(erc);
      return;
    }

#ifdef WITH_SSL
    if (_ssl)
    {
      if (!_sslHandshake)
      {
        _socket->async_handshake(boost::asio::ssl::stream_base::server,
          boost::bind(&TcpTransportSocket::handshake, shared_from_this(), _1));
        return;
      }

      boost::asio::async_read(*_socket,
        boost::asio::buffer(_msg->_p->getHeader(), sizeof(MessagePrivate::MessageHeader)),
        boost::bind(&TcpTransportSocket::onReadHeader, shared_from_this(), _1, _2));
    }
    else
    {
      boost::asio::async_read(_socket->next_layer(),
        boost::asio::buffer(_msg->_p->getHeader(), sizeof(MessagePrivate::MessageHeader)),
        boost::bind(&TcpTransportSocket::onReadHeader, shared_from_this(), _1, _2));
    }
#else
    boost::asio::async_read(*_socket,
      boost::asio::buffer(_msg->_p->getHeader(), sizeof(MessagePrivate::MessageHeader)),
      boost::bind(&TcpTransportSocket::onReadHeader, shared_from_this(), _1, _2));
#endif
  }

  void TcpTransportSocket::onReadHeader(const boost::system::error_code& erc,
    std::size_t len)
  {
    if (erc)
    {
      error(erc);
      return;
    }
    size_t payload = _msg->_p->header.size;
    if (payload)
    {
      void* ptr = _msg->_p->buffer.reserve(payload);

      boost::recursive_mutex::scoped_lock l(_closingMutex);

      if (_abort)
      {
        boost::system::error_code erc;
        error(erc);
        return;
      }

#ifdef WITH_SSL
      if (_ssl)
      {
        boost::asio::async_read(*_socket,
          boost::asio::buffer(ptr, payload),
          boost::bind(&TcpTransportSocket::onReadData, shared_from_this(), _1, _2));
      }
      else
      {
        boost::asio::async_read(_socket->next_layer(),
          boost::asio::buffer(ptr, payload),
          boost::bind(&TcpTransportSocket::onReadData, shared_from_this(), _1, _2));
      }
#else
      boost::asio::async_read(*_socket,
        boost::asio::buffer(ptr, payload),
        boost::bind(&TcpTransportSocket::onReadData, shared_from_this(), _1, _2));
#endif
    }
    else
      onReadData(boost::system::error_code(), 0);
  }

  void TcpTransportSocket::onReadData(const boost::system::error_code& erc,
    std::size_t len)
  {
    if (erc)
    {
      error(erc);
      return;
    }
      qiLogDebug() << this << " Recv (" << _msg->type() << "):" << _msg->address();
    static int usWarnThreshold = os::getenv("QIMESSAGING_SOCKET_DISPATCH_TIME_WARN_THRESHOLD").empty()?0:strtol(os::getenv("QIMESSAGING_SOCKET_DISPATCH_TIME_WARN_THRESHOLD").c_str(),0,0);
    qi::int64_t start = 0;
    if (usWarnThreshold)
      start = os::ustime(); // call might be not that cheap
    messageReady(*_msg);
    _dispatcher.dispatch(*_msg);
    if (usWarnThreshold)
    {
      qi::int64_t duration = os::ustime() - start;
      if (duration > usWarnThreshold)
        qiLogWarning() << "Dispatch to user took " << duration << "us";
    }
    delete _msg;
    startReading();
  }

  void TcpTransportSocket::error(const boost::system::error_code& erc)
  {
    boost::recursive_mutex::scoped_lock lock(_closingMutex);
    _abort = true;
    _status = qi::TransportSocket::Status_Disconnected;
    disconnected(erc.value());

    if (_connecting)
    {
      _connecting = false;
      pSetError(_connectPromise, std::string("Connection error: ") + erc.message());
    }

    {
      boost::mutex::scoped_lock l(_sendQueueMutex);
      boost::system::error_code er;
      if (_socket && _socket->lowest_layer().is_open())
      {
        _socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, er);
        _socket->lowest_layer().close(er);

      }
    }
    _socket.reset();
    pSetValue(_disconnectPromise);
  }

  qi::FutureSync<void> TcpTransportSocket::connect(const qi::Url &url)
  {
    boost::recursive_mutex::scoped_lock l(_closingMutex);

    if (_status == qi::TransportSocket::Status_Connected || _connecting)
    {
      const char* s = "connection already in progress";
      qiLogError() << s;
      return makeFutureError<void>(s);
    }
#ifdef WITH_SSL
    if (_ssl)
    {
      _sslContext.set_verify_mode(boost::asio::ssl::verify_none);
    }
    _socket = SocketPtr(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>((*(boost::asio::io_service*)_eventLoop->nativeHandle()), _sslContext));
#else
    _socket = SocketPtr(new boost::asio::ip::tcp::socket(*(boost::asio::io_service*)_eventLoop->nativeHandle()));
#endif
    _url = url;
    _connectPromise.reset();
    _disconnectPromise.reset();
    _status = qi::TransportSocket::Status_Connecting;
    _connecting = true;
    _err = 0;
    if (_url.port() == 0) {
      qiLogError() << "Error try to connect to a bad address: " << _url.str();
      pSetError(_connectPromise, std::string("Bad address ") + _url.str());

      _status = qi::TransportSocket::Status_Disconnected;
      _connecting = false;
      pSetValue(_disconnectPromise);
      return _connectPromise.future();
    }
    qiLogVerbose() << "Trying to connect to " << _url.host() << ":" << _url.port();
    using namespace boost::asio;
    // Resolve url
    ip::tcp::resolver r(_socket->get_io_service());
    ip::tcp::resolver::query q(_url.host(), boost::lexical_cast<std::string>(_url.port()));
    // Synchronous resolution

    try
    {
      ip::tcp::resolver::iterator it = r.resolve(q);
      // asynchronous connect
      _socket->lowest_layer().async_connect(*it,
        boost::bind(&TcpTransportSocket::onConnected, shared_from_this(), _1));
      return _connectPromise.future();
    }
    catch (const std::exception& e)
    {
      const char* s = e.what();
      qiLogError() << s;
      pSetError(_connectPromise, s);
      return _connectPromise.future();
    }
  }

  void TcpTransportSocket::handshake(const boost::system::error_code& erc)
  {
    if (erc)
    {
      qiLogWarning() << "connect: " << erc.message();
      _status = qi::TransportSocket::Status_Disconnected;
      pSetError(_connectPromise, erc.message());
      pSetValue(_disconnectPromise);
    }
    else
    {
      _status = qi::TransportSocket::Status_Connected;
      pSetValue(_connectPromise);
      connected();
      _sslHandshake = true;

      {
        boost::recursive_mutex::scoped_lock l(_closingMutex);

        if (_abort)
        {
          return;
        }
        // Transmit each Message without delay
        const boost::asio::ip::tcp::no_delay option( true );
        _socket->lowest_layer().set_option(option);
      }

      startReading();
    }
  }

  void TcpTransportSocket::onConnected(const boost::system::error_code& erc)
  {
    _connecting = false;
    if (erc)
    {
      qiLogWarning("qimessaging.TransportSocketLibEvent") << "connect: " << erc.message();
      _status = qi::TransportSocket::Status_Disconnected;
      pSetError(_connectPromise, erc.message());
      pSetValue(_disconnectPromise);
    }
    else
    {
      if (_ssl)
      {
#ifdef WITH_SSL
        _socket->async_handshake(boost::asio::ssl::stream_base::client,
          boost::bind(&TcpTransportSocket::handshake, shared_from_this(), _1));
#endif
      }
      else
      {
        _status = qi::TransportSocket::Status_Connected;
        pSetValue(_connectPromise);
        connected();

        {
          boost::recursive_mutex::scoped_lock l(_closingMutex);

          if (_abort)
          {
            return;
          }
          // Transmit each Message without delay
          const boost::asio::ip::tcp::no_delay option( true );
          _socket->lowest_layer().set_option(option);
        }

        startReading();
      }
    }
  }

  qi::FutureSync<void> TcpTransportSocket::disconnect()
  {
    boost::system::error_code erc;
    _eventLoop->post(boost::bind(&TcpTransportSocket::error,
                                 boost::static_pointer_cast<TcpTransportSocket>(shared_from_this()),
                                 erc));
    return _disconnectPromise.future();
  }

  bool TcpTransportSocket::send(const qi::Message &msg)
  {
    // Check that once before locking in case some idiot tries to send
    // from a disconnect notification.
    if (_status != qi::TransportSocket::Status_Connected)
      return false;
    boost::recursive_mutex::scoped_lock lockc(_closingMutex);

    if (!_socket || _status != qi::TransportSocket::Status_Connected)
    {
      qiLogDebug() << this << "Send on closed socket";
      return false;
    }

    qiLogDebug() << this << " Send (" << msg.type() << "):" << msg.address();
    boost::mutex::scoped_lock lock(_sendQueueMutex);

    if (!_sending)
    {
      _sending = true;
      send_(msg);
    }
    else
      _sendQueue.push_back(msg);
    return true;
  }

  void TcpTransportSocket::send_(qi::Message msg)
  {
    using boost::asio::buffer;
    std::vector<boost::asio::const_buffer> b;
    msg._p->complete();
    // Send header
    b.push_back(buffer(msg._p->getHeader(), sizeof(qi::MessagePrivate::MessageHeader)));
    const qi::Buffer& buf = msg.buffer();
    size_t sz = buf.size();
    const std::vector<std::pair<size_t, Buffer> >& subs = buf.subBuffers();
    size_t pos = 0;
    // Handle subbuffers
    for (unsigned i=0; i< subs.size(); ++i)
    {
      // Send parent buffer between pos and start of sub
      size_t end = subs[i].first+4;
      if (end != pos)
        b.push_back(buffer((const char*)buf.data() + pos, end-pos));
      pos = end;
      // Send subbuffer
      b.push_back(buffer(subs[i].second.data(), subs[i].second.size()));
    }
    b.push_back(buffer((const char*)buf.data() + pos, sz - pos));

    boost::recursive_mutex::scoped_lock l(_closingMutex);

    if (_abort)
    {
      qiLogWarning() << "send aborted";
      return;
    }

    _dispatcher.sent(msg);

#ifdef WITH_SSL
    if (_ssl)
    {
      boost::asio::async_write(*_socket, b,
        boost::bind(&TcpTransportSocket::sendCont, shared_from_this(), _1, msg));
    }
    else
    {
      boost::asio::async_write(_socket->next_layer(), b,
        boost::bind(&TcpTransportSocket::sendCont, shared_from_this(), _1, msg));
    }
#else
    boost::asio::async_write(*_socket, b,
      boost::bind(&TcpTransportSocket::sendCont, shared_from_this(), _1, msg));
#endif
  }

  /*
   * warning: msg is given to the callback so as not to drop buffers refcount
   */
  void TcpTransportSocket::sendCont(const boost::system::error_code& erc, qi::Message msg)
  {
    // The class does not wait for us to terminate, but it will set abort to true.
    // So do not use this before checking abort.
    if (erc || _abort)
      return; // read-callback will also get the error, avoid dup and ignore it

    qi::Message m;
    {
      boost::mutex::scoped_lock lock(_sendQueueMutex);
      if (_sendQueue.empty())
      {
        _sending = false;
        return;
      }

      m = _sendQueue.front();
      _sendQueue.pop_front();
    }

    send_(m);
  }

}

<|endoftext|>


<commit_before>#include "postal.h"

#include <libpostal/libpostal.h>

#include <iostream>
#include <sstream>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

using namespace GeoNLP;

#define ADDRESS_PARSER_LABEL_HOUSE "house"
#define ADDRESS_PARSER_LABEL_CATEGORY "category"
#define ADDRESS_PARSER_LABEL_HOUSE_NUMBER "house_number"
#define ADDRESS_PARSER_LABEL_ROAD "road"
#define ADDRESS_PARSER_LABEL_SUBURB "suburb"
#define ADDRESS_PARSER_LABEL_CITY_DISTRICT "city_district"
#define ADDRESS_PARSER_LABEL_CITY "city"
#define ADDRESS_PARSER_LABEL_ISLAND "island"
#define ADDRESS_PARSER_LABEL_STATE_DISTRICT  "state_district"
#define ADDRESS_PARSER_LABEL_STATE  "state"
#define ADDRESS_PARSER_LABEL_POSTAL_CODE  "postal_code"
#define ADDRESS_PARSER_LABEL_COUNTRY_REGION "country_region"
#define ADDRESS_PARSER_LABEL_COUNTRY  "country"

//////////////////////////////////////////////////////////////////////
/// Helper string functions
///

static void str2vecchar(const std::string &s, std::vector<char> &v)
{
  v.resize(s.length() + 1);
  std::copy(s.c_str(), s.c_str() + s.length() + 1, v.begin());
}

// trim from start
static inline std::string &ltrim(std::string &s) {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(),
				  std::not1(std::ptr_fun<int, int>(std::isspace))));
  return s;
}

// trim from end
static inline std::string &rtrim(std::string &s) {
  s.erase(std::find_if(s.rbegin(), s.rend(),
		       std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
  return s;
}

// trim from both ends
static inline std::string &trim(std::string &s) {
  return ltrim(rtrim(s));
}

static void split_tokens(const std::string &s, char delim,
                         std::vector<std::string> &elems)
{
  std::stringstream ss;
  ss.str(s);
  std::string item;
  while (std::getline(ss, item, delim))
    if (!item.empty())
      elems.push_back(trim(item));
}

static std::string primitive_key(size_t ind)
{
  std::ostringstream ss;
  ss << "h-" << ind;
  return ss.str();
}

// //////////////////////////////////////////////////////
// /// Helper classes and functions for cartesian product

// // cartesian product from http://stackoverflow.com/questions/5279051/how-can-i-create-cartesian-product-of-vector-of-vectors
// typedef std::vector<std::string> Vi;
// typedef std::vector<Vi> Vvi;

// struct Digits {
//   Vi::const_iterator begin;
//   Vi::const_iterator end;
//   Vi::const_iterator me;
// };
// typedef std::vector<Digits> Vd;

// static void cart_product(
// 			 Vvi& out,
// 			 Vvi& in)

// {
//   Vd vd;

//   // Start all of the iterators at the beginning.
//   for(Vvi::const_iterator it = in.begin();
//       it != in.end();
//       ++it) {
//     Digits d = {(*it).begin(), (*it).end(), (*it).begin()};
//     vd.push_back(d);
//   }

//   while(1) {

//     // Construct your first product vector by pulling
//     // out the element of each vector via the iterator.
//     Vi result;
//     for(Vd::const_iterator it = vd.begin();
// 	it != vd.end();
// 	it++) {
//       result.push_back(*(it->me));
//     }
//     out.push_back(result);

//     // Increment the rightmost one, and repeat.

//     // When you reach the end, reset that one to the beginning and
//     // increment the next-to-last one. You can get the "next-to-last"
//     // iterator by pulling it out of the neighboring element in your
//     // vector of iterators.
//     for(Vd::iterator it = vd.begin(); ; ) {
//       // okay, I started at the left instead. sue me
//       ++(it->me);
//       if(it->me == it->end) {
// 	if(it+1 == vd.end()) {
// 	  // I'm the last digit, and I'm about to roll
// 	  return;
// 	} else {
// 	  // cascade
// 	  it->me = it->begin;
// 	  ++it;
// 	}
//       } else {
// 	// normal
// 	break;
//       }
//     }
//   }
// }

///////////////////////////////////////////////////////////////////
/// Postal class

Postal::Postal()
{

}

Postal::~Postal()
{
  drop();
}

void Postal::set_postal_datadir(const std::string &global, const std::string &country)
{
  if (global.length() < 1) m_postal_datadir_global.clear();
  else str2vecchar(global, m_postal_datadir_global);

  if (country.length() < 1) m_postal_datadir_country.clear();
  else str2vecchar(country, m_postal_datadir_country);

  drop(); // force reinitialization
}

void Postal::set_postal_datadir_country(const std::string &country)
{
  std::vector<char> nc;
  if (country.length() >= 1) str2vecchar(country, nc);

  if (nc == m_postal_datadir_country) return; // nothing to do

  m_postal_datadir_country = nc;
  if (m_initialized)
    {
      // have to drop current country-specific parser and load a new one
      libpostal_teardown_parser();

      if ( (m_postal_datadir_country.empty() && !libpostal_setup_parser() ) ||
           (!m_postal_datadir_country.empty() && !libpostal_setup_parser_datadir(m_postal_datadir_country.data())) )
        {
          std::cerr << "Postal: Error at set_postal_datadir_country " << country << std::endl;
          drop();
        }
    }
}

void Postal::add_language(const std::string &lang)
{
  std::vector<char> l;
  str2vecchar(lang, l);
  m_postal_languages.push_back(l);
  drop();
}

bool Postal::init()
{
  if (m_initialized) return true;

  if ( (m_postal_datadir_global.empty() && !libpostal_setup() ) ||
       (!m_postal_datadir_global.empty() && !libpostal_setup_datadir(m_postal_datadir_global.data())) )
    return false;

  if ( m_postal_languages.empty() )
    {
      if ( (m_postal_datadir_global.empty() && !libpostal_setup_language_classifier() ) ||
	   (!m_postal_datadir_global.empty() && !libpostal_setup_language_classifier_datadir(m_postal_datadir_global.data())) )
	return false;
    }

  if ( (m_postal_datadir_country.empty() && !libpostal_setup_parser() ) ||
       (!m_postal_datadir_country.empty() && !libpostal_setup_parser_datadir(m_postal_datadir_country.data())) )
    return false;

  m_initialized = true;
  return true;
}

void Postal::drop()
{
  if (!m_initialized) return;
  libpostal_teardown_parser();
  libpostal_teardown();
  libpostal_teardown_language_classifier();
  m_initialized = false;
}

/// Normalize first, expand next. Seems to miss few expansions in current implementation
/// Have to wait for new libpostal version to switch to this approach

//bool Postal::parse(const std::string &input, std::vector<Postal::ParseResult> &result)
//{
//    if (!init()) return false;

//    // convert string into vector of chars (libpostal uses char* as an argument, not const char*)
//    std::vector<char> charbuff;
//    charbuff.resize(input.length() + 1);
//    std::copy(input.c_str(), input.c_str() + input.length() + 1, charbuff.begin());

//    size_t num_expansions;
//    normalize_options_t options_norm = get_libpostal_default_options();
//    address_parser_options_t options_parse = get_libpostal_address_parser_default_options();

//    char **expansions = expand_address(charbuff.data(), options_norm, &num_expansions);
//    if (m_initialize_for_every_call)
//        libpostal_teardown_language_classifier();

//    for (size_t i = 0; i < num_expansions; i++)
//    {
//        address_parser_response_t *parsed = parse_address(expansions[i], options_parse);

//        ParseResult r;
//        for (size_t j = 0; j < parsed->num_components; j++)
//            r[ parsed->labels[j] ] = parsed->components[j];

//        result.push_back(r);

//        address_parser_response_destroy(parsed);
//    }

//    expansion_array_destroy(expansions, num_expansions);

//    if (m_initialize_for_every_call) drop();

//    return true;
//}

//////////////////////////////////////////////////////////////
/// expand first then normalize

bool Postal::parse(const std::string &input, std::vector<Postal::ParseResult> &result,
                   Postal::ParseResult &nonormalization)
{
  if (m_use_postal && !init())
    return false;

  // libpostal parsing
  if (m_use_postal)
    {
      // convert string into vector of chars (libpostal uses char* as an argument, not const char*)
      std::vector<char> charbuff;
      charbuff.resize(input.length() + 1);
      std::copy(input.c_str(), input.c_str() + input.length() + 1, charbuff.begin());

      libpostal_address_parser_options_t options_parse = libpostal_get_address_parser_default_options();

      // parse the address
      libpostal_address_parser_response_t *parsed = libpostal_parse_address(charbuff.data(), options_parse);
      nonormalization.clear();
      for (size_t j = 0; j < parsed->num_components; j++)
        {
          std::vector<std::string> pc; pc.push_back(parsed->components[j]);
          nonormalization[ parsed->labels[j] ] = pc;
        }
      libpostal_address_parser_response_destroy(parsed);

      expand(nonormalization, result);
    }

  // primitive parsing
  if (m_use_primitive)
    {
      std::vector<std::string> hier;
      split_tokens(input, ',', hier);

      if (!hier.empty())
        {
	  ParseResult prim;
	  for (size_t j = 0; j < hier.size(); j++)
            {
              std::vector<std::string> pc; pc.push_back(hier[hier.size()-j-1]);
              prim[ primitive_key(j) ] = pc;
            }

	  expand(prim, result);
        }
    }

  if (m_initialize_for_every_call) drop();

  return true;
}

void Postal::expand(const Postal::ParseResult &input, std::vector<Postal::ParseResult> &result)
{
  if (!m_use_postal || !init())
    {
      result.push_back(input);
      return;
    }

  size_t num_expansions;
  libpostal_normalize_options_t options_norm = libpostal_get_default_options();

  std::vector<char*> lang;
  for (std::vector<char> &l: m_postal_languages)
    lang.push_back(l.data());

  options_norm.languages = lang.data();
  options_norm.num_languages = lang.size();

  std::vector<char> charbuff;

  std::vector< std::vector< std::string > > address_expansions;
  std::vector< std::string > address_keys;
  for (const auto i: input)
    {
      // in practice, its only one element at ParseResult at this stage
      for (const std::string tonorm: i.second)
        {
          charbuff.resize(tonorm.length() + 1);
          std::copy(tonorm.c_str(), tonorm.c_str() + tonorm.length() + 1, charbuff.begin());

          char **expansions = libpostal_expand_address(charbuff.data(), options_norm, &num_expansions);
          std::vector< std::string > norm;
          for (size_t j = 0; j < num_expansions; j++)
            norm.push_back(expansions[j]);

          libpostal_expansion_array_destroy(expansions, num_expansions);

          address_expansions.push_back(norm);
          address_keys.push_back(i.first);
        }
    }

  ParseResult r;
  for (size_t i=0; i < address_keys.size(); ++i)
    r[ address_keys[i] ] = address_expansions[i];
  result.push_back(r);
}

void Postal::expand_string(const std::string &input, std::vector<std::string> &expansions)
{
  if (!m_use_postal || !init())
    {
      expansions.push_back(input);
      return;
    }

  size_t num_expansions;
  libpostal_normalize_options_t options_norm = libpostal_get_default_options();

  std::vector<char*> lang;
  for (std::vector<char> &l: m_postal_languages)
    lang.push_back(l.data());

  options_norm.languages = lang.data();
  options_norm.num_languages = lang.size();

  std::vector<char> charbuff;

  charbuff.resize(input.length() + 1);
  std::copy(input.c_str(), input.c_str() + input.length() + 1, charbuff.begin());

  char **expansions_cstr = libpostal_expand_address(charbuff.data(), options_norm, &num_expansions);
  std::vector< std::string > norm;
  for (size_t j = 0; j < num_expansions; j++)
    expansions.push_back(expansions_cstr[j]);

  libpostal_expansion_array_destroy(expansions_cstr, num_expansions);
}

void Postal::result2hierarchy(const std::vector<ParseResult> &p, std::vector<Hierarchy> &h)
{
  h.clear();
  for (const ParseResult &r: p)
    {
      Hierarchy h_result;
#define ADDIFHAS(k) { ParseResult::const_iterator it = r.find(k); if (it != r.end()) h_result.push_back(it->second); }

      ADDIFHAS(ADDRESS_PARSER_LABEL_COUNTRY);
      ADDIFHAS(ADDRESS_PARSER_LABEL_COUNTRY_REGION);
      ADDIFHAS(ADDRESS_PARSER_LABEL_STATE);
      ADDIFHAS(ADDRESS_PARSER_LABEL_STATE_DISTRICT);
      ADDIFHAS(ADDRESS_PARSER_LABEL_ISLAND);
      ADDIFHAS(ADDRESS_PARSER_LABEL_CITY);
      ADDIFHAS(ADDRESS_PARSER_LABEL_CITY_DISTRICT);
      ADDIFHAS(ADDRESS_PARSER_LABEL_SUBURB);
      ADDIFHAS(ADDRESS_PARSER_LABEL_ROAD);
      ADDIFHAS(ADDRESS_PARSER_LABEL_HOUSE_NUMBER);
      ADDIFHAS(ADDRESS_PARSER_LABEL_CATEGORY);
      ADDIFHAS(ADDRESS_PARSER_LABEL_HOUSE);

      // test if its primitive expansion result
      if (h_result.empty())
        {
	  bool done = false;
	  for (size_t i=0; !done; ++i)
            {
	      ParseResult::const_iterator it = r.find(primitive_key(i));
	      if (it == r.end())
		done = true;
	      else
		h_result.push_back(it->second);
            }
        }

      h.push_back(h_result);
    }
}
<commit_msg>always use libpostal normalization, even without its parser<commit_after>#include "postal.h"

#include <libpostal/libpostal.h>

#include <iostream>
#include <sstream>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

using namespace GeoNLP;

#define ADDRESS_PARSER_LABEL_HOUSE "house"
#define ADDRESS_PARSER_LABEL_CATEGORY "category"
#define ADDRESS_PARSER_LABEL_HOUSE_NUMBER "house_number"
#define ADDRESS_PARSER_LABEL_ROAD "road"
#define ADDRESS_PARSER_LABEL_SUBURB "suburb"
#define ADDRESS_PARSER_LABEL_CITY_DISTRICT "city_district"
#define ADDRESS_PARSER_LABEL_CITY "city"
#define ADDRESS_PARSER_LABEL_ISLAND "island"
#define ADDRESS_PARSER_LABEL_STATE_DISTRICT  "state_district"
#define ADDRESS_PARSER_LABEL_STATE  "state"
#define ADDRESS_PARSER_LABEL_POSTAL_CODE  "postal_code"
#define ADDRESS_PARSER_LABEL_COUNTRY_REGION "country_region"
#define ADDRESS_PARSER_LABEL_COUNTRY  "country"

//////////////////////////////////////////////////////////////////////
/// Helper string functions
///

static void str2vecchar(const std::string &s, std::vector<char> &v)
{
  v.resize(s.length() + 1);
  std::copy(s.c_str(), s.c_str() + s.length() + 1, v.begin());
}

// trim from start
static inline std::string &ltrim(std::string &s) {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(),
				  std::not1(std::ptr_fun<int, int>(std::isspace))));
  return s;
}

// trim from end
static inline std::string &rtrim(std::string &s) {
  s.erase(std::find_if(s.rbegin(), s.rend(),
		       std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
  return s;
}

// trim from both ends
static inline std::string &trim(std::string &s) {
  return ltrim(rtrim(s));
}

static void split_tokens(const std::string &s, char delim,
                         std::vector<std::string> &elems)
{
  std::stringstream ss;
  ss.str(s);
  std::string item;
  while (std::getline(ss, item, delim))
    if (!item.empty())
      elems.push_back(trim(item));
}

static std::string primitive_key(size_t ind)
{
  std::ostringstream ss;
  ss << "h-" << ind;
  return ss.str();
}

// //////////////////////////////////////////////////////
// /// Helper classes and functions for cartesian product

// // cartesian product from http://stackoverflow.com/questions/5279051/how-can-i-create-cartesian-product-of-vector-of-vectors
// typedef std::vector<std::string> Vi;
// typedef std::vector<Vi> Vvi;

// struct Digits {
//   Vi::const_iterator begin;
//   Vi::const_iterator end;
//   Vi::const_iterator me;
// };
// typedef std::vector<Digits> Vd;

// static void cart_product(
// 			 Vvi& out,
// 			 Vvi& in)

// {
//   Vd vd;

//   // Start all of the iterators at the beginning.
//   for(Vvi::const_iterator it = in.begin();
//       it != in.end();
//       ++it) {
//     Digits d = {(*it).begin(), (*it).end(), (*it).begin()};
//     vd.push_back(d);
//   }

//   while(1) {

//     // Construct your first product vector by pulling
//     // out the element of each vector via the iterator.
//     Vi result;
//     for(Vd::const_iterator it = vd.begin();
// 	it != vd.end();
// 	it++) {
//       result.push_back(*(it->me));
//     }
//     out.push_back(result);

//     // Increment the rightmost one, and repeat.

//     // When you reach the end, reset that one to the beginning and
//     // increment the next-to-last one. You can get the "next-to-last"
//     // iterator by pulling it out of the neighboring element in your
//     // vector of iterators.
//     for(Vd::iterator it = vd.begin(); ; ) {
//       // okay, I started at the left instead. sue me
//       ++(it->me);
//       if(it->me == it->end) {
// 	if(it+1 == vd.end()) {
// 	  // I'm the last digit, and I'm about to roll
// 	  return;
// 	} else {
// 	  // cascade
// 	  it->me = it->begin;
// 	  ++it;
// 	}
//       } else {
// 	// normal
// 	break;
//       }
//     }
//   }
// }

///////////////////////////////////////////////////////////////////
/// Postal class

Postal::Postal()
{

}

Postal::~Postal()
{
  drop();
}

void Postal::set_postal_datadir(const std::string &global, const std::string &country)
{
  if (global.length() < 1) m_postal_datadir_global.clear();
  else str2vecchar(global, m_postal_datadir_global);

  if (country.length() < 1) m_postal_datadir_country.clear();
  else str2vecchar(country, m_postal_datadir_country);

  drop(); // force reinitialization
}

void Postal::set_postal_datadir_country(const std::string &country)
{
  std::vector<char> nc;
  if (country.length() >= 1) str2vecchar(country, nc);

  if (nc == m_postal_datadir_country) return; // nothing to do

  m_postal_datadir_country = nc;
  if (m_initialized)
    {
      // have to drop current country-specific parser and load a new one
      libpostal_teardown_parser();

      if ( (m_postal_datadir_country.empty() && !libpostal_setup_parser() ) ||
           (!m_postal_datadir_country.empty() && !libpostal_setup_parser_datadir(m_postal_datadir_country.data())) )
        {
          std::cerr << "Postal: Error at set_postal_datadir_country " << country << std::endl;
          drop();
        }
    }
}

void Postal::add_language(const std::string &lang)
{
  std::vector<char> l;
  str2vecchar(lang, l);
  m_postal_languages.push_back(l);
  drop();
}

bool Postal::init()
{
  if (m_initialized) return true;

  if ( (m_postal_datadir_global.empty() && !libpostal_setup() ) ||
       (!m_postal_datadir_global.empty() && !libpostal_setup_datadir(m_postal_datadir_global.data())) )
    return false;

  if ( m_postal_languages.empty() )
    {
      if ( (m_postal_datadir_global.empty() && !libpostal_setup_language_classifier() ) ||
	   (!m_postal_datadir_global.empty() && !libpostal_setup_language_classifier_datadir(m_postal_datadir_global.data())) )
	return false;
    }

  if ( (m_postal_datadir_country.empty() && !libpostal_setup_parser() ) ||
       (!m_postal_datadir_country.empty() && !libpostal_setup_parser_datadir(m_postal_datadir_country.data())) )
    return false;

  m_initialized = true;
  return true;
}

void Postal::drop()
{
  if (!m_initialized) return;
  libpostal_teardown_parser();
  libpostal_teardown();
  libpostal_teardown_language_classifier();
  m_initialized = false;
}

/// Normalize first, expand next. Seems to miss few expansions in current implementation
/// Have to wait for new libpostal version to switch to this approach

//bool Postal::parse(const std::string &input, std::vector<Postal::ParseResult> &result)
//{
//    if (!init()) return false;

//    // convert string into vector of chars (libpostal uses char* as an argument, not const char*)
//    std::vector<char> charbuff;
//    charbuff.resize(input.length() + 1);
//    std::copy(input.c_str(), input.c_str() + input.length() + 1, charbuff.begin());

//    size_t num_expansions;
//    normalize_options_t options_norm = get_libpostal_default_options();
//    address_parser_options_t options_parse = get_libpostal_address_parser_default_options();

//    char **expansions = expand_address(charbuff.data(), options_norm, &num_expansions);
//    if (m_initialize_for_every_call)
//        libpostal_teardown_language_classifier();

//    for (size_t i = 0; i < num_expansions; i++)
//    {
//        address_parser_response_t *parsed = parse_address(expansions[i], options_parse);

//        ParseResult r;
//        for (size_t j = 0; j < parsed->num_components; j++)
//            r[ parsed->labels[j] ] = parsed->components[j];

//        result.push_back(r);

//        address_parser_response_destroy(parsed);
//    }

//    expansion_array_destroy(expansions, num_expansions);

//    if (m_initialize_for_every_call) drop();

//    return true;
//}

//////////////////////////////////////////////////////////////
/// expand first then normalize

bool Postal::parse(const std::string &input, std::vector<Postal::ParseResult> &result,
                   Postal::ParseResult &nonormalization)
{
  if (m_use_postal && !init())
    return false;

  // libpostal parsing
  if (m_use_postal)
    {
      // convert string into vector of chars (libpostal uses char* as an argument, not const char*)
      std::vector<char> charbuff;
      charbuff.resize(input.length() + 1);
      std::copy(input.c_str(), input.c_str() + input.length() + 1, charbuff.begin());

      libpostal_address_parser_options_t options_parse = libpostal_get_address_parser_default_options();

      // parse the address
      libpostal_address_parser_response_t *parsed = libpostal_parse_address(charbuff.data(), options_parse);
      nonormalization.clear();
      for (size_t j = 0; j < parsed->num_components; j++)
        {
          std::vector<std::string> pc; pc.push_back(parsed->components[j]);
          nonormalization[ parsed->labels[j] ] = pc;
        }
      libpostal_address_parser_response_destroy(parsed);

      expand(nonormalization, result);
    }

  // primitive parsing
  if (m_use_primitive)
    {
      std::vector<std::string> hier;
      split_tokens(input, ',', hier);

      if (!hier.empty())
        {
	  ParseResult prim;
	  for (size_t j = 0; j < hier.size(); j++)
            {
              std::vector<std::string> pc; pc.push_back(hier[hier.size()-j-1]);
              prim[ primitive_key(j) ] = pc;
            }

	  expand(prim, result);
        }
    }

  if (m_initialize_for_every_call) drop();

  return true;
}

void Postal::expand(const Postal::ParseResult &input, std::vector<Postal::ParseResult> &result)
{
  if (!init())
    {
      result.push_back(input);
      return;
    }

  size_t num_expansions;
  libpostal_normalize_options_t options_norm = libpostal_get_default_options();

  std::vector<char*> lang;
  for (std::vector<char> &l: m_postal_languages)
    lang.push_back(l.data());

  options_norm.languages = lang.data();
  options_norm.num_languages = lang.size();

  std::vector<char> charbuff;

  std::vector< std::vector< std::string > > address_expansions;
  std::vector< std::string > address_keys;
  for (const auto i: input)
    {
      // in practice, its only one element at ParseResult at this stage
      for (const std::string tonorm: i.second)
        {
          charbuff.resize(tonorm.length() + 1);
          std::copy(tonorm.c_str(), tonorm.c_str() + tonorm.length() + 1, charbuff.begin());

          char **expansions = libpostal_expand_address(charbuff.data(), options_norm, &num_expansions);
          std::vector< std::string > norm;
          for (size_t j = 0; j < num_expansions; j++)
            norm.push_back(expansions[j]);

          libpostal_expansion_array_destroy(expansions, num_expansions);

          address_expansions.push_back(norm);
          address_keys.push_back(i.first);
        }
    }

  ParseResult r;
  for (size_t i=0; i < address_keys.size(); ++i)
    r[ address_keys[i] ] = address_expansions[i];
  result.push_back(r);
}

void Postal::expand_string(const std::string &input, std::vector<std::string> &expansions)
{
  if (!m_use_postal || !init())
    {
      expansions.push_back(input);
      return;
    }

  size_t num_expansions;
  libpostal_normalize_options_t options_norm = libpostal_get_default_options();

  std::vector<char*> lang;
  for (std::vector<char> &l: m_postal_languages)
    lang.push_back(l.data());

  options_norm.languages = lang.data();
  options_norm.num_languages = lang.size();

  std::vector<char> charbuff;

  charbuff.resize(input.length() + 1);
  std::copy(input.c_str(), input.c_str() + input.length() + 1, charbuff.begin());

  char **expansions_cstr = libpostal_expand_address(charbuff.data(), options_norm, &num_expansions);
  std::vector< std::string > norm;
  for (size_t j = 0; j < num_expansions; j++)
    expansions.push_back(expansions_cstr[j]);

  libpostal_expansion_array_destroy(expansions_cstr, num_expansions);
}

void Postal::result2hierarchy(const std::vector<ParseResult> &p, std::vector<Hierarchy> &h)
{
  h.clear();
  for (const ParseResult &r: p)
    {
      Hierarchy h_result;
#define ADDIFHAS(k) { ParseResult::const_iterator it = r.find(k); if (it != r.end()) h_result.push_back(it->second); }

      ADDIFHAS(ADDRESS_PARSER_LABEL_COUNTRY);
      ADDIFHAS(ADDRESS_PARSER_LABEL_COUNTRY_REGION);
      ADDIFHAS(ADDRESS_PARSER_LABEL_STATE);
      ADDIFHAS(ADDRESS_PARSER_LABEL_STATE_DISTRICT);
      ADDIFHAS(ADDRESS_PARSER_LABEL_ISLAND);
      ADDIFHAS(ADDRESS_PARSER_LABEL_CITY);
      ADDIFHAS(ADDRESS_PARSER_LABEL_CITY_DISTRICT);
      ADDIFHAS(ADDRESS_PARSER_LABEL_SUBURB);
      ADDIFHAS(ADDRESS_PARSER_LABEL_ROAD);
      ADDIFHAS(ADDRESS_PARSER_LABEL_HOUSE_NUMBER);
      ADDIFHAS(ADDRESS_PARSER_LABEL_CATEGORY);
      ADDIFHAS(ADDRESS_PARSER_LABEL_HOUSE);

      // test if its primitive expansion result
      if (h_result.empty())
        {
	  bool done = false;
	  for (size_t i=0; !done; ++i)
            {
	      ParseResult::const_iterator it = r.find(primitive_key(i));
	      if (it == r.end())
		done = true;
	      else
		h_result.push_back(it->second);
            }
        }

      h.push_back(h_result);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Frederik Beaujean <Frederik.Beaujean@lmu.de>

#include "pvalue.h"
#include "partitions.h"

#include <gsl/gsl_cdf.h>

#include <algorithm>
#include <cassert>
#include <cmath>

using namespace std;

namespace
{
static std::vector<double> log_factorial;

unsigned CacheFactorials(unsigned N)
{
  if (N < log_factorial.size())
    // log factorials have already been cached up to N
    return log_factorial.size();

  // reserve memory
  log_factorial.reserve(N);

  // add log(0!) if not there
  if (log_factorial.empty())
    log_factorial.push_back(0);

  // calculate new log factorials
  for (unsigned i = log_factorial.size(); i <= N; ++i)
    log_factorial.push_back(log_factorial.back() + log(static_cast<double>(i)));

  return log_factorial.size();
}

std::vector<double> CacheChi2(double Tobs, unsigned N)
{
    assert(N>0);
  // to ease addressing, pad with zero element that, if used, should spoil any calculation
  std::vector<double> res(N+1);
    res[0] = std::numeric_limits<double>::quiet_NaN();

#if 1
  // C style
#pragma omp parallel for shared(Tobs, N, res)
  for (size_t i = 1; i <= N; ++i)
    res[i] = log(gsl_cdf_chisq_P(Tobs, i));
#else
  // C++ 11 style
  unsigned i = 0;
  std::generate(res.begin()+1, res.end(), [&]{ return log(gsl_cdf_chisq_P(Tobs, ++i)); });
#endif
  return res;
}

} // namespace

double runs_cumulative(const double Tobs, const unsigned N)
{
    CacheFactorials(N);

    // pretabulate chi2 cumulative: given N, we need P(Tobs|i) for i=1...N
    auto log_cumulative = CacheChi2(Tobs, N);

    // work on log scale to avoid overflows of Pochhammer symbol,
    // factorial, and the exponential. Use natural log
    double poch = 0;
    // log(2^N-1): bit shift if N small enough, else neglect -1
    const double logpow2N1 = (N<=63)? log((1ul << N) - 1) : N*log(2);

    // the p value
    double p = 0;

// in tests for N=10 dynamic was better than schedule(static,2). Since
// part(r, M) is really different, each iteration can vary in time
// very much. Hyperthreading seemed to help a lot on my Intel K4770.
#pragma omp parallel for schedule(dynamic) private(poch) shared(log_cumulative, log_factorial) reduction(+:p)
    for (auto r=1ul; r <= N; ++r) {
        // const unsigned long Mmax = (r <= N-r+1)? r : N-r+1;
        const auto Mmax = min(r, N-r+1);
        poch = 0;
        for (auto M=1ul; M <= Mmax; ++M) {
          // compute Pochhammer iteratively
            // (...)_{M+1}/ (...)_M = N-r+1-M but to start the iteration we have to add 1
            poch += log(N-r+2-M);

            // this factor is independent of the actual partition,
            // only depends on M,r,N
            const double scale = poch - logpow2N1;

            // maintain sum over partitions
            double ppi = 0;

            // visit all partitions, save ref to partition
            KPartitionGenerator g(r, M);
            auto& n = g->mult();
            auto& y = g->parts();

            for (; g; ++g) {
                const auto h = g->distinct_parts();

              // perform sum on log scale within a partition
              double ppartition = 0;

                for (size_t l = 1; l <= h; ++l) {
                    ppartition += n[l] * log_cumulative[y[l]] - ::log_factorial[n[l]];
                }
                ppi += exp(ppartition);
            }

            // have to stay on linear scale
            p += exp(scale + log(ppi));
        }
    }
    assert(p < 1);

    return p;
}

double runs_pvalue(const double Tobs, const unsigned N)
{
    return 1 - runs_cumulative(Tobs, N);
}
<commit_msg>[src] use long double for sum over partitions<commit_after>// Copyright 2017 Frederik Beaujean <Frederik.Beaujean@lmu.de>

#include "pvalue.h"
#include "partitions.h"

#include <gsl/gsl_cdf.h>

#include <algorithm>
#include <cassert>
#include <cmath>

using namespace std;

// use ldouble for higher precision when adding lots of numbers
using ldouble = long double;

namespace
{
static std::vector<ldouble> log_factorial;

unsigned CacheFactorials(unsigned N)
{
    if (N < log_factorial.size())
        // log factorials have already been cached up to N
        return log_factorial.size();

    // reserve memory
    log_factorial.reserve(N);

    // add log(0!) if not there
    if (log_factorial.empty())
        log_factorial.push_back(0L);

    // calculate new log factorials
    for (unsigned i = log_factorial.size(); i <= N; ++i)
        log_factorial.push_back(log_factorial.back() + log(ldouble(i)));

    return log_factorial.size();
}

std::vector<ldouble> CacheChi2(double Tobs, unsigned N)
{
    assert(N>0);
    // to ease addressing, pad with zero element that, if used, should spoil any calculation
    std::vector<ldouble> res(N+1);
    res[0] = std::numeric_limits<ldouble>::quiet_NaN();

    // C style
#pragma omp parallel for shared(Tobs, N, res)
    for (size_t i = 1; i <= N; ++i)
        res[i] = log(ldouble(gsl_cdf_chisq_P(Tobs, i)));
    return res;
}

} // namespace

double runs_cumulative(const double Tobs, const unsigned N)
{
    CacheFactorials(N);

    // pretabulate chi2 cumulative: given N, we need P(Tobs|i) for i=1...N
    auto log_cumulative = CacheChi2(Tobs, N);

    // work on log scale to avoid overflows of Pochhammer symbol,
    // factorial, and the exponential. Use natural log
    ldouble poch = 0;
    // log(2^N-1): bit shift if N small enough, else neglect -1
    const ldouble logpow2N1 = (N<=63)? log((1ul << N) - 1) : N*log(2);

    // the p value
    ldouble p = 0;

// in tests for N=10 dynamic was better than schedule(static,2). Since
// part(r, M) is really different, each iteration can vary in time
// very much. Hyperthreading seemed to help a lot on my Intel K4770.
#pragma omp parallel for schedule(dynamic) private(poch) shared(log_cumulative, log_factorial) reduction(+:p)
    for (auto r=1ul; r <= N; ++r) {
        // const unsigned long Mmax = (r <= N-r+1)? r : N-r+1;
        const auto Mmax = min(r, N-r+1);
        poch = 0;
        for (auto M=1ul; M <= Mmax; ++M) {
          // compute Pochhammer iteratively
            // (...)_{M+1}/ (...)_M = N-r+1-M but to start the iteration we have to add 1
            poch += log(ldouble(N-r+2-M));

            // this factor is independent of the actual partition,
            // only depends on M,r,N
            const ldouble scale = poch - logpow2N1;

            // maintain sum over partitions
            ldouble ppi = 0;

            // visit all partitions, save ref to partition
            KPartitionGenerator g(r, M);
            auto& n = g->mult();
            auto& y = g->parts();

            for (; g; ++g) {
                const auto h = g->distinct_parts();

                // perform sum on log scale within a partition
                ldouble ppartition = 0;

                for (size_t l = 1; l <= h; ++l) {
                    ppartition += n[l] * log_cumulative[y[l]] - ::log_factorial[n[l]];
                }
                ppi += exp(ppartition);
            }

            // have to stay on linear scale
            p += exp(scale + log(ppi));
        }
    }
    assert(p < 1);

    return p;
}

double runs_pvalue(const double Tobs, const unsigned N)
{
    return 1 - runs_cumulative(Tobs, N);
}
<|endoftext|>