<commit_before>/*****************************************************************************
 * open.cpp : Panels for the open dialogs
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * 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.
 *****************************************************************************/

#include "qt4.hpp"
#include "components/open.hpp"
#include "dialogs/open.hpp"
#include "dialogs_provider.hpp"
#include "util/customwidgets.hpp"

#include <QFileDialog>
#include <QDialogButtonBox>
#include <QLineEdit>

/**************************************************************************
 * File open
 **************************************************************************/
FileOpenPanel::FileOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    /* Classic UI Setup */
    ui.setupUi( this );

    /* Use a QFileDialog and customize it because we don't want to
       rewrite it all. Be careful to your eyes cause there are a few hacks.
       Be very careful and test correctly when you modify this. */

    /* Set Filters for file selection */
    QString fileTypes = "";
    ADD_FILTER_MEDIA( fileTypes );
    ADD_FILTER_VIDEO( fileTypes );
    ADD_FILTER_AUDIO( fileTypes );
    ADD_FILTER_PLAYLIST( fileTypes );
    ADD_FILTER_ALL( fileTypes );
    fileTypes.replace(QString(";*"), QString(" *"));

    // Make this QFileDialog a child of tempWidget from the ui.
    dialogBox = new FileOpenBox( ui.tempWidget, NULL,
            qfu( p_intf->p_libvlc->psz_homedir ), fileTypes );
    dialogBox->setFileMode( QFileDialog::ExistingFiles );
    /* We don't want to see a grip in the middle of the window, do we? */
    dialogBox->setSizeGripEnabled( false );
    dialogBox->setToolTip( qtr( "Select one or multiple files, or a folder" ));

    // Add it to the layout
    ui.gridLayout->addWidget( dialogBox, 0, 0, 1, 3 );

    // But hide the two OK/Cancel buttons. Enable them for debug.
#ifndef WIN32
    findChild<QDialogButtonBox*>()->hide();
#endif

    /* Ugly hacks to get the good Widget */
    //This lineEdit is the normal line in the fileDialog.
    lineFileEdit = findChildren<QLineEdit*>()[3];
    lineFileEdit->hide();

    /* Make a list of QLabel inside the QFileDialog to access the good ones */
    QList<QLabel *> listLabel = findChildren<QLabel*>();

    /* Hide the FileNames one. Enable it for debug */
    listLabel[4]->hide();
    /* Change the text that was uncool in the usual box */
    listLabel[5]->setText( qtr( "Filter:" ) );

    // Hide the subtitles control by default.
    ui.subFrame->hide();

    /* Build the subs size combo box */
    module_config_t *p_item =
        config_FindConfig( VLC_OBJECT(p_intf), "freetype-rel-fontsize" );
    if( p_item )
    {
        for( int i_index = 0; i_index < p_item->i_list; i_index++ )
        {
            ui.sizeSubComboBox->addItem(
                qfu( p_item->ppsz_list_text[i_index] ),
                QVariant( p_item->pi_list[i_index] ) );
            if( p_item->value.i == p_item->pi_list[i_index] )
            {
                ui.sizeSubComboBox->setCurrentIndex( i_index );
            }
        }
    }

    /* Build the subs align combo box */
    p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-align" );
    if( p_item )
    {
        for( int i_index = 0; i_index < p_item->i_list; i_index++ )
        {
            ui.alignSubComboBox->addItem(
                qfu( p_item->ppsz_list_text[i_index] ),
                QVariant( p_item->pi_list[i_index] ) );
            if( p_item->value.i == p_item->pi_list[i_index] )
            {
                ui.alignSubComboBox->setCurrentIndex( i_index );
            }
        }
    }

    BUTTONACT( ui.subBrowseButton, browseFileSub() );
    BUTTONACT( ui.subCheckBox, toggleSubtitleFrame());

    CONNECT( ui.fileInput, editTextChanged(QString ), this, updateMRL());
    CONNECT( ui.subInput, editTextChanged(QString ), this, updateMRL());
    CONNECT( ui.alignSubComboBox, currentIndexChanged(int), this, updateMRL());
    CONNECT( ui.sizeSubComboBox, currentIndexChanged(int), this, updateMRL());
    CONNECT( lineFileEdit, textChanged( QString ), this, browseFile());
}

FileOpenPanel::~FileOpenPanel()
{}

QStringList FileOpenPanel::browse(QString help)
{
    return THEDP->showSimpleOpen( help );
}

void FileOpenPanel::browseFile()
{
    QString fileString = "";
    foreach( QString file, dialogBox->selectedFiles() ) {
         fileString += "\"" + file + "\" ";
    }
    ui.fileInput->setEditText( fileString );
    updateMRL();
}

void FileOpenPanel::browseFileSub()
{
    // FIXME Handle selection of more than one subtitles file
    QStringList files = THEDP->showSimpleOpen( qtr("Open subtitles file"),
                            EXT_FILTER_SUBTITLE,
                            dialogBox->directory().absolutePath() );
    if( files.isEmpty() ) return;
    ui.subInput->setEditText( files.join(" ") );
    updateMRL();
}

void FileOpenPanel::updateMRL()
{
    QString mrl = ui.fileInput->currentText();

    if( ui.subCheckBox->isChecked() ) {
        mrl.append( " :sub-file=" + ui.subInput->currentText() );
        int align = ui.alignSubComboBox->itemData( ui.alignSubComboBox->currentIndex() ).toInt();
        mrl.append( " :subsdec-align=" + QString().setNum( align ) );
        int size = ui.sizeSubComboBox->itemData( ui.sizeSubComboBox->currentIndex() ).toInt();
        mrl.append( " :freetype-rel-fontsize=" + QString().setNum( size ) );
    }
    emit mrlUpdated( mrl );
    emit methodChanged( "file-caching" );
}

/* Function called by Open Dialog when clicke on Play/Enqueue */
void FileOpenPanel::accept()
{
    ui.fileInput->addItem(ui.fileInput->currentText());
    if ( ui.fileInput->count() > 8 ) ui.fileInput->removeItem(0);
}

void FileOpenBox::accept()
{
    OpenDialog::getInstance( NULL, NULL )->play();
}

/* Function called by Open Dialog when clicked on cancel */
void FileOpenPanel::clear()
{
    ui.fileInput->setEditText( "" );
    ui.subInput->setEditText( "" );
}

void FileOpenPanel::toggleSubtitleFrame()
{
    if (ui.subFrame->isVisible())
    {
        ui.subFrame->hide();
//        setMinimumHeight(1);
        resize( sizeHint());
    }
    else
    {
        ui.subFrame->show();
    }

    /* Update the MRL */
    updateMRL();
}

/**************************************************************************
 * Disk open
 **************************************************************************/
DiskOpenPanel::DiskOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    ui.setupUi( this );

    CONNECT( ui.deviceCombo, editTextChanged(QString ), this, updateMRL());
    BUTTONACT( ui.dvdRadioButton, updateMRL());
    BUTTONACT( ui.vcdRadioButton, updateMRL());
    BUTTONACT( ui.audioCDRadioButton, updateMRL());

    CONNECT( ui.titleSpin, valueChanged(int), this, updateMRL());
    CONNECT( ui.chapterSpin, valueChanged(int), this, updateMRL());
}

DiskOpenPanel::~DiskOpenPanel()
{}

void DiskOpenPanel::clear()
{
    ui.titleSpin->setValue(0);
    ui.chapterSpin->setValue(0);
}

void DiskOpenPanel::updateMRL()
{
    QString mrl = "";
    /* DVD */
    if( ui.dvdRadioButton->isChecked() ) {
        mrl = "dvd://" + ui.deviceCombo->currentText();
        emit methodChanged( "dvdnav-caching" );

        if ( ui.titleSpin->value() > 0 ) {
            mrl += QString("@%1").arg(ui.titleSpin->value());
            if ( ui.chapterSpin->value() > 0 ) {
                mrl+= QString(":%1").arg(ui.chapterSpin->value());
            }
        }

    /* VCD */
    } else if (ui.vcdRadioButton->isChecked() ) {
        mrl = "vcd://" + ui.deviceCombo->currentText();
        emit methodChanged( "vcd-caching" );

        if( ui.titleSpin->value() > 0 ) {
            mrl += QString("@%1").arg(ui.titleSpin->value());
        }

    /* CDDA */
    } else {
        mrl = "cdda://" + ui.deviceCombo->currentText();
    }

    emit mrlUpdated(mrl);
}

/**************************************************************************
 * Net open
 **************************************************************************/
NetOpenPanel::NetOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    ui.setupUi( this );

    CONNECT( ui.protocolCombo, currentIndexChanged(int),
             this, updateProtocol(int) );
    CONNECT( ui.portSpin, valueChanged(int), this, updateMRL());
    CONNECT( ui.addressText, textChanged(QString), this, updateAddress());
    CONNECT( ui.timeShift, clicked(), this, updateMRL());
    CONNECT( ui.ipv6, clicked(), this, updateMRL());

    ui.protocolCombo->addItem("HTTP", QVariant("http"));
    ui.protocolCombo->addItem("FTP", QVariant("ftp"));
    ui.protocolCombo->addItem("MMS", QVariant("mms"));
    ui.protocolCombo->addItem("RTSP", QVariant("rtsp"));
    ui.protocolCombo->addItem("UDP/RTP (unicast)", QVariant("udp"));
    ui.protocolCombo->addItem("UDP/RTP (multicast)", QVariant("udp"));
}

NetOpenPanel::~NetOpenPanel()
{}

void NetOpenPanel::clear()
{}

void NetOpenPanel::updateProtocol(int idx) {
    QString addr = ui.addressText->text();
    QString proto = ui.protocolCombo->itemData(idx).toString();

    ui.timeShift->setEnabled( idx >= 4);
    ui.ipv6->setEnabled( idx == 4 );
    ui.addressText->setEnabled( idx != 4 );
    ui.portSpin->setEnabled( idx >= 4 );

    /* If we already have a protocol in the address, replace it */
    if( addr.contains( "://")) {
        msg_Err( p_intf, "replace");
        addr.replace(QRegExp("^.*://"), proto + "://");
        ui.addressText->setText(addr);
    }

    updateMRL();
}

void NetOpenPanel::updateAddress() {
    updateMRL();
}

void NetOpenPanel::updateMRL() {
    QString mrl = "";
    QString addr = ui.addressText->text();
    int proto = ui.protocolCombo->currentIndex();

    if( addr.contains( "://") && proto != 4 ) {
        mrl = addr;
    } else {
        switch(proto) {
        case 0:
            mrl = "http://" + addr;
            emit methodChanged("http-caching");
            break;
        case 2:
            mrl = "mms://" + addr;
            emit methodChanged("mms-caching");
            break;
        case 1:
            mrl = "ftp://" + addr;
            emit methodChanged("ftp-caching");
            break;
        case 3: /* RTSP */
            mrl = "rtsp://" + addr;
            emit methodChanged("rtsp-caching");
            break;
        case 4:
            mrl = "udp://@";
            if( ui.ipv6->isEnabled() && ui.ipv6->isChecked() ) {
                mrl += "[::]";
            }
            mrl += QString(":%1").arg(ui.portSpin->value());
            emit methodChanged("udp-caching");
            break;
        case 5: /* UDP multicast */
            mrl = "udp://@";
            /* Add [] to IPv6 */
            if ( addr.contains(':') && !addr.contains('[') ) {
                mrl += "[" + addr + "]";
            } else mrl += addr;
            mrl += QString(":%1").arg(ui.portSpin->value());
            emit methodChanged("udp-caching");
        }
    }
    if( ui.timeShift->isEnabled() && ui.timeShift->isChecked() ) {
        mrl += " :access-filter=timeshift";
    }
    emit mrlUpdated(mrl);
}

/**************************************************************************
 * Capture open
 **************************************************************************/
CaptureOpenPanel::CaptureOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    ui.setupUi( this );
}

CaptureOpenPanel::~CaptureOpenPanel()
{}

void CaptureOpenPanel::clear()
{}

void CaptureOpenPanel::updateMRL()
{
    QString mrl = "";
    emit mrlUpdated(mrl);
}
<commit_msg>qt4 - small and unimportant cosmetic change.<commit_after>/*****************************************************************************
 * open.cpp : Panels for the open dialogs
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * 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.
 *****************************************************************************/

#include "qt4.hpp"
#include "components/open.hpp"
#include "dialogs/open.hpp"
#include "dialogs_provider.hpp"
#include "util/customwidgets.hpp"

#include <QFileDialog>
#include <QDialogButtonBox>
#include <QLineEdit>

/**************************************************************************
 * File open
 **************************************************************************/
FileOpenPanel::FileOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    /* Classic UI Setup */
    ui.setupUi( this );

    /* Use a QFileDialog and customize it because we don't want to
       rewrite it all. Be careful to your eyes cause there are a few hacks.
       Be very careful and test correctly when you modify this. */

    /* Set Filters for file selection */
    QString fileTypes = "";
    ADD_FILTER_MEDIA( fileTypes );
    ADD_FILTER_VIDEO( fileTypes );
    ADD_FILTER_AUDIO( fileTypes );
    ADD_FILTER_PLAYLIST( fileTypes );
    ADD_FILTER_ALL( fileTypes );
    fileTypes.replace(QString(";*"), QString(" *"));

    // Make this QFileDialog a child of tempWidget from the ui.
    dialogBox = new FileOpenBox( ui.tempWidget, NULL,
            qfu( p_intf->p_libvlc->psz_homedir ), fileTypes );
    dialogBox->setFileMode( QFileDialog::ExistingFiles );
    dialogBox->setAcceptMode( QFileDialog::AcceptOpen );

    /* We don't want to see a grip in the middle of the window, do we? */
    dialogBox->setSizeGripEnabled( false );
    dialogBox->setToolTip( qtr( "Select one or multiple files, or a folder" ));

    // Add it to the layout
    ui.gridLayout->addWidget( dialogBox, 0, 0, 1, 3 );

    // But hide the two OK/Cancel buttons. Enable them for debug.
#ifndef WIN32
    findChild<QDialogButtonBox*>()->hide();
#endif

    /* Ugly hacks to get the good Widget */
    //This lineEdit is the normal line in the fileDialog.
    lineFileEdit = findChildren<QLineEdit*>()[3];
    lineFileEdit->hide();

    /* Make a list of QLabel inside the QFileDialog to access the good ones */
    QList<QLabel *> listLabel = findChildren<QLabel*>();

    /* Hide the FileNames one. Enable it for debug */
    listLabel[4]->hide();
    /* Change the text that was uncool in the usual box */
    listLabel[5]->setText( qtr( "Filter:" ) );

    // Hide the subtitles control by default.
    ui.subFrame->hide();

    /* Build the subs size combo box */
    module_config_t *p_item =
        config_FindConfig( VLC_OBJECT(p_intf), "freetype-rel-fontsize" );
    if( p_item )
    {
        for( int i_index = 0; i_index < p_item->i_list; i_index++ )
        {
            ui.sizeSubComboBox->addItem(
                qfu( p_item->ppsz_list_text[i_index] ),
                QVariant( p_item->pi_list[i_index] ) );
            if( p_item->value.i == p_item->pi_list[i_index] )
            {
                ui.sizeSubComboBox->setCurrentIndex( i_index );
            }
        }
    }

    /* Build the subs align combo box */
    p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-align" );
    if( p_item )
    {
        for( int i_index = 0; i_index < p_item->i_list; i_index++ )
        {
            ui.alignSubComboBox->addItem(
                qfu( p_item->ppsz_list_text[i_index] ),
                QVariant( p_item->pi_list[i_index] ) );
            if( p_item->value.i == p_item->pi_list[i_index] )
            {
                ui.alignSubComboBox->setCurrentIndex( i_index );
            }
        }
    }

    BUTTONACT( ui.subBrowseButton, browseFileSub() );
    BUTTONACT( ui.subCheckBox, toggleSubtitleFrame());

    CONNECT( ui.fileInput, editTextChanged(QString ), this, updateMRL());
    CONNECT( ui.subInput, editTextChanged(QString ), this, updateMRL());
    CONNECT( ui.alignSubComboBox, currentIndexChanged(int), this, updateMRL());
    CONNECT( ui.sizeSubComboBox, currentIndexChanged(int), this, updateMRL());
    CONNECT( lineFileEdit, textChanged( QString ), this, browseFile());
}

FileOpenPanel::~FileOpenPanel()
{}

QStringList FileOpenPanel::browse(QString help)
{
    return THEDP->showSimpleOpen( help );
}

void FileOpenPanel::browseFile()
{
    QString fileString = "";
    foreach( QString file, dialogBox->selectedFiles() ) {
         fileString += "\"" + file + "\" ";
    }
    ui.fileInput->setEditText( fileString );
    updateMRL();
}

void FileOpenPanel::browseFileSub()
{
    // FIXME Handle selection of more than one subtitles file
    QStringList files = THEDP->showSimpleOpen( qtr("Open subtitles file"),
                            EXT_FILTER_SUBTITLE,
                            dialogBox->directory().absolutePath() );
    if( files.isEmpty() ) return;
    ui.subInput->setEditText( files.join(" ") );
    updateMRL();
}

void FileOpenPanel::updateMRL()
{
    QString mrl = ui.fileInput->currentText();

    if( ui.subCheckBox->isChecked() ) {
        mrl.append( " :sub-file=" + ui.subInput->currentText() );
        int align = ui.alignSubComboBox->itemData( ui.alignSubComboBox->currentIndex() ).toInt();
        mrl.append( " :subsdec-align=" + QString().setNum( align ) );
        int size = ui.sizeSubComboBox->itemData( ui.sizeSubComboBox->currentIndex() ).toInt();
        mrl.append( " :freetype-rel-fontsize=" + QString().setNum( size ) );
    }
    emit mrlUpdated( mrl );
    emit methodChanged( "file-caching" );
}

/* Function called by Open Dialog when clicke on Play/Enqueue */
void FileOpenPanel::accept()
{
    ui.fileInput->addItem(ui.fileInput->currentText());
    if ( ui.fileInput->count() > 8 ) ui.fileInput->removeItem(0);
}

void FileOpenBox::accept()
{
    OpenDialog::getInstance( NULL, NULL )->play();
}

/* Function called by Open Dialog when clicked on cancel */
void FileOpenPanel::clear()
{
    ui.fileInput->setEditText( "" );
    ui.subInput->setEditText( "" );
}

void FileOpenPanel::toggleSubtitleFrame()
{
    if (ui.subFrame->isVisible())
    {
        ui.subFrame->hide();
//        setMinimumHeight(1);
        resize( sizeHint());
    }
    else
    {
        ui.subFrame->show();
    }

    /* Update the MRL */
    updateMRL();
}

/**************************************************************************
 * Disk open
 **************************************************************************/
DiskOpenPanel::DiskOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    ui.setupUi( this );

    CONNECT( ui.deviceCombo, editTextChanged(QString ), this, updateMRL());
    BUTTONACT( ui.dvdRadioButton, updateMRL());
    BUTTONACT( ui.vcdRadioButton, updateMRL());
    BUTTONACT( ui.audioCDRadioButton, updateMRL());

    CONNECT( ui.titleSpin, valueChanged(int), this, updateMRL());
    CONNECT( ui.chapterSpin, valueChanged(int), this, updateMRL());
}

DiskOpenPanel::~DiskOpenPanel()
{}

void DiskOpenPanel::clear()
{
    ui.titleSpin->setValue(0);
    ui.chapterSpin->setValue(0);
}

void DiskOpenPanel::updateMRL()
{
    QString mrl = "";
    /* DVD */
    if( ui.dvdRadioButton->isChecked() ) {
        mrl = "dvd://" + ui.deviceCombo->currentText();
        emit methodChanged( "dvdnav-caching" );

        if ( ui.titleSpin->value() > 0 ) {
            mrl += QString("@%1").arg(ui.titleSpin->value());
            if ( ui.chapterSpin->value() > 0 ) {
                mrl+= QString(":%1").arg(ui.chapterSpin->value());
            }
        }

    /* VCD */
    } else if (ui.vcdRadioButton->isChecked() ) {
        mrl = "vcd://" + ui.deviceCombo->currentText();
        emit methodChanged( "vcd-caching" );

        if( ui.titleSpin->value() > 0 ) {
            mrl += QString("@%1").arg(ui.titleSpin->value());
        }

    /* CDDA */
    } else {
        mrl = "cdda://" + ui.deviceCombo->currentText();
    }

    emit mrlUpdated(mrl);
}

/**************************************************************************
 * Net open
 **************************************************************************/
NetOpenPanel::NetOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    ui.setupUi( this );

    CONNECT( ui.protocolCombo, currentIndexChanged(int),
             this, updateProtocol(int) );
    CONNECT( ui.portSpin, valueChanged(int), this, updateMRL());
    CONNECT( ui.addressText, textChanged(QString), this, updateAddress());
    CONNECT( ui.timeShift, clicked(), this, updateMRL());
    CONNECT( ui.ipv6, clicked(), this, updateMRL());

    ui.protocolCombo->addItem("HTTP", QVariant("http"));
    ui.protocolCombo->addItem("FTP", QVariant("ftp"));
    ui.protocolCombo->addItem("MMS", QVariant("mms"));
    ui.protocolCombo->addItem("RTSP", QVariant("rtsp"));
    ui.protocolCombo->addItem("UDP/RTP (unicast)", QVariant("udp"));
    ui.protocolCombo->addItem("UDP/RTP (multicast)", QVariant("udp"));
}

NetOpenPanel::~NetOpenPanel()
{}

void NetOpenPanel::clear()
{}

void NetOpenPanel::updateProtocol(int idx) {
    QString addr = ui.addressText->text();
    QString proto = ui.protocolCombo->itemData(idx).toString();

    ui.timeShift->setEnabled( idx >= 4);
    ui.ipv6->setEnabled( idx == 4 );
    ui.addressText->setEnabled( idx != 4 );
    ui.portSpin->setEnabled( idx >= 4 );

    /* If we already have a protocol in the address, replace it */
    if( addr.contains( "://")) {
        msg_Err( p_intf, "replace");
        addr.replace(QRegExp("^.*://"), proto + "://");
        ui.addressText->setText(addr);
    }

    updateMRL();
}

void NetOpenPanel::updateAddress() {
    updateMRL();
}

void NetOpenPanel::updateMRL() {
    QString mrl = "";
    QString addr = ui.addressText->text();
    int proto = ui.protocolCombo->currentIndex();

    if( addr.contains( "://") && proto != 4 ) {
        mrl = addr;
    } else {
        switch(proto) {
        case 0:
            mrl = "http://" + addr;
            emit methodChanged("http-caching");
            break;
        case 2:
            mrl = "mms://" + addr;
            emit methodChanged("mms-caching");
            break;
        case 1:
            mrl = "ftp://" + addr;
            emit methodChanged("ftp-caching");
            break;
        case 3: /* RTSP */
            mrl = "rtsp://" + addr;
            emit methodChanged("rtsp-caching");
            break;
        case 4:
            mrl = "udp://@";
            if( ui.ipv6->isEnabled() && ui.ipv6->isChecked() ) {
                mrl += "[::]";
            }
            mrl += QString(":%1").arg(ui.portSpin->value());
            emit methodChanged("udp-caching");
            break;
        case 5: /* UDP multicast */
            mrl = "udp://@";
            /* Add [] to IPv6 */
            if ( addr.contains(':') && !addr.contains('[') ) {
                mrl += "[" + addr + "]";
            } else mrl += addr;
            mrl += QString(":%1").arg(ui.portSpin->value());
            emit methodChanged("udp-caching");
        }
    }
    if( ui.timeShift->isEnabled() && ui.timeShift->isChecked() ) {
        mrl += " :access-filter=timeshift";
    }
    emit mrlUpdated(mrl);
}

/**************************************************************************
 * Capture open
 **************************************************************************/
CaptureOpenPanel::CaptureOpenPanel( QWidget *_parent, intf_thread_t *_p_intf ) :
                                OpenPanel( _parent, _p_intf )
{
    ui.setupUi( this );
}

CaptureOpenPanel::~CaptureOpenPanel()
{}

void CaptureOpenPanel::clear()
{}

void CaptureOpenPanel::updateMRL()
{
    QString mrl = "";
    emit mrlUpdated(mrl);
}
<|endoftext|>


<commit_before>/*
 * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 */
#include "punctuation.h"
#include "notifications_public.h"
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <fcitx-config/iniparser.h>
#include <fcitx-utils/charutils.h>
#include <fcitx-utils/log.h>
#include <fcitx-utils/standardpath.h>
#include <fcitx-utils/utf8.h>
#include <fcitx/inputcontext.h>
#include <fcitx/inputcontextmanager.h>
#include <fcitx/inputmethodentry.h>
#include <fcitx/inputmethodmanager.h>
#include <fcitx/statusarea.h>
#include <fcitx/userinterfacemanager.h>
#include <fcntl.h>
#include <string_view>
#include <unordered_set>

using namespace fcitx;

namespace {
static const std::string emptyString;
static const std::pair<std::string, std::string> emptyStringPair;
} // namespace

bool dontConvertWhenEn(uint32_t c) { return c == '.' || c == ','; }

class PunctuationState : public InputContextProperty {
public:
    std::unordered_map<uint32_t, std::string> lastPuncStack_;
    char lastIsEngOrDigit_ = 0;
    uint32_t notConverted_ = 0;
    bool mayRebuildStateFromSurroundingText_ = false;

    std::unordered_map<uint32_t, std::string> lastPuncStackBackup_;
    uint32_t notConvertedBackup_ = 0;
};

PunctuationProfile::PunctuationProfile(std::istream &in) {
    std::string strBuf;
    while (std::getline(in, strBuf)) {
        auto pair = stringutils::trimInplace(strBuf);
        std::string::size_type start = pair.first, end = pair.second;
        if (start == end) {
            continue;
        }
        std::string text(strBuf.begin() + start, strBuf.begin() + end);
        auto tokens = stringutils::split(strBuf, FCITX_WHITESPACE);
        if (tokens.size() != 2 && tokens.size() != 3) {
            continue;
        }

        if (!std::any_of(
                tokens.begin(), tokens.end(),
                [](const std::string &s) { return utf8::validate(s); })) {
            continue;
        }
        // we don't make # as comment here, # would be consider as a valid char
        if (utf8::lengthValidated(tokens[0]) != 1) {
            continue;
        }
        auto c = utf8::getChar(tokens[0]);
        decltype(puncMap_)::mapped_type p;
        p.first = tokens[1];
        if (tokens.size() > 2) {
            p.second = tokens[2];
        }
        puncMap_.emplace(c, std::move(p));
    }
}

const std::pair<std::string, std::string> &
PunctuationProfile::getPunctuation(uint32_t unicode) const {
    auto iter = puncMap_.find(unicode);
    if (iter == puncMap_.end()) {
        return emptyStringPair;
    }
    return iter->second;
}

Punctuation::Punctuation(Instance *instance)
    : instance_(instance),
      factory_([](InputContext &) { return new PunctuationState; }) {
    reloadConfig();
    if (!instance_) {
        return;
    }
    instance_->inputContextManager().registerProperty("punctuationState",
                                                      &factory_);
    instance_->userInterfaceManager().registerAction("punctuation",
                                                     &toggleAction_);

    commitConn_ = instance_->connect<Instance::CommitFilter>(
        [this](InputContext *ic, const std::string &sentence) {
            auto state = ic->propertyFor(&factory_);
            // Though sentence is utf8, we only check ascii.
            if (sentence.size() && (charutils::isupper(sentence.back()) ||
                                    charutils::islower(sentence.back()) ||
                                    charutils::isdigit(sentence.back()))) {
                state->lastIsEngOrDigit_ = sentence.back();
            } else {
                state->lastIsEngOrDigit_ = '\0';
            }
        });
    keyEventConn_ = instance_->connect<Instance::KeyEventResult>(
        [this](const KeyEvent &event) {
            auto state = event.inputContext()->propertyFor(&factory_);
            if (event.isRelease()) {
                return;
            }
            if (!event.accepted()) {
                if (event.key().isUAZ() || event.key().isLAZ() ||
                    event.key().isDigit()) {
                    state->lastIsEngOrDigit_ =
                        Key::keySymToUnicode(event.key().sym());
                } else {
                    state->lastIsEngOrDigit_ = '\0';
                }
            }
        });
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextKeyEvent, EventWatcherPhase::PostInputMethod,
        [this](Event &event) {
            auto &keyEvent = static_cast<KeyEvent &>(event);
            if (keyEvent.isRelease()) {
                return;
            }
            if (inWhiteList(keyEvent.inputContext()) &&
                keyEvent.key().checkKeyList(config_.hotkey.value())) {
                setEnabled(!enabled(), keyEvent.inputContext());
                if (notifications()) {
                    notifications()->call<INotifications::showTip>(
                        "fcitx-punc-toggle", "fcitx",
                        enabled() ? "fcitx-punc-active" : "fcitx-punc-inactive",
                        _("Punctuation"),
                        enabled() ? _("Full width punctuation is enabled.")
                                  : _("Full width punctuation is disabled."),
                        -1);
                }
                return keyEvent.filterAndAccept();
            }
        }));
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextFocusIn, EventWatcherPhase::PostInputMethod,
        [this](Event &event) {
            auto &icEvent = static_cast<InputContextEvent &>(event);
            auto ic = icEvent.inputContext();
            auto state = ic->propertyFor(&factory_);
            if (ic->capabilityFlags().test(CapabilityFlag::SurroundingText)) {
                state->mayRebuildStateFromSurroundingText_ = true;
            }
        }));
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextReset, EventWatcherPhase::PostInputMethod,
        [this](Event &event) {
            auto &icEvent = static_cast<InputContextEvent &>(event);
            auto ic = icEvent.inputContext();
            auto state = ic->propertyFor(&factory_);
            state->lastIsEngOrDigit_ = 0;
            // Backup the state.
            state->notConvertedBackup_ = state->notConverted_;
            state->notConverted_ = 0;
            // Backup the state.
            state->lastPuncStackBackup_ = state->lastPuncStack_;
            state->lastPuncStack_.clear();
            if (ic->capabilityFlags().test(CapabilityFlag::SurroundingText)) {
                state->mayRebuildStateFromSurroundingText_ = true;
            }
        }));
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextSurroundingTextUpdated,
        EventWatcherPhase::PostInputMethod, [this](Event &event) {
            auto &icEvent = static_cast<InputContextEvent &>(event);
            auto ic = icEvent.inputContext();
            auto state = ic->propertyFor(&factory_);
            // Enable to rebuild punctuation state from surrounding text.
            if (state->mayRebuildStateFromSurroundingText_) {
                state->mayRebuildStateFromSurroundingText_ = false;
            } else {
                state->notConvertedBackup_ = 0;
                state->lastPuncStackBackup_.clear();
                return;
            }
            if (!ic->capabilityFlags().test(CapabilityFlag::SurroundingText) ||
                !ic->surroundingText().isValid()) {
                return;
            }
            // We need text before the cursor.
            auto &text = ic->surroundingText().text();
            auto cursor = ic->surroundingText().cursor();
            auto length = utf8::lengthValidated(text);
            if (length == utf8::INVALID_LENGTH) {
                return;
            }
            if (cursor <= 0 && cursor > length) {
                return;
            }
            uint32_t lastCharBeforeCursor;
            auto start = utf8::nextNChar(text.begin(), cursor - 1);
            auto end =
                utf8::getNextChar(start, text.end(), &lastCharBeforeCursor);
            if (lastCharBeforeCursor == utf8::INVALID_CHAR ||
                lastCharBeforeCursor == utf8::NOT_ENOUGH_SPACE) {
                return;
            }
            // Need to make sure we have ascii.
            if (std::distance(start, end) == 1 &&
                (charutils::isupper(lastCharBeforeCursor) ||
                 charutils::islower(lastCharBeforeCursor) ||
                 charutils::isdigit(lastCharBeforeCursor))) {
                state->lastIsEngOrDigit_ = lastCharBeforeCursor;
            }
            // Restore the not converted state if we still after the same chr.
            if (lastCharBeforeCursor == state->notConvertedBackup_ &&
                state->notConverted_ == 0) {
                state->notConverted_ = state->notConvertedBackup_;
            }
            state->notConvertedBackup_ = 0;
            // Scan through the surrounding text
            if (!state->lastPuncStackBackup_.empty() &&
                state->lastPuncStack_.empty()) {
                auto range =
                    utf8::MakeUTF8CharRange(MakeIterRange(text.begin(), end));
                for (auto iter = std::begin(range); iter != std::end(range);
                     iter++) {
                    auto charRange = iter.charRange();
                    std::string_view chr(
                        &*charRange.first,
                        std::distance(charRange.first, charRange.second));
                    auto puncIter = std::find_if(
                        state->lastPuncStackBackup_.begin(),
                        state->lastPuncStackBackup_.end(),
                        [chr](auto &p) { return p.second == chr; });
                    if (puncIter != state->lastPuncStackBackup_.end()) {
                        state->lastPuncStack_.insert(*puncIter);
                    }
                }
            }
            state->lastPuncStackBackup_.clear();
        }));
}

Punctuation::~Punctuation() {}

void Punctuation::reloadConfig() {
    readAsIni(config_, "conf/punctuation.conf");

    auto files = StandardPath::global().multiOpen(StandardPath::Type::PkgData,
                                                  "punctuation", O_RDONLY,
                                                  filter::Prefix("punc.mb."));
    auto iter = profiles_.begin();
    while (iter != profiles_.end()) {
        if (!files.count("punc.mb." + iter->first)) {
            iter = profiles_.erase(iter);
        } else {
            iter++;
        }
    }

    for (const auto &file : files) {
        if (file.first.size() <= 8) {
            continue;
        }
        auto lang = file.first.substr(8);

        try {
            boost::iostreams::stream_buffer<
                boost::iostreams::file_descriptor_source>
                buffer(file.second.fd(),
                       boost::iostreams::file_descriptor_flags::
                           never_close_handle);
            std::istream in(&buffer);
            PunctuationProfile newProfile(in);
            profiles_[lang] = std::move(newProfile);
        } catch (const std::exception &e) {
            FCITX_LOG(Warn)
                << "Error when load profile " << file.first << ": " << e.what();
        }
    }
}

bool Punctuation::inWhiteList(fcitx::InputContext *inputContext) const {
    return toggleAction_.isParent(&inputContext->statusArea());
}

const std::string &Punctuation::pushPunctuation(const std::string &language,
                                                InputContext *ic,
                                                uint32_t unicode) {
    if (!enabled()) {
        return emptyString;
    }
    auto state = ic->propertyFor(&factory_);
    if (state->lastIsEngOrDigit_ && dontConvertWhenEn(unicode)) {
        state->notConverted_ = unicode;
        return emptyString;
    } else {
        auto iter = profiles_.find(language);
        if (iter == profiles_.end()) {
            return emptyString;
        }
        auto &result = getPunctuation(language, unicode);
        state->notConverted_ = 0;
        if (result.second.empty()) {
            return result.first;
        } else {
            auto iter = state->lastPuncStack_.find(unicode);
            if (iter != state->lastPuncStack_.end()) {
                state->lastPuncStack_.erase(iter);
                return result.second;
            } else {
                state->lastPuncStack_.emplace(unicode, result.first);
                return result.first;
            }
        }
    }
}

const std::string &Punctuation::cancelLast(const std::string &language,
                                           InputContext *ic) {
    if (!enabled()) {
        return emptyString;
    }
    auto state = ic->propertyFor(&factory_);
    if (dontConvertWhenEn(state->notConverted_)) {
        auto &result = getPunctuation(language, state->notConverted_);
        state->notConverted_ = 0;
        return result.first;
    }
    return emptyString;
}

const std::pair<std::string, std::string> &
Punctuation::getPunctuation(const std::string &language, uint32_t unicode) {
    if (!*config_.enabled) {
        return emptyStringPair;
    }

    auto iter = profiles_.find(language);
    if (iter == profiles_.end()) {
        return emptyStringPair;
    }

    return iter->second.getPunctuation(unicode);
}

FCITX_ADDON_FACTORY(PunctuationFactory);
<commit_msg>Fix punc auto eng<commit_after>/*
 * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 */
#include "punctuation.h"
#include "notifications_public.h"
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <fcitx-config/iniparser.h>
#include <fcitx-utils/charutils.h>
#include <fcitx-utils/log.h>
#include <fcitx-utils/standardpath.h>
#include <fcitx-utils/utf8.h>
#include <fcitx/inputcontext.h>
#include <fcitx/inputcontextmanager.h>
#include <fcitx/inputmethodentry.h>
#include <fcitx/inputmethodmanager.h>
#include <fcitx/statusarea.h>
#include <fcitx/userinterfacemanager.h>
#include <fcntl.h>
#include <string_view>
#include <unordered_set>

using namespace fcitx;

namespace {
static const std::string emptyString;
static const std::pair<std::string, std::string> emptyStringPair;
} // namespace

bool dontConvertWhenEn(uint32_t c) { return c == '.' || c == ','; }

class PunctuationState : public InputContextProperty {
public:
    std::unordered_map<uint32_t, std::string> lastPuncStack_;
    char lastIsEngOrDigit_ = 0;
    uint32_t notConverted_ = 0;
    bool mayRebuildStateFromSurroundingText_ = false;

    std::unordered_map<uint32_t, std::string> lastPuncStackBackup_;
    uint32_t notConvertedBackup_ = 0;
};

PunctuationProfile::PunctuationProfile(std::istream &in) {
    std::string strBuf;
    while (std::getline(in, strBuf)) {
        auto pair = stringutils::trimInplace(strBuf);
        std::string::size_type start = pair.first, end = pair.second;
        if (start == end) {
            continue;
        }
        std::string text(strBuf.begin() + start, strBuf.begin() + end);
        auto tokens = stringutils::split(strBuf, FCITX_WHITESPACE);
        if (tokens.size() != 2 && tokens.size() != 3) {
            continue;
        }

        if (!std::any_of(
                tokens.begin(), tokens.end(),
                [](const std::string &s) { return utf8::validate(s); })) {
            continue;
        }
        // we don't make # as comment here, # would be consider as a valid char
        if (utf8::lengthValidated(tokens[0]) != 1) {
            continue;
        }
        auto c = utf8::getChar(tokens[0]);
        decltype(puncMap_)::mapped_type p;
        p.first = tokens[1];
        if (tokens.size() > 2) {
            p.second = tokens[2];
        }
        puncMap_.emplace(c, std::move(p));
    }
}

const std::pair<std::string, std::string> &
PunctuationProfile::getPunctuation(uint32_t unicode) const {
    auto iter = puncMap_.find(unicode);
    if (iter == puncMap_.end()) {
        return emptyStringPair;
    }
    return iter->second;
}

Punctuation::Punctuation(Instance *instance)
    : instance_(instance),
      factory_([](InputContext &) { return new PunctuationState; }) {
    reloadConfig();
    if (!instance_) {
        return;
    }
    instance_->inputContextManager().registerProperty("punctuationState",
                                                      &factory_);
    instance_->userInterfaceManager().registerAction("punctuation",
                                                     &toggleAction_);

    commitConn_ = instance_->connect<Instance::CommitFilter>(
        [this](InputContext *ic, const std::string &sentence) {
            auto state = ic->propertyFor(&factory_);
            // Though sentence is utf8, we only check ascii.
            if (sentence.size() && (charutils::isupper(sentence.back()) ||
                                    charutils::islower(sentence.back()) ||
                                    charutils::isdigit(sentence.back()))) {
                state->lastIsEngOrDigit_ = sentence.back();
            } else {
                state->lastIsEngOrDigit_ = '\0';
            }
        });
    auto processKeyEvent = [this](const KeyEventBase &event) {
        auto &keyEvent = static_cast<const ForwardKeyEvent &>(event);
        auto state = keyEvent.inputContext()->propertyFor(&factory_);
        if (keyEvent.isRelease()) {
            return;
        }
        if (!event.accepted()) {
            if (keyEvent.key().isUAZ() || keyEvent.key().isLAZ() ||
                keyEvent.key().isDigit()) {
                state->lastIsEngOrDigit_ =
                    Key::keySymToUnicode(keyEvent.key().sym());
            } else {
                state->lastIsEngOrDigit_ = '\0';
            }
        }
    };
    keyEventConn_ =
        instance_->connect<Instance::KeyEventResult>(processKeyEvent);
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextForwardKey, EventWatcherPhase::PostInputMethod,
        [processKeyEvent](Event &event) {
            auto &keyEvent = static_cast<ForwardKeyEvent &>(event);
            processKeyEvent(keyEvent);
        }));
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextKeyEvent, EventWatcherPhase::PostInputMethod,
        [this](Event &event) {
            auto &keyEvent = static_cast<KeyEvent &>(event);
            if (keyEvent.isRelease()) {
                return;
            }
            if (inWhiteList(keyEvent.inputContext()) &&
                keyEvent.key().checkKeyList(config_.hotkey.value())) {
                setEnabled(!enabled(), keyEvent.inputContext());
                if (notifications()) {
                    notifications()->call<INotifications::showTip>(
                        "fcitx-punc-toggle", "fcitx",
                        enabled() ? "fcitx-punc-active" : "fcitx-punc-inactive",
                        _("Punctuation"),
                        enabled() ? _("Full width punctuation is enabled.")
                                  : _("Full width punctuation is disabled."),
                        -1);
                }
                return keyEvent.filterAndAccept();
            }
        }));
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextFocusIn, EventWatcherPhase::PostInputMethod,
        [this](Event &event) {
            auto &icEvent = static_cast<InputContextEvent &>(event);
            auto ic = icEvent.inputContext();
            auto state = ic->propertyFor(&factory_);
            if (ic->capabilityFlags().test(CapabilityFlag::SurroundingText)) {
                state->mayRebuildStateFromSurroundingText_ = true;
            }
        }));
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextReset, EventWatcherPhase::PostInputMethod,
        [this](Event &event) {
            auto &icEvent = static_cast<InputContextEvent &>(event);
            auto ic = icEvent.inputContext();
            auto state = ic->propertyFor(&factory_);
            state->lastIsEngOrDigit_ = 0;
            // Backup the state.
            state->notConvertedBackup_ = state->notConverted_;
            state->notConverted_ = 0;
            // Backup the state.
            state->lastPuncStackBackup_ = state->lastPuncStack_;
            state->lastPuncStack_.clear();
            if (ic->capabilityFlags().test(CapabilityFlag::SurroundingText)) {
                state->mayRebuildStateFromSurroundingText_ = true;
            }
        }));
    eventWatchers_.emplace_back(instance_->watchEvent(
        EventType::InputContextSurroundingTextUpdated,
        EventWatcherPhase::PostInputMethod, [this](Event &event) {
            auto &icEvent = static_cast<InputContextEvent &>(event);
            auto ic = icEvent.inputContext();
            auto state = ic->propertyFor(&factory_);
            // Enable to rebuild punctuation state from surrounding text.
            if (state->mayRebuildStateFromSurroundingText_) {
                state->mayRebuildStateFromSurroundingText_ = false;
            } else {
                state->notConvertedBackup_ = 0;
                state->lastPuncStackBackup_.clear();
                return;
            }
            if (!ic->capabilityFlags().test(CapabilityFlag::SurroundingText) ||
                !ic->surroundingText().isValid()) {
                return;
            }
            // We need text before the cursor.
            auto &text = ic->surroundingText().text();
            auto cursor = ic->surroundingText().cursor();
            auto length = utf8::lengthValidated(text);
            if (length == utf8::INVALID_LENGTH) {
                return;
            }
            if (cursor <= 0 && cursor > length) {
                return;
            }
            uint32_t lastCharBeforeCursor;
            auto start = utf8::nextNChar(text.begin(), cursor - 1);
            auto end =
                utf8::getNextChar(start, text.end(), &lastCharBeforeCursor);
            if (lastCharBeforeCursor == utf8::INVALID_CHAR ||
                lastCharBeforeCursor == utf8::NOT_ENOUGH_SPACE) {
                return;
            }
            // Need to make sure we have ascii.
            if (std::distance(start, end) == 1 &&
                (charutils::isupper(lastCharBeforeCursor) ||
                 charutils::islower(lastCharBeforeCursor) ||
                 charutils::isdigit(lastCharBeforeCursor))) {
                state->lastIsEngOrDigit_ = lastCharBeforeCursor;
            }
            // Restore the not converted state if we still after the same chr.
            if (lastCharBeforeCursor == state->notConvertedBackup_ &&
                state->notConverted_ == 0) {
                state->notConverted_ = state->notConvertedBackup_;
            }
            state->notConvertedBackup_ = 0;
            // Scan through the surrounding text
            if (!state->lastPuncStackBackup_.empty() &&
                state->lastPuncStack_.empty()) {
                auto range =
                    utf8::MakeUTF8CharRange(MakeIterRange(text.begin(), end));
                for (auto iter = std::begin(range); iter != std::end(range);
                     iter++) {
                    auto charRange = iter.charRange();
                    std::string_view chr(
                        &*charRange.first,
                        std::distance(charRange.first, charRange.second));
                    auto puncIter = std::find_if(
                        state->lastPuncStackBackup_.begin(),
                        state->lastPuncStackBackup_.end(),
                        [chr](auto &p) { return p.second == chr; });
                    if (puncIter != state->lastPuncStackBackup_.end()) {
                        state->lastPuncStack_.insert(*puncIter);
                    }
                }
            }
            state->lastPuncStackBackup_.clear();
        }));
}

Punctuation::~Punctuation() {}

void Punctuation::reloadConfig() {
    readAsIni(config_, "conf/punctuation.conf");

    auto files = StandardPath::global().multiOpen(StandardPath::Type::PkgData,
                                                  "punctuation", O_RDONLY,
                                                  filter::Prefix("punc.mb."));
    auto iter = profiles_.begin();
    while (iter != profiles_.end()) {
        if (!files.count("punc.mb." + iter->first)) {
            iter = profiles_.erase(iter);
        } else {
            iter++;
        }
    }

    for (const auto &file : files) {
        if (file.first.size() <= 8) {
            continue;
        }
        auto lang = file.first.substr(8);

        try {
            boost::iostreams::stream_buffer<
                boost::iostreams::file_descriptor_source>
                buffer(file.second.fd(),
                       boost::iostreams::file_descriptor_flags::
                           never_close_handle);
            std::istream in(&buffer);
            PunctuationProfile newProfile(in);
            profiles_[lang] = std::move(newProfile);
        } catch (const std::exception &e) {
            FCITX_LOG(Warn)
                << "Error when load profile " << file.first << ": " << e.what();
        }
    }
}

bool Punctuation::inWhiteList(fcitx::InputContext *inputContext) const {
    return toggleAction_.isParent(&inputContext->statusArea());
}

const std::string &Punctuation::pushPunctuation(const std::string &language,
                                                InputContext *ic,
                                                uint32_t unicode) {
    if (!enabled()) {
        return emptyString;
    }
    auto state = ic->propertyFor(&factory_);
    if (state->lastIsEngOrDigit_ && dontConvertWhenEn(unicode)) {
        state->notConverted_ = unicode;
        return emptyString;
    } else {
        auto iter = profiles_.find(language);
        if (iter == profiles_.end()) {
            return emptyString;
        }
        auto &result = getPunctuation(language, unicode);
        state->notConverted_ = 0;
        if (result.second.empty()) {
            return result.first;
        } else {
            auto iter = state->lastPuncStack_.find(unicode);
            if (iter != state->lastPuncStack_.end()) {
                state->lastPuncStack_.erase(iter);
                return result.second;
            } else {
                state->lastPuncStack_.emplace(unicode, result.first);
                return result.first;
            }
        }
    }
}

const std::string &Punctuation::cancelLast(const std::string &language,
                                           InputContext *ic) {
    if (!enabled()) {
        return emptyString;
    }
    auto state = ic->propertyFor(&factory_);
    if (dontConvertWhenEn(state->notConverted_)) {
        auto &result = getPunctuation(language, state->notConverted_);
        state->notConverted_ = 0;
        return result.first;
    }
    return emptyString;
}

const std::pair<std::string, std::string> &
Punctuation::getPunctuation(const std::string &language, uint32_t unicode) {
    if (!*config_.enabled) {
        return emptyStringPair;
    }

    auto iter = profiles_.find(language);
    if (iter == profiles_.end()) {
        return emptyStringPair;
    }

    return iter->second.getPunctuation(unicode);
}

FCITX_ADDON_FACTORY(PunctuationFactory);
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	std::wstring safe_convert(std::string const& s)
	{
		try
		{
			return libtorrent::utf8_wchar(s);
		}
		catch (std::exception)
		{
			std::wstring ret;
			for (const char* i = &*s.begin(); i < &*s.end(); ++i)
			{
				wchar_t c;
				c = '.';
				std::mbtowc(&c, i, 1);
				ret += c;
			}
			return ret;
		}
	}

	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			ret.resize(size-1);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}

	void throw_exception(const char* thrower)
	{
		DWORD err = GetLastError();

#ifdef UNICODE
		wchar_t *wbuffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
		auto_localfree auto_free(wbuffer);
		std::string tmp_utf8;
		libtorrent::wchar_utf8(wbuffer, tmp_utf8);
		char const* buffer = tmp_utf8.c_str();
#else
		char* buffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPSTR)&buffer, 0, 0);
		auto_localfree auto_free(buffer);
#endif

		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef UNICODE
			std::wstring wfile_name(safe_convert(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				utf8_native(file_name).c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	std::wstring safe_convert(std::string const& s)
	{
		try
		{
			return libtorrent::utf8_wchar(s);
		}
		catch (std::exception)
		{
			std::wstring ret;
			for (const char* i = &*s.begin(); i < &*s.end(); ++i)
			{
				wchar_t c;
				c = '.';
				std::mbtowc(&c, i, 1);
				ret += c;
			}
			return ret;
		}
	}

	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}

	void throw_exception(const char* thrower)
	{
		DWORD err = GetLastError();

#ifdef UNICODE
		wchar_t *wbuffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
		auto_localfree auto_free(wbuffer);
		std::string tmp_utf8;
		libtorrent::wchar_utf8(wbuffer, tmp_utf8);
		char const* buffer = tmp_utf8.c_str();
#else
		char* buffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPSTR)&buffer, 0, 0);
		auto_localfree auto_free(buffer);
#endif

		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef UNICODE
			std::wstring wfile_name(safe_convert(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				utf8_native(file_name).c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<|endoftext|>


<commit_before>#include "textStyle.h"

#include "text/fontContext.h"
#include "tile/tile.h"
#include "gl/shaderProgram.h"
#include "gl/vboMesh.h"
#include "view/view.h"
#include "labels/textLabel.h"
#include "glm/gtc/type_ptr.hpp"
#include "tangram.h"

namespace Tangram {

const static std::string key_name("name");
const static std::string uppercase("uppercase");
const static std::string lowercase("lowercase");
const static std::string capitalize("capitalize");

TextStyle::TextStyle(std::string _name, bool _sdf, bool _sdfMultisampling, Blending _blendMode, GLenum _drawMode) :
    Style(_name, _blendMode, _drawMode), m_sdf(_sdf), m_sdfMultisampling(_sdfMultisampling) {
}

TextStyle::~TextStyle() {
}

void TextStyle::constructVertexLayout() {
    m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
        {"a_position", 2, GL_FLOAT, false, 0},
        {"a_uv", 2, GL_FLOAT, false, 0},
        {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
        {"a_screenPosition", 2, GL_FLOAT, false, 0},
        {"a_alpha", 1, GL_FLOAT, false, 0},
        {"a_rotation", 1, GL_FLOAT, false, 0},
    }));
}

void TextStyle::constructShaderProgram() {
    std::string frag = m_sdf ? "sdf.fs" : "text.fs";

    std::string vertShaderSrcStr = stringFromResource("point.vs");
    std::string fragShaderSrcStr = stringFromResource(frag.c_str());

    m_shaderProgram->setSourceStrings(fragShaderSrcStr, vertShaderSrcStr);

    std::string defines;

    if (m_sdf && m_sdfMultisampling) {
        defines += "#define TANGRAM_SDF_MULTISAMPLING\n";
    }

    m_shaderProgram->addSourceBlock("defines", defines);
}

Parameters TextStyle::parseRule(const DrawRule& _rule) const {
    Parameters p;

    std::string fontFamily, fontWeight, fontStyle, transform;
    glm::vec2 offset;

    _rule.get(StyleParamKey::font_family, fontFamily);
    _rule.get(StyleParamKey::font_weight, fontWeight);
    _rule.get(StyleParamKey::font_style, fontStyle);
    _rule.get(StyleParamKey::font_size, p.fontSize);
    _rule.get(StyleParamKey::font_fill, p.fill);
    _rule.get(StyleParamKey::offset, p.offset);
    if (_rule.get(StyleParamKey::font_stroke, p.strokeColor)) {
        _rule.get(StyleParamKey::font_stroke_color, p.strokeColor);
    }
    _rule.get(StyleParamKey::font_stroke_width, p.strokeWidth);
    _rule.get(StyleParamKey::transform, transform);
    _rule.get(StyleParamKey::visible, p.visible);
    _rule.get(StyleParamKey::priority, p.priority);
    _rule.get(StyleParamKey::text_source, p.textSource.second);
    p.textSource.first = _rule.isJSFunction(StyleParamKey::text_source);

    if (transform == capitalize) {
        p.transform = TextTransform::capitalize;
    } else if (transform == lowercase) {
        p.transform = TextTransform::lowercase;
    } else if (transform == uppercase) {
        p.transform = TextTransform::uppercase;
    }

    p.fontKey = fontFamily + "_" + fontWeight + "_" + fontStyle;

    /* Global operations done for fontsize and sdfblur */
    float emSize = p.fontSize / 16.f;
    p.fontSize *= m_pixelScale;
    p.blurSpread = m_sdf ? emSize * 5.0f : 0.0f;

    return p;
}

Label::Options TextStyle::optionsFromTextParams(const Parameters& _params) const {
    Label::Options options;
    options.color = _params.fill;
    options.priority = _params.priority;
    options.offset = _params.offset;
    return options;
}

const std::string& TextStyle::applyTextSource(const Parameters& _parameters, const Properties& _props) const {
    if (!_parameters.textSource.second.empty()) {
        if (_parameters.textSource.first) {
            return _parameters.textSource.second;
        } else {
            return _props.getString(_parameters.textSource.second);
        }
    }
    return _props.getString(key_name);
}

void TextStyle::buildPoint(const Point& _point, const DrawRule& _rule, const Properties& _props, VboMesh& _mesh, Tile& _tile) const {
    auto& buffer = static_cast<TextBuffer&>(_mesh);

    Parameters params = parseRule(_rule);

    if (!params.visible) {
        return;
    }

    const std::string text = applyTextSource(params, _props);

    if (text.length() == 0) { return; }

    buffer.addLabel(text, { glm::vec2(_point), glm::vec2(_point) }, Label::Type::point, params, optionsFromTextParams(params));
}

void TextStyle::buildLine(const Line& _line, const DrawRule& _rule, const Properties& _props, VboMesh& _mesh, Tile& _tile) const {
    auto& buffer = static_cast<TextBuffer&>(_mesh);

	Parameters params = parseRule(_rule);

    if (!params.visible) {
        return;
    }

    const std::string text = applyTextSource(params, _props);

    if (text.length() == 0) { return; }

    int lineLength = _line.size();
    int skipOffset = floor(lineLength / 2);
    float minLength = 0.15; // default, probably need some more thoughts

    for (size_t i = 0; i < _line.size() - 1; i += skipOffset) {
        glm::vec2 p1 = glm::vec2(_line[i]);
        glm::vec2 p2 = glm::vec2(_line[i + 1]);

        glm::vec2 p1p2 = p2 - p1;
        float length = glm::length(p1p2);

        if (length < minLength) {
            continue;
        }

        buffer.addLabel(text, { p1, p2 }, Label::Type::line, params, optionsFromTextParams(params));
    }

}

void TextStyle::buildPolygon(const Polygon& _polygon, const DrawRule& _rule, const Properties& _props, VboMesh& _mesh, Tile& _tile) const {
    auto& buffer = static_cast<TextBuffer&>(_mesh);

	Parameters params = parseRule(_rule);

    if (!params.visible) {
        return;
    }

    const std::string text = applyTextSource(params, _props);

    if (text.length() == 0) { return; }

    glm::vec2 centroid;
    int n = 0;

    for (auto& l : _polygon) {
        for (auto& p : l) {
            centroid.x += p.x;
            centroid.y += p.y;
            n++;
        }
    }
    if (n == 0) { return; }

    centroid /= n;

    buffer.addLabel(text, { centroid, centroid }, Label::Type::point, params, optionsFromTextParams(params));
}

void TextStyle::onBeginDrawFrame(const View& _view, const Scene& _scene) {
    bool contextLost = Style::glContextLost();

    FontContext::GetInstance()->bindAtlas(0);

    if (contextLost) {
        m_shaderProgram->setUniformi("u_tex", 0);
    }

    if (m_dirtyViewport || contextLost) {
        m_shaderProgram->setUniformf("u_resolution", _view.getWidth(), _view.getHeight());
        m_shaderProgram->setUniformMatrix4f("u_proj", glm::value_ptr(_view.getOrthoViewportMatrix()));
        m_dirtyViewport = false;
    }

    Style::onBeginDrawFrame(_view, _scene);

}

}
<commit_msg>Reduce string copies<commit_after>#include "textStyle.h"

#include "text/fontContext.h"
#include "tile/tile.h"
#include "gl/shaderProgram.h"
#include "gl/vboMesh.h"
#include "view/view.h"
#include "labels/textLabel.h"
#include "glm/gtc/type_ptr.hpp"
#include "tangram.h"

namespace Tangram {

const static std::string key_name("name");
const static std::string uppercase("uppercase");
const static std::string lowercase("lowercase");
const static std::string capitalize("capitalize");

TextStyle::TextStyle(std::string _name, bool _sdf, bool _sdfMultisampling, Blending _blendMode, GLenum _drawMode) :
    Style(_name, _blendMode, _drawMode), m_sdf(_sdf), m_sdfMultisampling(_sdfMultisampling) {
}

TextStyle::~TextStyle() {
}

void TextStyle::constructVertexLayout() {
    m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
        {"a_position", 2, GL_FLOAT, false, 0},
        {"a_uv", 2, GL_FLOAT, false, 0},
        {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
        {"a_screenPosition", 2, GL_FLOAT, false, 0},
        {"a_alpha", 1, GL_FLOAT, false, 0},
        {"a_rotation", 1, GL_FLOAT, false, 0},
    }));
}

void TextStyle::constructShaderProgram() {
    std::string frag = m_sdf ? "sdf.fs" : "text.fs";

    std::string vertShaderSrcStr = stringFromResource("point.vs");
    std::string fragShaderSrcStr = stringFromResource(frag.c_str());

    m_shaderProgram->setSourceStrings(fragShaderSrcStr, vertShaderSrcStr);

    std::string defines;

    if (m_sdf && m_sdfMultisampling) {
        defines += "#define TANGRAM_SDF_MULTISAMPLING\n";
    }

    m_shaderProgram->addSourceBlock("defines", defines);
}

Parameters TextStyle::parseRule(const DrawRule& _rule) const {
    Parameters p;

    std::string fontFamily, fontWeight, fontStyle, transform;
    glm::vec2 offset;

    _rule.get(StyleParamKey::font_family, fontFamily);
    _rule.get(StyleParamKey::font_weight, fontWeight);
    _rule.get(StyleParamKey::font_style, fontStyle);
    _rule.get(StyleParamKey::font_size, p.fontSize);
    _rule.get(StyleParamKey::font_fill, p.fill);
    _rule.get(StyleParamKey::offset, p.offset);
    if (_rule.get(StyleParamKey::font_stroke, p.strokeColor)) {
        _rule.get(StyleParamKey::font_stroke_color, p.strokeColor);
    }
    _rule.get(StyleParamKey::font_stroke_width, p.strokeWidth);
    _rule.get(StyleParamKey::transform, transform);
    _rule.get(StyleParamKey::visible, p.visible);
    _rule.get(StyleParamKey::priority, p.priority);
    _rule.get(StyleParamKey::text_source, p.textSource.second);
    p.textSource.first = _rule.isJSFunction(StyleParamKey::text_source);

    if (transform == capitalize) {
        p.transform = TextTransform::capitalize;
    } else if (transform == lowercase) {
        p.transform = TextTransform::lowercase;
    } else if (transform == uppercase) {
        p.transform = TextTransform::uppercase;
    }

    p.fontKey = fontFamily + "_" + fontWeight + "_" + fontStyle;

    /* Global operations done for fontsize and sdfblur */
    float emSize = p.fontSize / 16.f;
    p.fontSize *= m_pixelScale;
    p.blurSpread = m_sdf ? emSize * 5.0f : 0.0f;

    return p;
}

Label::Options TextStyle::optionsFromTextParams(const Parameters& _params) const {
    Label::Options options;
    options.color = _params.fill;
    options.priority = _params.priority;
    options.offset = _params.offset;
    return options;
}

const std::string& TextStyle::applyTextSource(const Parameters& _parameters, const Properties& _props) const {
    if (!_parameters.textSource.second.empty()) {
        if (_parameters.textSource.first) {
            return _parameters.textSource.second;
        } else {
            return _props.getString(_parameters.textSource.second);
        }
    }
    return _props.getString(key_name);
}

void TextStyle::buildPoint(const Point& _point, const DrawRule& _rule, const Properties& _props, VboMesh& _mesh, Tile& _tile) const {
    auto& buffer = static_cast<TextBuffer&>(_mesh);

    Parameters params = parseRule(_rule);

    if (!params.visible) {
        return;
    }

    const std::string& text = applyTextSource(params, _props);

    if (text.length() == 0) { return; }

    buffer.addLabel(text, { glm::vec2(_point), glm::vec2(_point) }, Label::Type::point, params, optionsFromTextParams(params));
}

void TextStyle::buildLine(const Line& _line, const DrawRule& _rule, const Properties& _props, VboMesh& _mesh, Tile& _tile) const {
    auto& buffer = static_cast<TextBuffer&>(_mesh);

	Parameters params = parseRule(_rule);

    if (!params.visible) {
        return;
    }

    const std::string& text = applyTextSource(params, _props);

    if (text.length() == 0) { return; }

    int lineLength = _line.size();
    int skipOffset = floor(lineLength / 2);
    float minLength = 0.15; // default, probably need some more thoughts

    for (size_t i = 0; i < _line.size() - 1; i += skipOffset) {
        glm::vec2 p1 = glm::vec2(_line[i]);
        glm::vec2 p2 = glm::vec2(_line[i + 1]);

        glm::vec2 p1p2 = p2 - p1;
        float length = glm::length(p1p2);

        if (length < minLength) {
            continue;
        }

        buffer.addLabel(text, { p1, p2 }, Label::Type::line, params, optionsFromTextParams(params));
    }

}

void TextStyle::buildPolygon(const Polygon& _polygon, const DrawRule& _rule, const Properties& _props, VboMesh& _mesh, Tile& _tile) const {
    auto& buffer = static_cast<TextBuffer&>(_mesh);

	Parameters params = parseRule(_rule);

    if (!params.visible) {
        return;
    }

    const std::string& text = applyTextSource(params, _props);

    if (text.length() == 0) { return; }

    glm::vec2 centroid;
    int n = 0;

    for (auto& l : _polygon) {
        for (auto& p : l) {
            centroid.x += p.x;
            centroid.y += p.y;
            n++;
        }
    }
    if (n == 0) { return; }

    centroid /= n;

    buffer.addLabel(text, { centroid, centroid }, Label::Type::point, params, optionsFromTextParams(params));
}

void TextStyle::onBeginDrawFrame(const View& _view, const Scene& _scene) {
    bool contextLost = Style::glContextLost();

    FontContext::GetInstance()->bindAtlas(0);

    if (contextLost) {
        m_shaderProgram->setUniformi("u_tex", 0);
    }

    if (m_dirtyViewport || contextLost) {
        m_shaderProgram->setUniformf("u_resolution", _view.getWidth(), _view.getHeight());
        m_shaderProgram->setUniformMatrix4f("u_proj", glm::value_ptr(_view.getOrthoViewportMatrix()));
        m_dirtyViewport = false;
    }

    Style::onBeginDrawFrame(_view, _scene);

}

}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef EXIF_IO_EASYEXIF_HPP
#define EXIF_IO_EASYEXIF_HPP

#include "openMVG/exif/exif_IO.hpp"
#include "third_party/easyexif/exif.h"

#include <fstream>
#include <sstream>
#include <vector>

namespace openMVG {
namespace exif  {

class Exif_IO_EasyExif : public Exif_IO
{
  public:
    Exif_IO_EasyExif(): bHaveExifInfo_(false)
    {
    }

    Exif_IO_EasyExif( const std::string & sFileName ): bHaveExifInfo_(false)
    {
      open(sFileName);
    }

    bool open( const std::string & sFileName )
    {
      // Read the file into a buffer
      FILE *fp = fopen(sFileName.c_str(), "rb");
      if (!fp) {
        return false;
      }
      fseek(fp, 0, SEEK_END);
      unsigned long fsize = ftell(fp);
      rewind(fp);
      std::vector<unsigned char> buf(fsize);
      if (fread(&buf[0], 1, fsize, fp) != fsize) {
        return false;
      }
      fclose(fp);

      // Parse EXIF
      int code = exifInfo_.parseFrom(&buf[0], fsize);
      if (code)
        bHaveExifInfo_ = false;
      else
        bHaveExifInfo_ = true;

      return bHaveExifInfo_;
    }

    size_t getWidth() const
    {
      return exifInfo_.ImageWidth;
    }

    size_t getHeight() const
    {
      return exifInfo_.ImageHeight;
    }

    float getFocal() const
    {
      return static_cast<float>(exifInfo_.FocalLength);
    }

    std::string getBrand() const
    {
      std::string sbrand = exifInfo_.Make;
      if (!sbrand.empty())
      {
        // remove leading and trailing spaces
        sbrand.erase(0, sbrand.find_first_not_of(' '));
        sbrand.erase(sbrand.find_last_not_of(' '));
      }
      return sbrand;
    }

    std::string getModel() const
    {
      std::string smodel = exifInfo_.Model;
      if (!smodel.empty())
      {
        // remove leading and trailing spaces
        smodel.erase(0, smodel.find_first_not_of(' '));
        smodel.erase(smodel.find_last_not_of(' '));
      }
      return smodel;
    }

    std::string getImageUniqueID() const
    {
      return exifInfo_.ImageUniqueID;
    }

    std::string getSerialNumber() const
    {
      return exifInfo_.SerialNumber;
    }

    std::string getLensModel() const
    {
      return exifInfo_.LensModel;
    }

    std::string getLensSerialNumber() const
    {
      return exifInfo_.LensSerialNumber;
    }

    // File change date and time
    std::string getDateTime() const
    {
      return exifInfo_.DateTime;
    }

    // Original file date and time (may not exist)
    std::string getDateTimeOriginal() const
    {
      return exifInfo_.SubSecTimeOriginal;
    }

    // Digitization date and time (may not exist)
    std::string getDateTimeDigitized() const
    {
      return exifInfo_.SubSecTimeOriginal;
    }

    // Sub-second time that original picture was taken
    std::string getSubSecTimeOriginal() const
    {
      return exifInfo_.SubSecTimeOriginal;
    }

    /**Verify if the file has metadata*/
    bool doesHaveExifInfo() const
    {
      return bHaveExifInfo_;
    }

    /** Print all data*/
    std::string allExifData() const
    {
      std::ostringstream os;
      os
        << "Camera make        : " << exifInfo_.Make << "\n"
        << "Camera model       : " << exifInfo_.Model << "\n"
        << "Lens Model         : " << exifInfo_.LensModel << "\n"
        << "Software           : " << exifInfo_.Software << "\n"
        << "Bits per sample    : " << exifInfo_.BitsPerSample << "\n"
        << "Image width        : " << exifInfo_.ImageWidth << "\n"
        << "Image height       : " << exifInfo_.ImageHeight << "\n"
        << "Image description  : " << exifInfo_.ImageDescription << "\n"
        << "Image orientation  : " << exifInfo_.Orientation << "\n"
        << "Image copyright    : " << exifInfo_.Copyright << "\n"
        << "Image date/time    : " << exifInfo_.DateTime << "\n"
        << "Original date/time : " << exifInfo_.DateTimeOriginal << "\n"
        << "Digitize date/time : " << exifInfo_.DateTimeDigitized << "\n"
        << "Subsecond time     : " << exifInfo_.SubSecTimeOriginal << "\n"
        << "Exposure time      : 1/" << (unsigned) (1.0/exifInfo_.ExposureTime) << "\n"
        << "F-stop             : " << exifInfo_.FNumber << "\n"
        << "ISO speed          : " << exifInfo_.ISOSpeedRatings << "\n"
        << "Subject distance   : " << exifInfo_.SubjectDistance << "\n"
        << "Exposure bias      : EV" << exifInfo_.ExposureBiasValue << "\n"
        << "Flash used?        : " << exifInfo_.Flash << "\n"
        << "Metering mode      : " << exifInfo_.MeteringMode << "\n"
        << "Lens focal length  : mm\n" << exifInfo_.FocalLength << "\n"
        << "35mm focal length  : mm\n" << exifInfo_.FocalLengthIn35mm << "\n"
        << "GPS Latitude       : deg ( deg, min, sec )\n" << "("
        <<  exifInfo_.GeoLocation.Latitude << ", "
        <<  exifInfo_.GeoLocation.LatComponents.degrees << ", "
        <<  exifInfo_.GeoLocation.LatComponents.minutes << ", "
        <<  exifInfo_.GeoLocation.LatComponents.seconds << ", "
        <<  exifInfo_.GeoLocation.LatComponents.direction << ")" << "\n"
        << "GPS Longitude      : deg ( deg, min, sec )\n" << "("
        <<  exifInfo_.GeoLocation.Longitude << ", "
        <<  exifInfo_.GeoLocation.LonComponents.degrees << ", "
        <<  exifInfo_.GeoLocation.LonComponents.minutes << ", "
        <<  exifInfo_.GeoLocation.LonComponents.seconds << ", "
        <<  exifInfo_.GeoLocation.LonComponents.direction << ")" << "\n"
        << "GPS Altitude       : m" << exifInfo_.GeoLocation.Altitude << "\n"
        << "Image Unique ID    : " << exifInfo_.ImageUniqueID << "\n"
        << "Serial Number      : " << exifInfo_.SerialNumber << "\n"
        << "Lens Serial Number : " << exifInfo_.LensSerialNumber << "\n";
      return os.str();
    }

  private:
    EXIFInfo exifInfo_;
    bool bHaveExifInfo_;
};

} // namespace exif
} // namespace openMVG

#endif //EXIF_IO_EASYEXIF_HPP
<commit_msg>Exif: trim spaces<commit_after>// Copyright (c) 2013-2015 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef EXIF_IO_EASYEXIF_HPP
#define EXIF_IO_EASYEXIF_HPP

#include "openMVG/exif/exif_IO.hpp"
#include "third_party/easyexif/exif.h"

#include <fstream>
#include <sstream>
#include <vector>

namespace openMVG {
namespace exif  {

/// Remove all leading and trailing spaces from the input. The result is a trimmed copy of the input
inline std::string trim_copy(const std::string& s)
{
  if(s.empty())
    return s;

  std::string res(s);
  // remove leading and trailing spaces
  res.erase(0, res.find_first_not_of(' '));
  res.erase(res.find_last_not_of(' '));
  return res;
}

class Exif_IO_EasyExif : public Exif_IO
{
  public:
    Exif_IO_EasyExif(): bHaveExifInfo_(false)
    {
    }

    Exif_IO_EasyExif( const std::string & sFileName ): bHaveExifInfo_(false)
    {
      open(sFileName);
    }

    bool open( const std::string & sFileName )
    {
      // Read the file into a buffer
      FILE *fp = fopen(sFileName.c_str(), "rb");
      if (!fp) {
        return false;
      }
      fseek(fp, 0, SEEK_END);
      unsigned long fsize = ftell(fp);
      rewind(fp);
      std::vector<unsigned char> buf(fsize);
      if (fread(&buf[0], 1, fsize, fp) != fsize) {
        return false;
      }
      fclose(fp);

      // Parse EXIF
      int code = exifInfo_.parseFrom(&buf[0], fsize);
      if (code)
        bHaveExifInfo_ = false;
      else
        bHaveExifInfo_ = true;

      return bHaveExifInfo_;
    }

    size_t getWidth() const
    {
      return exifInfo_.ImageWidth;
    }

    size_t getHeight() const
    {
      return exifInfo_.ImageHeight;
    }

    float getFocal() const
    {
      return static_cast<float>(exifInfo_.FocalLength);
    }

    std::string getBrand() const
    {
      return trim_copy(exifInfo_.Make);
    }

    std::string getModel() const
    {
      return trim_copy(exifInfo_.Model);
    }

    std::string getImageUniqueID() const
    {
      return trim_copy(exifInfo_.ImageUniqueID);
    }

    std::string getSerialNumber() const
    {
      return trim_copy(exifInfo_.SerialNumber);
    }

    std::string getLensModel() const
    {
      return trim_copy(exifInfo_.LensModel);
    }

    std::string getLensSerialNumber() const
    {
      return trim_copy(exifInfo_.LensSerialNumber);
    }

    // File change date and time
    std::string getDateTime() const
    {
      return trim_copy(exifInfo_.DateTime);
    }

    // Original file date and time (may not exist)
    std::string getDateTimeOriginal() const
    {
      return trim_copy(exifInfo_.DateTimeOriginal);
    }

    // Digitization date and time (may not exist)
    std::string getDateTimeDigitized() const
    {
      return trim_copy(exifInfo_.DateTimeDigitized);
    }

    // Sub-second time that original picture was taken
    std::string getSubSecTimeOriginal() const
    {
      return trim_copy(exifInfo_.SubSecTimeOriginal);
    }

    /**Verify if the file has metadata*/
    bool doesHaveExifInfo() const
    {
      return bHaveExifInfo_;
    }

    /** Print all data*/
    std::string allExifData() const
    {
      std::ostringstream os;
      os
        << "Camera make        : " << exifInfo_.Make << "\n"
        << "Camera model       : " << exifInfo_.Model << "\n"
        << "Lens Model         : " << exifInfo_.LensModel << "\n"
        << "Software           : " << exifInfo_.Software << "\n"
        << "Bits per sample    : " << exifInfo_.BitsPerSample << "\n"
        << "Image width        : " << exifInfo_.ImageWidth << "\n"
        << "Image height       : " << exifInfo_.ImageHeight << "\n"
        << "Image description  : " << exifInfo_.ImageDescription << "\n"
        << "Image orientation  : " << exifInfo_.Orientation << "\n"
        << "Image copyright    : " << exifInfo_.Copyright << "\n"
        << "Image date/time    : " << exifInfo_.DateTime << "\n"
        << "Original date/time : " << exifInfo_.DateTimeOriginal << "\n"
        << "Digitize date/time : " << exifInfo_.DateTimeDigitized << "\n"
        << "Subsecond time     : " << exifInfo_.SubSecTimeOriginal << "\n"
        << "Exposure time      : 1/" << (unsigned) (1.0/exifInfo_.ExposureTime) << "\n"
        << "F-stop             : " << exifInfo_.FNumber << "\n"
        << "ISO speed          : " << exifInfo_.ISOSpeedRatings << "\n"
        << "Subject distance   : " << exifInfo_.SubjectDistance << "\n"
        << "Exposure bias      : EV" << exifInfo_.ExposureBiasValue << "\n"
        << "Flash used?        : " << exifInfo_.Flash << "\n"
        << "Metering mode      : " << exifInfo_.MeteringMode << "\n"
        << "Lens focal length  : mm\n" << exifInfo_.FocalLength << "\n"
        << "35mm focal length  : mm\n" << exifInfo_.FocalLengthIn35mm << "\n"
        << "GPS Latitude       : deg ( deg, min, sec )\n" << "("
        <<  exifInfo_.GeoLocation.Latitude << ", "
        <<  exifInfo_.GeoLocation.LatComponents.degrees << ", "
        <<  exifInfo_.GeoLocation.LatComponents.minutes << ", "
        <<  exifInfo_.GeoLocation.LatComponents.seconds << ", "
        <<  exifInfo_.GeoLocation.LatComponents.direction << ")" << "\n"
        << "GPS Longitude      : deg ( deg, min, sec )\n" << "("
        <<  exifInfo_.GeoLocation.Longitude << ", "
        <<  exifInfo_.GeoLocation.LonComponents.degrees << ", "
        <<  exifInfo_.GeoLocation.LonComponents.minutes << ", "
        <<  exifInfo_.GeoLocation.LonComponents.seconds << ", "
        <<  exifInfo_.GeoLocation.LonComponents.direction << ")" << "\n"
        << "GPS Altitude       : m" << exifInfo_.GeoLocation.Altitude << "\n"
        << "Image Unique ID    : " << exifInfo_.ImageUniqueID << "\n"
        << "Serial Number      : " << exifInfo_.SerialNumber << "\n"
        << "Lens Serial Number : " << exifInfo_.LensSerialNumber << "\n";
      return os.str();
    }

  private:
    EXIFInfo exifInfo_;
    bool bHaveExifInfo_;
};

} // namespace exif
} // namespace openMVG

#endif //EXIF_IO_EASYEXIF_HPP
<|endoftext|>


<commit_before>/**
 * @file Cosa/UML/Clock.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_UML_CLOCK_HH
#define COSA_UML_CLOCK_HH

#include "Cosa/UML/TimedCapsule.hh"
#include "Cosa/UML/Connector.hh"
#include "Cosa/UML/Controller.hh"
#include "Cosa/Periodic.hh"
#include "Cosa/Time.hh"

namespace UML {

/**
 * Clock Capsule class. The clock signal is defined as a Connector
 * type; Tick. The behavior of this class is simple incrementing the
 * tick value and thereby scheduling the capsules that are listening
 * to the tick.
 *
 * @section Diagram
 *
 *   +--------+
 *   | Clock  |---[Tick]--->
 *   +--------+
 *         [ms]
 */
class Clock : public TimedCapsule {
public:
  /**
   * Type of clock tick connector.
   */
  typedef Connector<clock_t> Tick;

  /**
   * Construct Clock with given tick connector and period in
   * milli-seconds.
   * @param[in] tick connector.
   * @param[in] ms period.
   */
  Clock(Tick& tick, uint16_t ms) :
    TimedCapsule(ms),
    m_tick(tick)
  {}

  /**
   * @override Capsule
   * Increment clock tick and schedule all capsules that listen for
   * clock update.
   */
  virtual void behavior()
  {
    m_tick = m_tick + 1;
  }

protected:
  Tick& m_tick;
};

};
#endif
<commit_msg>Cleanup include section.<commit_after>/**
 * @file Cosa/UML/Clock.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_UML_CLOCK_HH
#define COSA_UML_CLOCK_HH

#include "Cosa/UML/TimedCapsule.hh"
#include "Cosa/UML/Connector.hh"
#include "Cosa/Time.hh"

namespace UML {

/**
 * Clock Capsule class. The clock signal is defined as a Connector
 * type; Tick. The behavior of this class is simple incrementing the
 * tick value and thereby scheduling the capsules that are listening
 * to the tick.
 *
 * @section Diagram
 *
 *   +--------+
 *   | Clock  |---[Tick]--->
 *   +--------+
 *         [ms]
 */
class Clock : public TimedCapsule {
public:
  /**
   * Type of clock tick connector.
   */
  typedef Connector<clock_t> Tick;

  /**
   * Construct Clock with given tick connector and period in
   * milli-seconds.
   * @param[in] tick connector.
   * @param[in] ms period.
   */
  Clock(Tick& tick, uint16_t ms) :
    TimedCapsule(ms),
    m_tick(tick)
  {}

  /**
   * @override Capsule
   * Increment clock tick and schedule all capsules that listen for
   * clock update.
   */
  virtual void behavior()
  {
    m_tick = m_tick + 1;
  }

protected:
  Tick& m_tick;
};

};
#endif
<|endoftext|>