<commit_before>/*=========================================================================

  Program:   Monteverdi2
  Language:  C++

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See Copyright.txt for details.

  Monteverdi2 is distributed under the CeCILL licence version 2. See
  Licence_CeCILL_V2-en.txt or
  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt for more details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "mvdDatabaseTreeWidget.h"

/*****************************************************************************/
/* INCLUDE SECTION                                                           */

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// System includes (sorted by alphabetic order)

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)
#include "Core/mvdAlgorithm.h"
#include "Core/mvdDataStream.h"
#include "Gui/mvdTreeWidgetItem.h"

namespace mvd
{

/*
  TRANSLATOR mvd::DatabaseTreeWidget

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*****************************************************************************/
/* SUB-CLASSES DECLARATION                                                   */

class DatabaseTreeWidget::EditionContext
{
  // Q_OBJECT;

public:
  EditionContext() :
    m_Item( NULL ),
    m_Text(),
    m_Column( -1 )
  {
  }

  inline bool IsEditable() const
  {
    return m_Item!=NULL && m_Item->flags().testFlag( Qt::ItemIsEditable );
  }

  inline bool IsActive() const
  {
    return IsEditable() && m_Column>=0;
  }

  inline QTreeWidgetItem* GetItem()
  {
    return m_Item;
  }

  inline void SetItem( QTreeWidgetItem* item )
  {
    EditItem();

    m_Item = item;
  }

  inline int GetColumn() const
  {
    return m_Column;
  }

  inline void EditItem( int column =-1 )
  {
    if( column<0 )
      {
      m_Column = -1;
      m_Text.clear();
      }
    else
      {
      assert( m_Item!=NULL );
      assert( m_Column<0 );

      m_Column = column;

      m_Text = m_Item->text( column );
      }
  }

  inline void RestoreItem()
  {
    assert( m_Item!=NULL );
    assert( m_Column>=0 );

    m_Item->setText( m_Column, m_Text );

    m_Column = -1;
  }

private:
  QTreeWidgetItem* m_Item;
  QString m_Text;
  int m_Column;
};

/*****************************************************************************/
/* SUB-CLASSES DEFINITION                                                    */

/*****************************************************************************/
/* CONSTANTS                                                                 */

/*****************************************************************************/
/* STATIC IMPLEMENTATION SECTION                                             */

/*****************************************************************************/
/* CLASS IMPLEMENTATION SECTION                                              */

/*******************************************************************************/
DatabaseTreeWidget
::DatabaseTreeWidget( QWidget* parent  ):
  TreeWidget( parent ),
  // m_DatasetFilename(),
  // m_EditionActive( false )
  m_EditionContext( new EditionContext() )
{
  // setMouseTracking(true);

  //
  // do some connection
  QObject::connect(
    this,
    SIGNAL( itemChanged( QTreeWidgetItem* , int ) ),
    SLOT( OnItemChanged( QTreeWidgetItem* , int ) )
  );

  QObject::connect(
    this,
    SIGNAL( customContextMenuRequested( const QPoint& ) ),
    SLOT( OnCustomContextMenuRequested( const QPoint& ) )
  );
}

/*******************************************************************************/
DatabaseTreeWidget
::~DatabaseTreeWidget()
{
  delete m_EditionContext;
  m_EditionContext = NULL;
}

/*******************************************************************************/
void
DatabaseTreeWidget::mouseMoveEvent( QMouseEvent * event )
{
  TreeWidget::mouseMoveEvent( event );
}

/*******************************************************************************/
void
DatabaseTreeWidget::mousePressEvent(QMouseEvent *event)
{
  TreeWidget::mousePressEvent( event );
}

/*******************************************************************************/
void
DatabaseTreeWidget::dropEvent(QDropEvent *event)
{
  // qDebug() << this << "::dropEvent(" << event << ")";

  /*
  if( event->mimeData()->hasFormat( "application/x-qabstractitemmodeldatalist" ) )
    {
    QByteArray byteArray(
      event->mimeData()->data( "application/x-qabstractitemmodeldatalist" )
    );

    QDataStream stream( &byteArray, QIODevice::ReadOnly );

    int count = 0;

    //
    // http://www.qtcentre.org/threads/8756-QTreeWidgetItem-mime-type

    typedef QMap< int, QVariant > QIntToVariantMap;

    struct Item
    {
      Item() : row( -1 ), col( -1 ), var() {}

      int row;
      int col;
      QIntToVariantMap var;
    };

    while( !stream.atEnd() )
      {
      Item item;

      stream >> item.row >> item.col >> item.var;

      qDebug() << item.row << item.col << item.var;

      ++ count;
      }

    qDebug() << count << "items.";
    }
  */

  /*
  if( event->mimeData()->hasFormat( "application/x-qtreewidgetitemptrlist" ) )
    {
    QByteArray byteArray(
      event->mimeData()->data( "application/x-qtreewidgetitemptrlist" )
    );

    QDataStream stream( &byteArray, QIODevice::ReadOnly );

    int count = 0;

    //
    // http://www.qtcentre.org/threads/8756-QTreeWidgetItem-mime-type

    QTreeWidgetItem* varItem = NULL;

    while( !stream.atEnd() )
      {
      QVariant variant;

      stream >> variant;

      qDebug() << "Variant:" << variant;

      // http://www.qtfr.org/viewtopic.php?id=9630

      varItem = variant.value< QTreeWidgetItem* >();

      qDebug()
        << "Item (variant):"
        << varItem
        << varItem->text( 0 )
        << varItem->text( 1 )
        << varItem->text( 2 )
        << varItem->parent();

      ++ count;
      }

    qDebug() << count << "items.";
    }
  */

  TreeWidget::dropEvent( event );
}

/*******************************************************************************/
bool
DatabaseTreeWidget::dropMimeData( QTreeWidgetItem* parent,
                                  int index,
                                  const QMimeData* data,
                                  Qt::DropAction action )
{
  qDebug()
    << this << "::dropMimeData("
    << parent << ","
    << index << ","
    << data << ","
    << action << ")";

  bool result = TreeWidget::dropMimeData( parent, index, data, action );

  qDebug() << "->" << result;

  return result;
}

/*******************************************************************************/
void
DatabaseTreeWidget
::EditItem( int column )
{
  assert( m_EditionContext!=NULL );
  assert( m_EditionContext->GetItem()!=NULL );

  m_EditionContext->EditItem( column );

  if( m_EditionContext->IsActive() )
    editItem( m_EditionContext->GetItem(), m_EditionContext->GetColumn() );
}

/*******************************************************************************/
/* SLOTS                                                                       */
/*******************************************************************************/
void
DatabaseTreeWidget
::OnAddItemTriggered()
{
  assert( m_EditionContext!=NULL );
  assert( m_EditionContext->GetItem()!=NULL );

  emit AddItemRequested( m_EditionContext->GetItem() );
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnDeleteItemTriggered()
{
  assert( m_EditionContext!=NULL );
  assert( m_EditionContext->GetItem()!=NULL );

  emit DeleteItemRequested( m_EditionContext->GetItem() );
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnRenameItemTriggered()
{
  EditItem( 0 );

  /*
  // find the QTreeWidgetItem and make it editable
  m_ItemToEdit =
  m_PreviousItemText = m_ItemToEdit->text(0);
  // m_DefaultItemFlags  = m_ItemToEdit->flags();
  // m_ItemToEdit->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled);

  // edit item
  // inspired from here:
  // http://www.qtcentre.org/archive/index.php/t-45857.html?s=ad4e7c45bbd9fd4bf5cc32853dd3fe82
  m_EditionActive = true;

  editItem( m_ItemToEdit, 0 );
  */
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnItemChanged( QTreeWidgetItem* item , int column )
{
  assert( m_EditionContext!=NULL );

  if( !m_EditionContext->IsActive() )
    return;

  if( item->text( column ).isEmpty() )
    m_EditionContext->RestoreItem();
  else
    {
    /*
    // dynamic cast to get the id
    TreeWidgetItem* dsItem =
      dynamic_cast<TreeWidgetItem *>( item );

    // send the new alias of the dataset / it identifier
    emit DatasetRenamed( dsItem->text( column ), dsItem->GetHash() );
    */

    assert( m_EditionContext->GetItem()==item );

    emit ItemTextChanged( item, column );
    }

  m_EditionContext->EditItem();
}

/******************************************************************************/
void
DatabaseTreeWidget
::keyPressEvent( QKeyEvent* event )
{
  assert( currentItem()!=NULL );

  assert( m_EditionContext!=NULL );

  QTreeWidgetItem * item = currentItem();

  switch( event->key() )
    {
    case Qt::Key_F2:
        m_EditionContext->SetItem( item );
        EditItem( 0 );
      break;

    case Qt::Key_Delete:
        m_EditionContext->SetItem( item );
        if( m_EditionContext->IsEditable() )
          emit DeleteItemRequested( m_EditionContext->GetItem() );
      break;

    default:
      TreeWidget::keyPressEvent( event );
      break;
      /*
    {
    // cast to DatasetTreeItem
    TreeWidgetItem* item
      = dynamic_cast<TreeWidgetItem *>( currentItem() );

    emit DatasetToDeleteSelected( item->GetHash() );
    break;
    }
      */
    }
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnCustomContextMenuRequested(const QPoint& pos)
{
  // Get  item.
  QTreeWidgetItem* qtwi = itemAt( pos );

  if( qtwi==NULL )
    return;

  TreeWidgetItem* item =
    dynamic_cast< TreeWidgetItem* >( itemAt( pos ) );

  assert( item!=NULL );

  /*
  QString itemType;

  switch( item->type() )
    {
    case TreeWidgetItem::ITEM_TYPE_NONE:
      break;

    case TreeWidgetItem::ITEM_TYPE_NODE:
      itemType = tr( "group" );
      break;

    case TreeWidgetItem::ITEM_TYPE_LEAF:
      itemType = tr( "dataset" );
      break;

    default:
      assert( false && "Unhandled TreeWidgetItem::ItemType value!" );
      break;
    };
  */

  // Remember context-menu clicked position.
  //
  // This is done to later find cicked item because QTreeWidgetItem is
  // not derived from QObject and QSignalMapper only supports int,
  // QString, QObject and QWiget.
  //
  // This is also the reason why delete and rename triggers are
  // duplicated.
  // m_ContextualMenuClickedPosition = pos;

  // Remember clicked item.
  assert( m_EditionContext!=NULL );
  m_EditionContext->SetItem( item );

  // Create context-menu.
  QMenu menu;

  // Insert actions into context-menu.
  if( item->parent()!=NULL &&
      item->type()==TreeWidgetItem::ITEM_TYPE_LEAF )
    {
    /*
    AddMappedAction(
      &menu,
      tr( "Delete dataset" ),
      item->GetHash(),
      this,
      SIGNAL( DatasetToDeleteSelected( const QString& ) )
    );
    */

    AddAction(
      &menu,
      tr( "Delete dataset" ),
      this,
      SLOT( OnDeleteItemTriggered() )
    );

    if( item->flags().testFlag( Qt::ItemIsEditable ) )
      AddAction(
        &menu,
        tr ("Rename dataset"),
        this,
        SLOT( OnRenameItemTriggered() )
      );
    }

  if( item->type()==TreeWidgetItem::ITEM_TYPE_NODE )
    {
    AddAction(
      &menu,
      tr( "Add group" ),
      this,
      SLOT( OnAddItemTriggered() )
    );

    QAction * action2 =
      AddAction(
        &menu,
        tr( "Delete group" ),
        this,
        SLOT( OnDeleteItemTriggered() )
      );

    action2->setEnabled(
      item->childCount()<=0 && m_EditionContext->IsEditable()
    );

    QAction * action3 =
      AddAction(
        &menu,
        tr( "Rename group" ),
        this,
        SLOT( OnRenameItemTriggered() )
      );

    action3->setEnabled( m_EditionContext->IsEditable() );
    }

  // Display and activate context-menu.
  menu.exec( viewport()->mapToGlobal( pos ) );
}

/*******************************************************************************/
QAction*
DatabaseTreeWidget::AddAction( QMenu* menu,
                               const QString& text,
                               QObject* receiver,
                               const char* method,
                               Qt::ConnectionType type )
{
  assert( menu!=NULL );
  assert( receiver!=NULL );
  assert( method!=NULL );

  QAction* action = menu->addAction( text );

  QObject::connect(
    action,
    SIGNAL( triggered() ),
    // to:
    receiver,
    method,
    // with:
    type
  );

  return action;
}

/*******************************************************************************/
QAction*
DatabaseTreeWidget::AddMappedAction( QMenu* menu,
                                     const QString& text,
                                     const QString& data,
                                     QObject* receiver,
                                     const char* slot,
                                     Qt::ConnectionType type )
{
  assert( menu!=NULL );
  assert( receiver!=NULL );
  assert( slot!=NULL );

  // Add signal-mapped action into menu.
  QSignalMapper* signalMapper = AddMappedAction( menu, text );
  assert(
    signalMapper->parent()==qobject_cast< QAction* >( signalMapper->parent() )
  );

  // Get action back.
  QAction* action = qobject_cast< QAction* >( signalMapper->parent() );
  assert( action!=NULL );

  // Set signal mapping.
  signalMapper->setMapping( action, data );

  // Connect mapped signal.
  QObject::connect(
    signalMapper,
    SIGNAL( mapped( const QString& ) ),
    // to:
    receiver,
    slot,
    // with:
    type
  );

  return action;
}

/*******************************************************************************/
QSignalMapper *
DatabaseTreeWidget::AddMappedAction( QMenu* menu,
                                     const QString& text )
{
  assert( menu!=NULL );

  // Add menu action.
  QAction * action = menu->addAction( text );

  // Pre-create signal-mapper.
  QSignalMapper* signalMapper = new QSignalMapper( action );

  // Connect menu-action trigger to signal-mapper.
  QObject::connect(
    action,
    SIGNAL( triggered() ),
    // to:
    signalMapper,
    SLOT( map() )
  );

  // Return parented signal-mapper.
  return signalMapper;
}

} // end namespace 'mvd'
<commit_msg>ENH: Disabled 'Rename dataset' action from contextual menu (DatabaseBrowserView) when dataset is disabled.<commit_after>/*=========================================================================

  Program:   Monteverdi2
  Language:  C++

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See Copyright.txt for details.

  Monteverdi2 is distributed under the CeCILL licence version 2. See
  Licence_CeCILL_V2-en.txt or
  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt for more details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "mvdDatabaseTreeWidget.h"

/*****************************************************************************/
/* INCLUDE SECTION                                                           */

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// System includes (sorted by alphabetic order)

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)
#include "Core/mvdAlgorithm.h"
#include "Core/mvdDataStream.h"
#include "Gui/mvdTreeWidgetItem.h"

namespace mvd
{

/*
  TRANSLATOR mvd::DatabaseTreeWidget

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*****************************************************************************/
/* SUB-CLASSES DECLARATION                                                   */

class DatabaseTreeWidget::EditionContext
{
  // Q_OBJECT;

public:
  EditionContext() :
    m_Item( NULL ),
    m_Text(),
    m_Column( -1 )
  {
  }

  inline bool IsEditable() const
  {
    return m_Item!=NULL && m_Item->flags().testFlag( Qt::ItemIsEditable );
  }

  inline bool IsActive() const
  {
    return IsEditable() && m_Column>=0;
  }

  inline QTreeWidgetItem* GetItem()
  {
    return m_Item;
  }

  inline void SetItem( QTreeWidgetItem* item )
  {
    EditItem();

    m_Item = item;
  }

  inline int GetColumn() const
  {
    return m_Column;
  }

  inline void EditItem( int column =-1 )
  {
    if( column<0 )
      {
      m_Column = -1;
      m_Text.clear();
      }
    else
      {
      assert( m_Item!=NULL );
      assert( m_Column<0 );

      m_Column = column;

      m_Text = m_Item->text( column );
      }
  }

  inline void RestoreItem()
  {
    assert( m_Item!=NULL );
    assert( m_Column>=0 );

    m_Item->setText( m_Column, m_Text );

    m_Column = -1;
  }

private:
  QTreeWidgetItem* m_Item;
  QString m_Text;
  int m_Column;
};

/*****************************************************************************/
/* SUB-CLASSES DEFINITION                                                    */

/*****************************************************************************/
/* CONSTANTS                                                                 */

/*****************************************************************************/
/* STATIC IMPLEMENTATION SECTION                                             */

/*****************************************************************************/
/* CLASS IMPLEMENTATION SECTION                                              */

/*******************************************************************************/
DatabaseTreeWidget
::DatabaseTreeWidget( QWidget* parent  ):
  TreeWidget( parent ),
  // m_DatasetFilename(),
  // m_EditionActive( false )
  m_EditionContext( new EditionContext() )
{
  // setMouseTracking(true);

  //
  // do some connection
  QObject::connect(
    this,
    SIGNAL( itemChanged( QTreeWidgetItem* , int ) ),
    SLOT( OnItemChanged( QTreeWidgetItem* , int ) )
  );

  QObject::connect(
    this,
    SIGNAL( customContextMenuRequested( const QPoint& ) ),
    SLOT( OnCustomContextMenuRequested( const QPoint& ) )
  );
}

/*******************************************************************************/
DatabaseTreeWidget
::~DatabaseTreeWidget()
{
  delete m_EditionContext;
  m_EditionContext = NULL;
}

/*******************************************************************************/
void
DatabaseTreeWidget::mouseMoveEvent( QMouseEvent * event )
{
  TreeWidget::mouseMoveEvent( event );
}

/*******************************************************************************/
void
DatabaseTreeWidget::mousePressEvent(QMouseEvent *event)
{
  TreeWidget::mousePressEvent( event );
}

/*******************************************************************************/
void
DatabaseTreeWidget::dropEvent(QDropEvent *event)
{
  // qDebug() << this << "::dropEvent(" << event << ")";

  /*
  if( event->mimeData()->hasFormat( "application/x-qabstractitemmodeldatalist" ) )
    {
    QByteArray byteArray(
      event->mimeData()->data( "application/x-qabstractitemmodeldatalist" )
    );

    QDataStream stream( &byteArray, QIODevice::ReadOnly );

    int count = 0;

    //
    // http://www.qtcentre.org/threads/8756-QTreeWidgetItem-mime-type

    typedef QMap< int, QVariant > QIntToVariantMap;

    struct Item
    {
      Item() : row( -1 ), col( -1 ), var() {}

      int row;
      int col;
      QIntToVariantMap var;
    };

    while( !stream.atEnd() )
      {
      Item item;

      stream >> item.row >> item.col >> item.var;

      qDebug() << item.row << item.col << item.var;

      ++ count;
      }

    qDebug() << count << "items.";
    }
  */

  /*
  if( event->mimeData()->hasFormat( "application/x-qtreewidgetitemptrlist" ) )
    {
    QByteArray byteArray(
      event->mimeData()->data( "application/x-qtreewidgetitemptrlist" )
    );

    QDataStream stream( &byteArray, QIODevice::ReadOnly );

    int count = 0;

    //
    // http://www.qtcentre.org/threads/8756-QTreeWidgetItem-mime-type

    QTreeWidgetItem* varItem = NULL;

    while( !stream.atEnd() )
      {
      QVariant variant;

      stream >> variant;

      qDebug() << "Variant:" << variant;

      // http://www.qtfr.org/viewtopic.php?id=9630

      varItem = variant.value< QTreeWidgetItem* >();

      qDebug()
        << "Item (variant):"
        << varItem
        << varItem->text( 0 )
        << varItem->text( 1 )
        << varItem->text( 2 )
        << varItem->parent();

      ++ count;
      }

    qDebug() << count << "items.";
    }
  */

  TreeWidget::dropEvent( event );
}

/*******************************************************************************/
bool
DatabaseTreeWidget::dropMimeData( QTreeWidgetItem* parent,
                                  int index,
                                  const QMimeData* data,
                                  Qt::DropAction action )
{
  qDebug()
    << this << "::dropMimeData("
    << parent << ","
    << index << ","
    << data << ","
    << action << ")";

  bool result = TreeWidget::dropMimeData( parent, index, data, action );

  qDebug() << "->" << result;

  return result;
}

/*******************************************************************************/
void
DatabaseTreeWidget
::EditItem( int column )
{
  assert( m_EditionContext!=NULL );
  assert( m_EditionContext->GetItem()!=NULL );

  m_EditionContext->EditItem( column );

  if( m_EditionContext->IsActive() )
    editItem( m_EditionContext->GetItem(), m_EditionContext->GetColumn() );
}

/*******************************************************************************/
/* SLOTS                                                                       */
/*******************************************************************************/
void
DatabaseTreeWidget
::OnAddItemTriggered()
{
  assert( m_EditionContext!=NULL );
  assert( m_EditionContext->GetItem()!=NULL );

  emit AddItemRequested( m_EditionContext->GetItem() );
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnDeleteItemTriggered()
{
  assert( m_EditionContext!=NULL );
  assert( m_EditionContext->GetItem()!=NULL );

  emit DeleteItemRequested( m_EditionContext->GetItem() );
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnRenameItemTriggered()
{
  EditItem( 0 );

  /*
  // find the QTreeWidgetItem and make it editable
  m_ItemToEdit =
  m_PreviousItemText = m_ItemToEdit->text(0);
  // m_DefaultItemFlags  = m_ItemToEdit->flags();
  // m_ItemToEdit->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled);

  // edit item
  // inspired from here:
  // http://www.qtcentre.org/archive/index.php/t-45857.html?s=ad4e7c45bbd9fd4bf5cc32853dd3fe82
  m_EditionActive = true;

  editItem( m_ItemToEdit, 0 );
  */
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnItemChanged( QTreeWidgetItem* item , int column )
{
  assert( m_EditionContext!=NULL );

  if( !m_EditionContext->IsActive() )
    return;

  if( item->text( column ).isEmpty() )
    m_EditionContext->RestoreItem();
  else
    {
    /*
    // dynamic cast to get the id
    TreeWidgetItem* dsItem =
      dynamic_cast<TreeWidgetItem *>( item );

    // send the new alias of the dataset / it identifier
    emit DatasetRenamed( dsItem->text( column ), dsItem->GetHash() );
    */

    assert( m_EditionContext->GetItem()==item );

    emit ItemTextChanged( item, column );
    }

  m_EditionContext->EditItem();
}

/******************************************************************************/
void
DatabaseTreeWidget
::keyPressEvent( QKeyEvent* event )
{
  assert( currentItem()!=NULL );

  assert( m_EditionContext!=NULL );

  QTreeWidgetItem * item = currentItem();

  switch( event->key() )
    {
    case Qt::Key_F2:
        m_EditionContext->SetItem( item );
        EditItem( 0 );
      break;

    case Qt::Key_Delete:
        m_EditionContext->SetItem( item );
        if( m_EditionContext->IsEditable() )
          emit DeleteItemRequested( m_EditionContext->GetItem() );
      break;

    default:
      TreeWidget::keyPressEvent( event );
      break;
      /*
    {
    // cast to DatasetTreeItem
    TreeWidgetItem* item
      = dynamic_cast<TreeWidgetItem *>( currentItem() );

    emit DatasetToDeleteSelected( item->GetHash() );
    break;
    }
      */
    }
}

/*******************************************************************************/
void
DatabaseTreeWidget::OnCustomContextMenuRequested(const QPoint& pos)
{
  // Get  item.
  QTreeWidgetItem* qtwi = itemAt( pos );

  if( qtwi==NULL )
    return;

  TreeWidgetItem* item =
    dynamic_cast< TreeWidgetItem* >( itemAt( pos ) );

  assert( item!=NULL );

  /*
  QString itemType;

  switch( item->type() )
    {
    case TreeWidgetItem::ITEM_TYPE_NONE:
      break;

    case TreeWidgetItem::ITEM_TYPE_NODE:
      itemType = tr( "group" );
      break;

    case TreeWidgetItem::ITEM_TYPE_LEAF:
      itemType = tr( "dataset" );
      break;

    default:
      assert( false && "Unhandled TreeWidgetItem::ItemType value!" );
      break;
    };
  */

  // Remember context-menu clicked position.
  //
  // This is done to later find cicked item because QTreeWidgetItem is
  // not derived from QObject and QSignalMapper only supports int,
  // QString, QObject and QWiget.
  //
  // This is also the reason why delete and rename triggers are
  // duplicated.
  // m_ContextualMenuClickedPosition = pos;

  // Remember clicked item.
  assert( m_EditionContext!=NULL );
  m_EditionContext->SetItem( item );

  // Create context-menu.
  QMenu menu;

  // Insert actions into context-menu.
  if( item->parent()!=NULL &&
      item->type()==TreeWidgetItem::ITEM_TYPE_LEAF )
    {
    /*
    AddMappedAction(
      &menu,
      tr( "Delete dataset" ),
      item->GetHash(),
      this,
      SIGNAL( DatasetToDeleteSelected( const QString& ) )
    );
    */

    AddAction(
      &menu,
      tr( "Delete dataset" ),
      this,
      SLOT( OnDeleteItemTriggered() )
    );

    if( item->flags().testFlag( Qt::ItemIsEditable ) )
      {
      QAction * action =
        AddAction(
          &menu,
          tr ("Rename dataset"),
          this,
          SLOT( OnRenameItemTriggered() )
        );

      action->setEnabled( !item->isDisabled() );
      }
    }

  if( item->type()==TreeWidgetItem::ITEM_TYPE_NODE )
    {
    AddAction(
      &menu,
      tr( "Add group" ),
      this,
      SLOT( OnAddItemTriggered() )
    );

    QAction * action2 =
      AddAction(
        &menu,
        tr( "Delete group" ),
        this,
        SLOT( OnDeleteItemTriggered() )
      );

    action2->setEnabled(
      item->childCount()<=0 && m_EditionContext->IsEditable()
    );

    QAction * action3 =
      AddAction(
        &menu,
        tr( "Rename group" ),
        this,
        SLOT( OnRenameItemTriggered() )
      );

    action3->setEnabled( m_EditionContext->IsEditable() );
    }

  // Display and activate context-menu.
  menu.exec( viewport()->mapToGlobal( pos ) );
}

/*******************************************************************************/
QAction*
DatabaseTreeWidget::AddAction( QMenu* menu,
                               const QString& text,
                               QObject* receiver,
                               const char* method,
                               Qt::ConnectionType type )
{
  assert( menu!=NULL );
  assert( receiver!=NULL );
  assert( method!=NULL );

  QAction* action = menu->addAction( text );

  QObject::connect(
    action,
    SIGNAL( triggered() ),
    // to:
    receiver,
    method,
    // with:
    type
  );

  return action;
}

/*******************************************************************************/
QAction*
DatabaseTreeWidget::AddMappedAction( QMenu* menu,
                                     const QString& text,
                                     const QString& data,
                                     QObject* receiver,
                                     const char* slot,
                                     Qt::ConnectionType type )
{
  assert( menu!=NULL );
  assert( receiver!=NULL );
  assert( slot!=NULL );

  // Add signal-mapped action into menu.
  QSignalMapper* signalMapper = AddMappedAction( menu, text );
  assert(
    signalMapper->parent()==qobject_cast< QAction* >( signalMapper->parent() )
  );

  // Get action back.
  QAction* action = qobject_cast< QAction* >( signalMapper->parent() );
  assert( action!=NULL );

  // Set signal mapping.
  signalMapper->setMapping( action, data );

  // Connect mapped signal.
  QObject::connect(
    signalMapper,
    SIGNAL( mapped( const QString& ) ),
    // to:
    receiver,
    slot,
    // with:
    type
  );

  return action;
}

/*******************************************************************************/
QSignalMapper *
DatabaseTreeWidget::AddMappedAction( QMenu* menu,
                                     const QString& text )
{
  assert( menu!=NULL );

  // Add menu action.
  QAction * action = menu->addAction( text );

  // Pre-create signal-mapper.
  QSignalMapper* signalMapper = new QSignalMapper( action );

  // Connect menu-action trigger to signal-mapper.
  QObject::connect(
    action,
    SIGNAL( triggered() ),
    // to:
    signalMapper,
    SLOT( map() )
  );

  // Return parented signal-mapper.
  return signalMapper;
}

} // end namespace 'mvd'
<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CdsdkViewfinderImpl.hpp CDSDK - Viewfinder impl
//
#pragma once

// includes
#include "Viewfinder.hpp"
#include "CdsdkCommon.hpp"
#include "LightweightMutex.hpp"

namespace CDSDK
{

class SourceDeviceImpl;

/// viewfinder impl for CDSDK
// TODO use CDSelectViewfinderCameraOutput
class ViewfinderImpl : public Viewfinder
{
public:
   /// ctor
   ViewfinderImpl(std::shared_ptr<SourceDeviceImpl> spSourceDevice)
      :m_spSourceDevice(spSourceDevice),
       m_dwLastViewfinderCallbackTick(0)
   {
      // note: check if camera supports viewfinder before calling CDStartViewfinder()
      // Not all camera models support the Viewfinder function. Cameras that support Viewfinder
      // are those cameras for which the cdRELEASE_CONTROL_CAP_VIEWFINDER bit is set. Obtain the
      // value by executing CDGetDevicePropertyData using cdDEVICE_PROP_RELEASE_CONTROL_CAP.

      // check: pointers (e.g. this) must fit into cdContext; may not work on 64-bit
      static_assert(sizeof(cdContext) == sizeof(void*), "pointers must fit into cdContext");

#pragma warning(push)
#pragma warning(disable: 4311) // 'reinterpret_cast' : pointer truncation from 'P' to 'T'
      cdContext context = reinterpret_cast<cdContext>(this);
#pragma warning(pop)

      // may return cdINVALID_HANDLE, cdNOT_SUPPORTED
      cdError err = CDStartViewfinder(GetSource(),
         0, // format; 0 = JPEG, 1 = Bitmap
         &ViewfinderImpl::ViewfinderCallback,
         context);

      LOG_TRACE(_T("CDStartViewfinder(%08x, 1 (BMP), &CallbackFunc, context=%08x) returned %08x\n"),
         GetSource(), this, err);
      CheckError(_T("CDStartViewfinder"), err, __FILE__, __LINE__);
   }

   /// dtor
   virtual ~ViewfinderImpl() throw()
   {
      // disable handler
      SetAvailImageHandler(Viewfinder::T_fnOnAvailViewfinderImage());

      // may return cdINVALID_HANDLE, cdINVALID_FN_CALL
      cdError err = CDTermViewfinder(GetSource());
      LOG_TRACE(_T("CDTermViewfinder(%08x) returned %08x\n"), GetSource(), err);
   }

   virtual void SetAvailImageHandler(Viewfinder::T_fnOnAvailViewfinderImage fnOnAvailViewfinderImage) override
   {
      LightweightMutex::LockType lock(m_mtxFnOnAvailViewfinderImage);

      m_fnOnAvailViewfinderImage = fnOnAvailViewfinderImage;
   }

private:
   /// callback function called when new viewfinder image is available
   static cdUInt32 __stdcall ViewfinderCallback(
      cdVoid* pBuf,        // Pointer to the buffer that contains one frame of Viewfinder data.
      cdUInt32 Size,       // Buffer size indicated by pBuf
      cdUInt32 Format,     // Viewfinder data format
      cdContext Context)   // Context
   {
#pragma warning(push)
#pragma warning(disable: 4312) // 'reinterpret_cast' : conversion from 'T' to 'P' of greater size
      ViewfinderImpl* pThis = reinterpret_cast<ViewfinderImpl*>(Context);
      ATLASSERT(pThis != nullptr);
#pragma warning(pop)

#ifdef _DEBUG
      DWORD dwCurrentTick = GetTickCount();

      LOG_TRACE(_T("\nViewfinderCallback(p = %p, size = %u, format = %u (%s), context) called with new viewfinder data;")
         _T("last callback was %u ms ago.\n"),
         pBuf, Size, Format,
         Format == 0 ? _T("JPEG") : Format == 1 ? _T("BMP") : _T("???"),
         pThis->m_dwLastViewfinderCallbackTick == 0 ? 0 : dwCurrentTick - pThis->m_dwLastViewfinderCallbackTick);
      pThis->m_dwLastViewfinderCallbackTick = dwCurrentTick;
#endif

      const BYTE* pbData = static_cast<BYTE*>(pBuf);

      std::vector<BYTE> vecData(pbData, pbData+Size);
      pThis->OnViewfinderImage(vecData, Format == 0);

      return 0;
   }

   /// called when new viewfinder image is available
   void OnViewfinderImage(const std::vector<BYTE>& vecData, bool /*bFormatIsJpeg*/)
   {
      LightweightMutex::LockType lock(m_mtxFnOnAvailViewfinderImage);

      if (m_fnOnAvailViewfinderImage)
         m_fnOnAvailViewfinderImage(vecData);
   }

   /// returns source
   cdHSource GetSource() const throw();

private:
   /// source device
   std::shared_ptr<SourceDeviceImpl> m_spSourceDevice;

   /// last tick where viewfinder image was retrieved
   DWORD m_dwLastViewfinderCallbackTick;

   /// mutex to protect m_fnOnAvailViewfinderImage
   LightweightMutex m_mtxFnOnAvailViewfinderImage;

   /// viewfinder image handler
   Viewfinder::T_fnOnAvailViewfinderImage m_fnOnAvailViewfinderImage;
};

} // namespace CDSDK
<commit_msg>improved logging for viewfinder impl<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CdsdkViewfinderImpl.hpp CDSDK - Viewfinder impl
//
#pragma once

// includes
#include "Viewfinder.hpp"
#include "CdsdkCommon.hpp"
#include "LightweightMutex.hpp"

namespace CDSDK
{

class SourceDeviceImpl;

/// viewfinder impl for CDSDK
// TODO use CDSelectViewfinderCameraOutput
class ViewfinderImpl : public Viewfinder
{
public:
   /// ctor
   ViewfinderImpl(std::shared_ptr<SourceDeviceImpl> spSourceDevice)
      :m_spSourceDevice(spSourceDevice),
       m_dwLastViewfinderCallbackTick(0)
   {
      // note: check if camera supports viewfinder before calling CDStartViewfinder()
      // Not all camera models support the Viewfinder function. Cameras that support Viewfinder
      // are those cameras for which the cdRELEASE_CONTROL_CAP_VIEWFINDER bit is set. Obtain the
      // value by executing CDGetDevicePropertyData using cdDEVICE_PROP_RELEASE_CONTROL_CAP.

      // check: pointers (e.g. this) must fit into cdContext; may not work on 64-bit
      static_assert(sizeof(cdContext) == sizeof(void*), "pointers must fit into cdContext");

#pragma warning(push)
#pragma warning(disable: 4311) // 'reinterpret_cast' : pointer truncation from 'P' to 'T'
      cdContext context = reinterpret_cast<cdContext>(this);
#pragma warning(pop)

      // may return cdINVALID_HANDLE, cdNOT_SUPPORTED
      cdUInt32 format = 0; // 0 = JPEG, 1 = Bitmap
      cdError err = CDStartViewfinder(GetSource(),
         format,
         &ViewfinderImpl::ViewfinderCallback,
         context);

      LOG_TRACE(_T("CDStartViewfinder(source = %08x, %u (%s), &CallbackFunc, context=%08x) returned %08x\n"),
         GetSource(),
         format,
         format == 0 ? _T("JPEG") :
         format == 1 ? _T("BMP") : _T("???"),
         this, err);
      CheckError(_T("CDStartViewfinder"), err, __FILE__, __LINE__);
   }

   /// dtor
   virtual ~ViewfinderImpl() throw()
   {
      // disable handler
      SetAvailImageHandler(Viewfinder::T_fnOnAvailViewfinderImage());

      // may return cdINVALID_HANDLE, cdINVALID_FN_CALL
      cdError err = CDTermViewfinder(GetSource());
      LOG_TRACE(_T("CDTermViewfinder(%08x) returned %08x\n"), GetSource(), err);
   }

   virtual void SetAvailImageHandler(Viewfinder::T_fnOnAvailViewfinderImage fnOnAvailViewfinderImage) override
   {
      LightweightMutex::LockType lock(m_mtxFnOnAvailViewfinderImage);

      m_fnOnAvailViewfinderImage = fnOnAvailViewfinderImage;
   }

private:
   /// callback function called when new viewfinder image is available
   static cdUInt32 __stdcall ViewfinderCallback(
      cdVoid* pBuf,        // Pointer to the buffer that contains one frame of Viewfinder data.
      cdUInt32 Size,       // Buffer size indicated by pBuf
      cdUInt32 Format,     // Viewfinder data format
      cdContext Context)   // Context
   {
#pragma warning(push)
#pragma warning(disable: 4312) // 'reinterpret_cast' : conversion from 'T' to 'P' of greater size
      ViewfinderImpl* pThis = reinterpret_cast<ViewfinderImpl*>(Context);
      ATLASSERT(pThis != nullptr);
#pragma warning(pop)

#ifdef _DEBUG
      DWORD dwCurrentTick = GetTickCount();

      LOG_TRACE(_T("\nViewfinderCallback(p = %p, size = %u, format = %u (%s), context) called with new viewfinder data;")
         _T("last callback was %u ms ago.\n"),
         pBuf, Size, Format,
         Format == 0 ? _T("JPEG") : Format == 1 ? _T("BMP") : _T("???"),
         pThis->m_dwLastViewfinderCallbackTick == 0 ? 0 : dwCurrentTick - pThis->m_dwLastViewfinderCallbackTick);
      pThis->m_dwLastViewfinderCallbackTick = dwCurrentTick;
#endif

      const BYTE* pbData = static_cast<BYTE*>(pBuf);

      std::vector<BYTE> vecData(pbData, pbData+Size);
      pThis->OnViewfinderImage(vecData, Format == 0);

      return 0;
   }

   /// called when new viewfinder image is available
   void OnViewfinderImage(const std::vector<BYTE>& vecData, bool /*bFormatIsJpeg*/)
   {
      LightweightMutex::LockType lock(m_mtxFnOnAvailViewfinderImage);

      if (m_fnOnAvailViewfinderImage)
         m_fnOnAvailViewfinderImage(vecData);
   }

   /// returns source
   cdHSource GetSource() const throw();

private:
   /// source device
   std::shared_ptr<SourceDeviceImpl> m_spSourceDevice;

   /// last tick where viewfinder image was retrieved
   DWORD m_dwLastViewfinderCallbackTick;

   /// mutex to protect m_fnOnAvailViewfinderImage
   LightweightMutex m_mtxFnOnAvailViewfinderImage;

   /// viewfinder image handler
   Viewfinder::T_fnOnAvailViewfinderImage m_fnOnAvailViewfinderImage;
};

} // namespace CDSDK
<|endoftext|>


<commit_before>#include <cstring>

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>

#include "customhash.hpp"
#include "proposals.hpp"
#include "serialization.hpp"
#include "storage.hpp"

namespace dafs
{
    ReplicatedStorage::ReplicatedStorage(
        std::string directory,
        std::string hostport,
        int identity)
    : parliament(directory, Action(parliament))
    {
        files_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::FileListName)).string(),
            dafs::CreateLocation(hostport)
        );
        blocks_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::BlockListName)).string(),
            dafs::CreateLocation(hostport)
        );
        nodeset_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::NodeSetName)).string(),
            dafs::CreateLocation(hostport)
        );
        identity_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::IdentityName)).string(),
            dafs::CreateLocation(hostport)
        );

        set_identity(identity);
        load_nodes(hostport);
    }

    int
    ReplicatedStorage::GetIdentity()
    {
        int identity;
        std::fstream s(fs::path(identity_info.path).string(),
                       std::ios::in | std::ios::binary);
        s >> identity;
        return identity;
    }

    void
    ReplicatedStorage::CreateFile(FileInfo info)
    {
        do_write(ProposalType::CreateFile,
                 files_info,
                 dafs::Serialize(info));
    }

    void
    ReplicatedStorage::OpenFile(FileInfo info)
    {
    }

    void
    ReplicatedStorage::DeleteFile(FileInfo info)
    {
        do_write(ProposalType::RemoveFile,
                 files_info,
                 dafs::Serialize(info));
    }

    FileFormat
    ReplicatedStorage::ReadFile(FileInfo info)
    {
        std::fstream s(fs::path(info.path).string(),
                       std::ios::out | std::ios::binary);
        FileFormat f = dafs::Deserialize<FileFormat>(s);
        return f;
    }

    void
    ReplicatedStorage::WriteFile(FileInfo info, Bytes data)
    {
    }

    void
    ReplicatedStorage::CreateBlock(BlockInfo info)
    {
        do_write(ProposalType::CreateBlock,
                 blocks_info,
                 dafs::Serialize(info));
    }

    void
    ReplicatedStorage::DeleteBlock(BlockInfo info)
    {
        do_write(ProposalType::RemoveBlock,
                 blocks_info,
                 dafs::Serialize(info));
    }

    BlockFormat
    ReplicatedStorage::ReadBlock(BlockInfo info)
    {
        std::fstream f(fs::path(info.path).string(),
                       std::ios::out | std::ios::binary);
        BlockFormat b;
        f.read(b.contents, BLOCK_SIZE_IN_BYTES);
        return b;
    }

    void
    ReplicatedStorage::WriteBlock(BlockInfo info, Bytes data)
    {
        // TODO: Handle overflows to another block.
        BlockFormat was = ReadBlock(info);
        BlockFormat is(was);

        std::memmove(is.contents + info.offset, data.contents,
                     BLOCK_SIZE_IN_BYTES - info.offset);

        Delta delta = CreateDelta(info.path, was.contents, is.contents);

        do_write(ProposalType::WriteDelta,
                 info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::WriteBlock(BlockInfo info, BlockFormat data)
    {
        BlockFormat was = ReadBlock(info);
        Delta delta = CreateDelta(info.path, was.contents, data.contents);

        do_write(ProposalType::WriteDelta,
                 info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::AddNode(std::string address, short port)
    {
        BlockFormat was = ReadBlock(nodeset_info);
        BlockFormat is(was);

        auto nodeset = dafs::Deserialize<NodeSet>(was.contents);
        nodeset.endpoints.push_back(address + std::to_string(port));
        std::memmove(is.contents, dafs::Serialize(nodeset).c_str(),
                     BLOCK_SIZE_IN_BYTES);

        Delta delta = CreateDelta(nodeset_info.path, was.contents,
                                  is.contents);

        do_write(ProposalType::AddNode,
                 nodeset_info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::RemoveNode(std::string address, short port)
    {
        BlockFormat was = ReadBlock(nodeset_info);
        BlockFormat is(was);

        auto nodeset = dafs::Deserialize<NodeSet>(was.contents);
        std::memmove(is.contents, dafs::Serialize(nodeset).c_str(),
                     BLOCK_SIZE_IN_BYTES);
        nodeset.endpoints.erase
        (
            std::remove_if
            (
                nodeset.endpoints.begin(),
                nodeset.endpoints.end(),
                [=](const std::string& current)
                {
                    return current == address + std::to_string(port);
                }
            ),
            nodeset.endpoints.end()
        );

        Delta delta = CreateDelta(nodeset_info.path, was.contents,
                                  is.contents);

        do_write(ProposalType::RemoveNode,
                 nodeset_info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::do_write(
        dafs::ProposalType type,
        BlockInfo info,
        std::string data)
    {
        info.path = fs::path(info.path).string();
        parliament.SendProposal
        (
            dafs::Serialize<dafs::Proposal>
            (
                CreateProposal
                (
                    type,
                    data,
                    info,
                    info.revision
                )
            )
        );
    }

    void
    ReplicatedStorage::load_nodes(
        std::string hostport)
    {
        if (boost::filesystem::exists(nodeset_info.path))
        {
            std::fstream f(fs::path(nodeset_info.path).string(),
                           std::ios::in | std::ios::binary);

            for (auto node_string : dafs::Deserialize<NodeSet>(f).endpoints)
            {
                std::vector<std::string> hostport;
                split(hostport, node_string, boost::is_any_of(":"));
                parliament.AddLegislator(
                    hostport[0],
                    boost::lexical_cast<short>(hostport[1]));
            }
        }
        else
        {
            NodeSet nodeset;
            nodeset.endpoints.push_back(hostport);

            std::fstream f(fs::path(nodeset_info.path).string(),
                           std::ios::out | std::ios::binary);
            f << dafs::Serialize(nodeset);
            f.flush();
        }
    }

    void
    ReplicatedStorage::set_identity(int id)
    {
        std::fstream s(fs::path(identity_info.path).string(),
                       std::ios::out | std::ios::binary);
        s << id;
        s.flush();
    }
}
<commit_msg>Fix replicated storage fstream args<commit_after>#include <cstring>

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>

#include "customhash.hpp"
#include "proposals.hpp"
#include "serialization.hpp"
#include "storage.hpp"

namespace dafs
{
    ReplicatedStorage::ReplicatedStorage(
        std::string directory,
        std::string hostport,
        int identity)
    : parliament(directory, Action(parliament))
    {
        files_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::FileListName)).string(),
            dafs::CreateLocation(hostport)
        );
        blocks_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::BlockListName)).string(),
            dafs::CreateLocation(hostport)
        );
        nodeset_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::NodeSetName)).string(),
            dafs::CreateLocation(hostport)
        );
        identity_info = dafs::CreateBlockInfo(
            (fs::path(directory) / fs::path(Constant::IdentityName)).string(),
            dafs::CreateLocation(hostport)
        );

        set_identity(identity);
        load_nodes(hostport);
    }

    int
    ReplicatedStorage::GetIdentity()
    {
        int identity;
        std::fstream s(fs::path(identity_info.path).string(),
                       std::ios::in | std::ios::binary);
        s >> identity;
        return identity;
    }

    void
    ReplicatedStorage::CreateFile(FileInfo info)
    {
        do_write(ProposalType::CreateFile,
                 files_info,
                 dafs::Serialize(info));
    }

    void
    ReplicatedStorage::OpenFile(FileInfo info)
    {
    }

    void
    ReplicatedStorage::DeleteFile(FileInfo info)
    {
        do_write(ProposalType::RemoveFile,
                 files_info,
                 dafs::Serialize(info));
    }

    FileFormat
    ReplicatedStorage::ReadFile(FileInfo info)
    {
        std::fstream s(fs::path(info.path).string(),
                       std::ios::in | std::ios::binary);
        FileFormat f = dafs::Deserialize<FileFormat>(s);
        return f;
    }

    void
    ReplicatedStorage::WriteFile(FileInfo info, Bytes data)
    {
    }

    void
    ReplicatedStorage::CreateBlock(BlockInfo info)
    {
        do_write(ProposalType::CreateBlock,
                 blocks_info,
                 dafs::Serialize(info));
    }

    void
    ReplicatedStorage::DeleteBlock(BlockInfo info)
    {
        do_write(ProposalType::RemoveBlock,
                 blocks_info,
                 dafs::Serialize(info));
    }

    BlockFormat
    ReplicatedStorage::ReadBlock(BlockInfo info)
    {
        std::fstream f(fs::path(info.path).string(),
                       std::ios::in | std::ios::binary);
        BlockFormat b;
        f.read(b.contents, BLOCK_SIZE_IN_BYTES);
        return b;
    }

    void
    ReplicatedStorage::WriteBlock(BlockInfo info, Bytes data)
    {
        // TODO: Handle overflows to another block.
        BlockFormat was = ReadBlock(info);
        BlockFormat is(was);

        std::memmove(is.contents + info.offset, data.contents,
                     BLOCK_SIZE_IN_BYTES - info.offset);

        Delta delta = CreateDelta(info.path, was.contents, is.contents);

        do_write(ProposalType::WriteDelta,
                 info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::WriteBlock(BlockInfo info, BlockFormat data)
    {
        BlockFormat was = ReadBlock(info);
        Delta delta = CreateDelta(info.path, was.contents, data.contents);

        do_write(ProposalType::WriteDelta,
                 info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::AddNode(std::string address, short port)
    {
        BlockFormat was = ReadBlock(nodeset_info);
        BlockFormat is(was);

        auto nodeset = dafs::Deserialize<NodeSet>(was.contents);
        nodeset.endpoints.push_back(address + std::to_string(port));
        std::memmove(is.contents, dafs::Serialize(nodeset).c_str(),
                     BLOCK_SIZE_IN_BYTES);

        Delta delta = CreateDelta(nodeset_info.path, was.contents,
                                  is.contents);

        do_write(ProposalType::AddNode,
                 nodeset_info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::RemoveNode(std::string address, short port)
    {
        BlockFormat was = ReadBlock(nodeset_info);
        BlockFormat is(was);

        auto nodeset = dafs::Deserialize<NodeSet>(was.contents);
        std::memmove(is.contents, dafs::Serialize(nodeset).c_str(),
                     BLOCK_SIZE_IN_BYTES);
        nodeset.endpoints.erase
        (
            std::remove_if
            (
                nodeset.endpoints.begin(),
                nodeset.endpoints.end(),
                [=](const std::string& current)
                {
                    return current == address + std::to_string(port);
                }
            ),
            nodeset.endpoints.end()
        );

        Delta delta = CreateDelta(nodeset_info.path, was.contents,
                                  is.contents);

        do_write(ProposalType::RemoveNode,
                 nodeset_info,
                 dafs::Serialize(delta));
    }

    void
    ReplicatedStorage::do_write(
        dafs::ProposalType type,
        BlockInfo info,
        std::string data)
    {
        info.path = fs::path(info.path).string();
        parliament.SendProposal
        (
            dafs::Serialize<dafs::Proposal>
            (
                CreateProposal
                (
                    type,
                    data,
                    info,
                    info.revision
                )
            )
        );
    }

    void
    ReplicatedStorage::load_nodes(
        std::string hostport)
    {
        if (boost::filesystem::exists(nodeset_info.path))
        {
            std::fstream f(fs::path(nodeset_info.path).string(),
                           std::ios::in | std::ios::binary);

            for (auto node_string : dafs::Deserialize<NodeSet>(f).endpoints)
            {
                std::vector<std::string> hostport;
                split(hostport, node_string, boost::is_any_of(":"));
                parliament.AddLegislator(
                    hostport[0],
                    boost::lexical_cast<short>(hostport[1]));
            }
        }
        else
        {
            NodeSet nodeset;
            nodeset.endpoints.push_back(hostport);

            std::fstream f(fs::path(nodeset_info.path).string(),
                           std::ios::out | std::ios::binary);
            f << dafs::Serialize(nodeset);
            f.flush();
        }
    }

    void
    ReplicatedStorage::set_identity(int id)
    {
        std::fstream s(fs::path(identity_info.path).string(),
                       std::ios::out | std::ios::binary);
        s << id;
        s.flush();
    }
}
<|endoftext|>


<commit_before>// $Id$
//
//  Copyright (C) 2002-2008 Greg Landrum and Rational Discovery LLC
//
//   @@ All Rights Reserved  @@
//
#include "SmilesWrite.h"
#include <GraphMol/RDKitBase.h>
#include <RDGeneral/types.h>
#include <GraphMol/Canon.h>
#include <boost/lexical_cast.hpp>
#include <sstream>
#include <map>
#include <list>

namespace RDKit{

  namespace SmilesWrite{
    const int atomicSmiles[] = {5,6,7,8,9,15,16,17,35,53,-1};
    bool inOrganicSubset(int atomicNumber){
      unsigned int idx=0;
      while( atomicSmiles[idx]<atomicNumber &&
             atomicSmiles[idx]!=-1){
        ++idx;
      }
      if(atomicSmiles[idx]==atomicNumber){
        return true;
      }
      return false;
    }

    std::string GetAtomSmiles(const Atom *atom,bool doKekule,const Bond *bondIn){
      PRECONDITION(atom,"bad atom");
      int i;
      static bool firstCall=true;
      static INT_VECT atomicSmilesVect;
      if(firstCall){
        i = 0;
        while(atomicSmiles[i] != -1){
          atomicSmilesVect.push_back(atomicSmiles[i]);
          i++;
        }
        firstCall = false;
      }
      std::stringstream res;
      int fc = atom->getFormalCharge();
      int num = atom->getAtomicNum();
      double massDiff=fabs(PeriodicTable::getTable()->getAtomicWeight(num) -
                           atom->getMass());

      bool needsBracket=false;
      std::string symb;
      symb = atom->getSymbol();
      if(inOrganicSubset(num)){
        // it's a member of the organic subset
        if(!doKekule && atom->getIsAromatic() && symb[0] < 'a') symb[0] -= ('A'-'a');

        // -----
        // figure out if we need to put a bracket around the atom,
        // the conditions for this are:
        //   - formal charge specified
        //   - the atom has a nonstandard valence
        //   - chirality present and writing isomeric smiles
        //   - non-default isotope and writing isomeric smiles
        const INT_VECT &defaultVs=PeriodicTable::getTable()->getValenceList(num);
        int totalValence= atom->getExplicitValence()+atom->getImplicitValence();
        bool nonStandard;
        nonStandard = std::find(defaultVs.begin(),defaultVs.end(),
                                totalValence)==defaultVs.end();
        // another type of "nonstandard" valence is an aromatic N with
        // explicit Hs indicated:
        if(num==7 && atom->getIsAromatic() && atom->getNumExplicitHs()){
          nonStandard=true;
        }

        if(fc || nonStandard){
          needsBracket=true;
        }
        if(atom->getOwningMol().hasProp("_doIsoSmiles")){
          if( atom->getChiralTag()!=Atom::CHI_UNSPECIFIED ){
            needsBracket = true;
          } else if(massDiff>0.01){
            needsBracket=true;
          }
        }
      } else {
        needsBracket = true;
      }
      if( needsBracket ) res << "[";

      if(massDiff>0.01 && atom->getOwningMol().hasProp("_doIsoSmiles")){
        int iMass=static_cast<int>(atom->getMass()+.1);
        res <<iMass;
      }
      res << symb;

      bool chiralityIncluded=false;
      if(atom->getOwningMol().hasProp("_doIsoSmiles") &&
         atom->getChiralTag()!=Atom::CHI_UNSPECIFIED ){
        INT_LIST trueOrder;
        atom->getProp("_TraversalBondIndexOrder",trueOrder);
#ifdef VERBOSE_CANON
        std::cout << "\tatom: " << atom->getIdx() << " | ";
        std::copy(trueOrder.begin(),trueOrder.end(),
                  std::ostream_iterator<int>(std::cout,", "));
        std::cout << std::endl;
        std::cout << "\t ---- | " ;
        ROMol::OEDGE_ITER beg,end;
        boost::tie(beg,end) = atom->getOwningMol().getAtomBonds(atom);
        ROMol::GRAPH_MOL_BOND_PMAP::type pMap = atom->getOwningMol().getBondPMap();
        while(beg!=end){
          std::cout <<pMap[*beg]->getIdx()<<", ";
          ++beg;
        }
        std::cout << std::endl;
#endif
        int nSwaps =  atom->getPerturbationOrder(trueOrder);

        if(atom->getDegree()==3){
          // Does the atom have a preceder in the original ordering?
          bool hasTruePrecedingAtom=false;
          ROMol::OEDGE_ITER beg,end;
          boost::tie(beg,end) = atom->getOwningMol().getAtomBonds(atom);
          ROMol::GRAPH_MOL_BOND_PMAP::type pMap = atom->getOwningMol().getBondPMap();
          while(beg!=end){
            Bond *nbrBond=pMap[*beg];
            unsigned int oIdx=nbrBond->getOtherAtomIdx(atom->getIdx());
            if(oIdx<atom->getIdx() && nbrBond->getBeginAtomIdx()==oIdx){
              hasTruePrecedingAtom=true;
              break;
            }
            ++beg;
          }

          if(hasTruePrecedingAtom^static_cast<bool>(bondIn)){
            // if we had a preceder and don't now, or vice versa,
            // we need another swap to reflect the H position
            ++nSwaps;
          }
        }
        std::string atStr="";
        switch(atom->getChiralTag()){
        case Atom::CHI_TETRAHEDRAL_CW:
          if(!(nSwaps%2))
            atStr = "@@";
          else
            atStr = "@";
          chiralityIncluded=true;
          break;
        case Atom::CHI_TETRAHEDRAL_CCW:
          if(!(nSwaps%2))
            atStr = "@";
          else
            atStr = "@@";
          chiralityIncluded=true;
          break;
        default:
          break;
        }
        res << atStr;
      }

      if(needsBracket){
        unsigned int totNumHs=atom->getTotalNumHs();
        if(totNumHs > 0){
          res << "H";
          if(totNumHs > 1) res << totNumHs;
        }
        if(fc > 0){
          res << "+";
          if(fc > 1) res << fc;
        } else if(fc < 0) {
          res << "-";
          if(fc < -1) res << -fc;
        }
        res << "]";
      }

      // If the atom has this property, the contained string will
      // be inserted directly in the SMILES:
      if(atom->hasProp("_supplementalSmilesLabel")){
        std::string label;
        atom->getProp("_supplementalSmilesLabel",label);
        res << label;
      }

      return res.str();
    }

    std::string GetBondSmiles(const Bond *bond,int atomToLeftIdx,bool doKekule){
      PRECONDITION(bond,"bad bond");
      if(atomToLeftIdx<0) atomToLeftIdx=bond->getBeginAtomIdx();

      std::stringstream res;
      bool aromatic=false;
      if( !doKekule &&
          (bond->getBondType() == Bond::SINGLE ||
           bond->getBondType() == Bond::DOUBLE ||
           bond->getBondType() == Bond::AROMATIC) ){
        Atom *a1,*a2;
        a1 = bond->getOwningMol().getAtomWithIdx(atomToLeftIdx);
        a2 = bond->getOwningMol().getAtomWithIdx(bond->getOtherAtomIdx(atomToLeftIdx));
        if(a1->getIsAromatic() && a2->getIsAromatic()) aromatic=true;
      }

      Bond::BondDir dir= bond->getBondDir();
      switch(bond->getBondType()){
      case Bond::SINGLE:
        if( dir != Bond::NONE && dir != Bond::UNKNOWN ){
          switch(dir){
          case Bond::ENDDOWNRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "\\";
            break;
          case Bond::ENDUPRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "/";
            break;
          default:
            break;
          }
        } else {
          // if the bond is marked as aromatic and the two atoms
          //  are aromatic, we need no marker (this arises in kekulized
          //  molecules).
          // FIX: we should be able to dump kekulized smiles
          //   currently this is possible by removing all
          //   isAromatic flags, but there should maybe be another way
          if( aromatic && !bond->getIsAromatic() ) res << "-";
        }
        break;
      case Bond::DOUBLE:
        // see note above
        if( !aromatic || !bond->getIsAromatic() ) res << "=";
        break;
      case Bond::TRIPLE: res << "#"; break;
      case Bond::AROMATIC:
        if ( dir != Bond::NONE && dir != Bond::UNKNOWN ){
          switch(dir){
          case Bond::ENDDOWNRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "\\";
            break;
          case Bond::ENDUPRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "/";
            break;
          default:
            break;
          }
        }
        if(!aromatic) res << ":";
        break;
      case Bond::DATIVE:
        if(atomToLeftIdx>=0 &&
           bond->getBeginAtomIdx()==static_cast<unsigned int>(atomToLeftIdx) ) res << ">";
        else res << "<";
        break;
      default:
        res << "?";
      }
      return res.str();
    }

    std::string FragmentSmilesConstruct(ROMol &mol,int atomIdx,
                                        std::vector<Canon::AtomColors> &colors,
                                        INT_VECT &ranks,bool doKekule){

      Canon::MolStack molStack;
      // try to prevent excessive reallocation
      molStack.reserve(mol.getNumAtoms()+
                       mol.getNumBonds());
      std::stringstream res;

      std::map<int,int> ringClosureMap;
      int ringIdx,closureVal;
      Canon::canonicalizeFragment(mol,atomIdx,colors,ranks,
                                  molStack);
      Bond *bond=0;
      for(Canon::MolStack::const_iterator msCI=molStack.begin();msCI!=molStack.end();msCI++){
        switch(msCI->type){
        case Canon::MOL_STACK_ATOM:
          //std::cout<<"\t\tAtom: "<<msCI->obj.atom->getIdx()<<std::endl;
          res << GetAtomSmiles(msCI->obj.atom,doKekule,bond);
          break;
        case Canon::MOL_STACK_BOND:
          bond = msCI->obj.bond;
          //std::cout<<"\t\tBond: "<<bond->getIdx()<<std::endl;
          res << GetBondSmiles(bond,msCI->number,doKekule);
          break;
        case Canon::MOL_STACK_RING:
          ringIdx = msCI->number;
          //std::cout<<"\t\tRing: "<<ringIdx;
          if(ringClosureMap.count(ringIdx)){
            // the index is already in the map ->
            //   we're closing a ring, so grab
            //   the index and then delete the value:
            closureVal = ringClosureMap[ringIdx];
            ringClosureMap.erase(ringIdx);
          } else {
            // we're opening a new ring, find the index for it:
            closureVal = 1;
            bool done=false;
            // EFF: there's got to be a more efficient way to do this
            while(!done){
              std::map<int,int>::iterator mapIt;
              for(mapIt=ringClosureMap.begin();
                  mapIt!=ringClosureMap.end();
                  mapIt++){
                if(mapIt->second==closureVal) break;
              }
              if(mapIt==ringClosureMap.end()){
                done=true;
              } else {
                closureVal+=1;
              }
            }
            ringClosureMap[ringIdx]=closureVal;
          }
          if(closureVal >= 10){
            res << "%";
          }
          //std::cout << " > " << closureVal <<std::endl;
          res << closureVal;
          break;
        case Canon::MOL_STACK_BRANCH_OPEN:
          res << "(";
          break;
        case Canon::MOL_STACK_BRANCH_CLOSE:
          res << ")";
          break;
        default:
          break;
        }
      }
      return res.str();
    }

  } // end of namespace SmilesWrite

  // NOTE: I did not forget the const here... Producing SMILES for
  // a molecule actually can change the molecule.  Specifically,
  // things like the directionality of bonds may be changed when
  // the molecule is canonicalized.
  // Odds are good that this may be one of those foot-shooting
  // decisions and I'm gonna want to smack myself for doing this,
  // but we'll try anyway.
  std::string MolToSmiles(ROMol &mol,bool doIsomericSmiles,
                          bool doKekule,int rootedAtAtom){
    PRECONDITION(rootedAtAtom<0||static_cast<unsigned int>(rootedAtAtom)<mol.getNumAtoms(),
                 "rootedAtomAtom must be less than the number of atoms");
    if(doIsomericSmiles){
      mol.setProp("_doIsoSmiles",1);
    } else if(mol.hasProp("_doIsoSmiles")){
      mol.clearProp("_doIsoSmiles");
    }

#if 0
    std::cout << "----------------------------" << std::endl;
    std::cout << "MolToSmiles:"<< std::endl;
    mol.debugMol(std::cout);
    std::cout << "----------------------------" << std::endl;
#endif
    std::string res;

    for(ROMol::AtomIterator atIt=mol.beginAtoms();atIt!=mol.endAtoms();atIt++){
      (*atIt)->updatePropertyCache();
    }

    unsigned int nAtoms=mol.getNumAtoms();
    INT_VECT ranks(nAtoms,-1);

    // clean up the chirality on any atom that is marked as chiral,
    // but that should not be:
    if(doIsomericSmiles){
      MolOps::assignAtomChiralCodes(mol,true);
      MolOps::rankAtoms(mol,ranks,ComprehensiveInvariants,
                        true,0,true);
    } else {
      MolOps::rankAtoms(mol,ranks);
    }
#ifdef VERBOSE_CANON
    for(unsigned int tmpI=0;tmpI<ranks.size();tmpI++){
      std::cout << tmpI << " " << ranks[tmpI] << " " << *(mol.getAtomWithIdx(tmpI)) << std::endl;
    }
#endif

    std::vector<Canon::AtomColors> colors(nAtoms,Canon::WHITE_NODE);
    std::vector<Canon::AtomColors>::iterator colorIt;
    colorIt = colors.begin();
    // loop to deal with the possibility that there might be disconnected fragments
    while(colorIt != colors.end()){
      int nextAtomIdx=-1;
      std::string subSmi;

      // find the next atom for a traverse
      if(rootedAtAtom>=0){
        nextAtomIdx=rootedAtAtom;
        rootedAtAtom=-1;
      } else {
        int nextRank = nAtoms+1;
        for(unsigned int i=0;i<nAtoms;i++){
          if( colors[i] == Canon::WHITE_NODE && ranks[i] < nextRank ){
            nextRank = ranks[i];
            nextAtomIdx = i;
          }
        }
      }
      CHECK_INVARIANT(nextAtomIdx>=0,"no start atom found");

      subSmi = SmilesWrite::FragmentSmilesConstruct(mol, nextAtomIdx, colors,
                                                    ranks,doKekule);

      res += subSmi;
      colorIt = std::find(colors.begin(),colors.end(),Canon::WHITE_NODE);
      if(colorIt != colors.end()){
        res += ".";
      }
    }

    return res;
  }
}
<commit_msg>make this a bit more robust to roundoff<commit_after>// $Id$
//
//  Copyright (C) 2002-2008 Greg Landrum and Rational Discovery LLC
//
//   @@ All Rights Reserved  @@
//
#include "SmilesWrite.h"
#include <GraphMol/RDKitBase.h>
#include <RDGeneral/types.h>
#include <GraphMol/Canon.h>
#include <boost/lexical_cast.hpp>
#include <sstream>
#include <map>
#include <list>

namespace RDKit{

  namespace SmilesWrite{
    const int atomicSmiles[] = {5,6,7,8,9,15,16,17,35,53,-1};
    bool inOrganicSubset(int atomicNumber){
      unsigned int idx=0;
      while( atomicSmiles[idx]<atomicNumber &&
             atomicSmiles[idx]!=-1){
        ++idx;
      }
      if(atomicSmiles[idx]==atomicNumber){
        return true;
      }
      return false;
    }

    std::string GetAtomSmiles(const Atom *atom,bool doKekule,const Bond *bondIn){
      PRECONDITION(atom,"bad atom");
      int i;
      static bool firstCall=true;
      static INT_VECT atomicSmilesVect;
      if(firstCall){
        i = 0;
        while(atomicSmiles[i] != -1){
          atomicSmilesVect.push_back(atomicSmiles[i]);
          i++;
        }
        firstCall = false;
      }
      std::stringstream res;
      int fc = atom->getFormalCharge();
      int num = atom->getAtomicNum();
      double massDiff=fabs(PeriodicTable::getTable()->getAtomicWeight(num) -
                           atom->getMass());

      bool needsBracket=false;
      std::string symb;
      symb = atom->getSymbol();
      if(inOrganicSubset(num)){
        // it's a member of the organic subset
        if(!doKekule && atom->getIsAromatic() && symb[0] < 'a') symb[0] -= ('A'-'a');

        // -----
        // figure out if we need to put a bracket around the atom,
        // the conditions for this are:
        //   - formal charge specified
        //   - the atom has a nonstandard valence
        //   - chirality present and writing isomeric smiles
        //   - non-default isotope and writing isomeric smiles
        const INT_VECT &defaultVs=PeriodicTable::getTable()->getValenceList(num);
        int totalValence= atom->getExplicitValence()+atom->getImplicitValence();
        bool nonStandard;
        nonStandard = std::find(defaultVs.begin(),defaultVs.end(),
                                totalValence)==defaultVs.end();
        // another type of "nonstandard" valence is an aromatic N with
        // explicit Hs indicated:
        if(num==7 && atom->getIsAromatic() && atom->getNumExplicitHs()){
          nonStandard=true;
        }

        if(fc || nonStandard){
          needsBracket=true;
        }
        if(atom->getOwningMol().hasProp("_doIsoSmiles")){
          if( atom->getChiralTag()!=Atom::CHI_UNSPECIFIED ){
            needsBracket = true;
          } else if(massDiff>0.1){
            needsBracket=true;
          }
        }
      } else {
        needsBracket = true;
      }
      if( needsBracket ) res << "[";

      if(massDiff>0.1 && atom->getOwningMol().hasProp("_doIsoSmiles")){
        int iMass=static_cast<int>(atom->getMass()+.1);
        res <<iMass;
      }
      res << symb;

      bool chiralityIncluded=false;
      if(atom->getOwningMol().hasProp("_doIsoSmiles") &&
         atom->getChiralTag()!=Atom::CHI_UNSPECIFIED ){
        INT_LIST trueOrder;
        atom->getProp("_TraversalBondIndexOrder",trueOrder);
#ifdef VERBOSE_CANON
        std::cout << "\tatom: " << atom->getIdx() << " | ";
        std::copy(trueOrder.begin(),trueOrder.end(),
                  std::ostream_iterator<int>(std::cout,", "));
        std::cout << std::endl;
        std::cout << "\t ---- | " ;
        ROMol::OEDGE_ITER beg,end;
        boost::tie(beg,end) = atom->getOwningMol().getAtomBonds(atom);
        ROMol::GRAPH_MOL_BOND_PMAP::type pMap = atom->getOwningMol().getBondPMap();
        while(beg!=end){
          std::cout <<pMap[*beg]->getIdx()<<", ";
          ++beg;
        }
        std::cout << std::endl;
#endif
        int nSwaps =  atom->getPerturbationOrder(trueOrder);

        if(atom->getDegree()==3){
          // Does the atom have a preceder in the original ordering?
          bool hasTruePrecedingAtom=false;
          ROMol::OEDGE_ITER beg,end;
          boost::tie(beg,end) = atom->getOwningMol().getAtomBonds(atom);
          ROMol::GRAPH_MOL_BOND_PMAP::type pMap = atom->getOwningMol().getBondPMap();
          while(beg!=end){
            Bond *nbrBond=pMap[*beg];
            unsigned int oIdx=nbrBond->getOtherAtomIdx(atom->getIdx());
            if(oIdx<atom->getIdx() && nbrBond->getBeginAtomIdx()==oIdx){
              hasTruePrecedingAtom=true;
              break;
            }
            ++beg;
          }

          if(hasTruePrecedingAtom^static_cast<bool>(bondIn)){
            // if we had a preceder and don't now, or vice versa,
            // we need another swap to reflect the H position
            ++nSwaps;
          }
        }
        std::string atStr="";
        switch(atom->getChiralTag()){
        case Atom::CHI_TETRAHEDRAL_CW:
          if(!(nSwaps%2))
            atStr = "@@";
          else
            atStr = "@";
          chiralityIncluded=true;
          break;
        case Atom::CHI_TETRAHEDRAL_CCW:
          if(!(nSwaps%2))
            atStr = "@";
          else
            atStr = "@@";
          chiralityIncluded=true;
          break;
        default:
          break;
        }
        res << atStr;
      }

      if(needsBracket){
        unsigned int totNumHs=atom->getTotalNumHs();
        if(totNumHs > 0){
          res << "H";
          if(totNumHs > 1) res << totNumHs;
        }
        if(fc > 0){
          res << "+";
          if(fc > 1) res << fc;
        } else if(fc < 0) {
          res << "-";
          if(fc < -1) res << -fc;
        }
        res << "]";
      }

      // If the atom has this property, the contained string will
      // be inserted directly in the SMILES:
      if(atom->hasProp("_supplementalSmilesLabel")){
        std::string label;
        atom->getProp("_supplementalSmilesLabel",label);
        res << label;
      }

      return res.str();
    }

    std::string GetBondSmiles(const Bond *bond,int atomToLeftIdx,bool doKekule){
      PRECONDITION(bond,"bad bond");
      if(atomToLeftIdx<0) atomToLeftIdx=bond->getBeginAtomIdx();

      std::stringstream res;
      bool aromatic=false;
      if( !doKekule &&
          (bond->getBondType() == Bond::SINGLE ||
           bond->getBondType() == Bond::DOUBLE ||
           bond->getBondType() == Bond::AROMATIC) ){
        Atom *a1,*a2;
        a1 = bond->getOwningMol().getAtomWithIdx(atomToLeftIdx);
        a2 = bond->getOwningMol().getAtomWithIdx(bond->getOtherAtomIdx(atomToLeftIdx));
        if(a1->getIsAromatic() && a2->getIsAromatic()) aromatic=true;
      }

      Bond::BondDir dir= bond->getBondDir();
      switch(bond->getBondType()){
      case Bond::SINGLE:
        if( dir != Bond::NONE && dir != Bond::UNKNOWN ){
          switch(dir){
          case Bond::ENDDOWNRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "\\";
            break;
          case Bond::ENDUPRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "/";
            break;
          default:
            break;
          }
        } else {
          // if the bond is marked as aromatic and the two atoms
          //  are aromatic, we need no marker (this arises in kekulized
          //  molecules).
          // FIX: we should be able to dump kekulized smiles
          //   currently this is possible by removing all
          //   isAromatic flags, but there should maybe be another way
          if( aromatic && !bond->getIsAromatic() ) res << "-";
        }
        break;
      case Bond::DOUBLE:
        // see note above
        if( !aromatic || !bond->getIsAromatic() ) res << "=";
        break;
      case Bond::TRIPLE: res << "#"; break;
      case Bond::AROMATIC:
        if ( dir != Bond::NONE && dir != Bond::UNKNOWN ){
          switch(dir){
          case Bond::ENDDOWNRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "\\";
            break;
          case Bond::ENDUPRIGHT:
            if(bond->getOwningMol().hasProp("_doIsoSmiles"))  res << "/";
            break;
          default:
            break;
          }
        }
        if(!aromatic) res << ":";
        break;
      case Bond::DATIVE:
        if(atomToLeftIdx>=0 &&
           bond->getBeginAtomIdx()==static_cast<unsigned int>(atomToLeftIdx) ) res << ">";
        else res << "<";
        break;
      default:
        res << "?";
      }
      return res.str();
    }

    std::string FragmentSmilesConstruct(ROMol &mol,int atomIdx,
                                        std::vector<Canon::AtomColors> &colors,
                                        INT_VECT &ranks,bool doKekule){

      Canon::MolStack molStack;
      // try to prevent excessive reallocation
      molStack.reserve(mol.getNumAtoms()+
                       mol.getNumBonds());
      std::stringstream res;

      std::map<int,int> ringClosureMap;
      int ringIdx,closureVal;
      Canon::canonicalizeFragment(mol,atomIdx,colors,ranks,
                                  molStack);
      Bond *bond=0;
      for(Canon::MolStack::const_iterator msCI=molStack.begin();msCI!=molStack.end();msCI++){
        switch(msCI->type){
        case Canon::MOL_STACK_ATOM:
          //std::cout<<"\t\tAtom: "<<msCI->obj.atom->getIdx()<<std::endl;
          res << GetAtomSmiles(msCI->obj.atom,doKekule,bond);
          break;
        case Canon::MOL_STACK_BOND:
          bond = msCI->obj.bond;
          //std::cout<<"\t\tBond: "<<bond->getIdx()<<std::endl;
          res << GetBondSmiles(bond,msCI->number,doKekule);
          break;
        case Canon::MOL_STACK_RING:
          ringIdx = msCI->number;
          //std::cout<<"\t\tRing: "<<ringIdx;
          if(ringClosureMap.count(ringIdx)){
            // the index is already in the map ->
            //   we're closing a ring, so grab
            //   the index and then delete the value:
            closureVal = ringClosureMap[ringIdx];
            ringClosureMap.erase(ringIdx);
          } else {
            // we're opening a new ring, find the index for it:
            closureVal = 1;
            bool done=false;
            // EFF: there's got to be a more efficient way to do this
            while(!done){
              std::map<int,int>::iterator mapIt;
              for(mapIt=ringClosureMap.begin();
                  mapIt!=ringClosureMap.end();
                  mapIt++){
                if(mapIt->second==closureVal) break;
              }
              if(mapIt==ringClosureMap.end()){
                done=true;
              } else {
                closureVal+=1;
              }
            }
            ringClosureMap[ringIdx]=closureVal;
          }
          if(closureVal >= 10){
            res << "%";
          }
          //std::cout << " > " << closureVal <<std::endl;
          res << closureVal;
          break;
        case Canon::MOL_STACK_BRANCH_OPEN:
          res << "(";
          break;
        case Canon::MOL_STACK_BRANCH_CLOSE:
          res << ")";
          break;
        default:
          break;
        }
      }
      return res.str();
    }

  } // end of namespace SmilesWrite

  // NOTE: I did not forget the const here... Producing SMILES for
  // a molecule actually can change the molecule.  Specifically,
  // things like the directionality of bonds may be changed when
  // the molecule is canonicalized.
  // Odds are good that this may be one of those foot-shooting
  // decisions and I'm gonna want to smack myself for doing this,
  // but we'll try anyway.
  std::string MolToSmiles(ROMol &mol,bool doIsomericSmiles,
                          bool doKekule,int rootedAtAtom){
    PRECONDITION(rootedAtAtom<0||static_cast<unsigned int>(rootedAtAtom)<mol.getNumAtoms(),
                 "rootedAtomAtom must be less than the number of atoms");
    if(doIsomericSmiles){
      mol.setProp("_doIsoSmiles",1);
    } else if(mol.hasProp("_doIsoSmiles")){
      mol.clearProp("_doIsoSmiles");
    }

#if 0
    std::cout << "----------------------------" << std::endl;
    std::cout << "MolToSmiles:"<< std::endl;
    mol.debugMol(std::cout);
    std::cout << "----------------------------" << std::endl;
#endif
    std::string res;

    for(ROMol::AtomIterator atIt=mol.beginAtoms();atIt!=mol.endAtoms();atIt++){
      (*atIt)->updatePropertyCache();
    }

    unsigned int nAtoms=mol.getNumAtoms();
    INT_VECT ranks(nAtoms,-1);

    // clean up the chirality on any atom that is marked as chiral,
    // but that should not be:
    if(doIsomericSmiles){
      MolOps::assignAtomChiralCodes(mol,true);
      MolOps::rankAtoms(mol,ranks,ComprehensiveInvariants,
                        true,0,true);
    } else {
      MolOps::rankAtoms(mol,ranks);
    }
#ifdef VERBOSE_CANON
    for(unsigned int tmpI=0;tmpI<ranks.size();tmpI++){
      std::cout << tmpI << " " << ranks[tmpI] << " " << *(mol.getAtomWithIdx(tmpI)) << std::endl;
    }
#endif

    std::vector<Canon::AtomColors> colors(nAtoms,Canon::WHITE_NODE);
    std::vector<Canon::AtomColors>::iterator colorIt;
    colorIt = colors.begin();
    // loop to deal with the possibility that there might be disconnected fragments
    while(colorIt != colors.end()){
      int nextAtomIdx=-1;
      std::string subSmi;

      // find the next atom for a traverse
      if(rootedAtAtom>=0){
        nextAtomIdx=rootedAtAtom;
        rootedAtAtom=-1;
      } else {
        int nextRank = nAtoms+1;
        for(unsigned int i=0;i<nAtoms;i++){
          if( colors[i] == Canon::WHITE_NODE && ranks[i] < nextRank ){
            nextRank = ranks[i];
            nextAtomIdx = i;
          }
        }
      }
      CHECK_INVARIANT(nextAtomIdx>=0,"no start atom found");

      subSmi = SmilesWrite::FragmentSmilesConstruct(mol, nextAtomIdx, colors,
                                                    ranks,doKekule);

      res += subSmi;
      colorIt = std::find(colors.begin(),colors.end(),Canon::WHITE_NODE);
      if(colorIt != colors.end()){
        res += ".";
      }
    }

    return res;
  }
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_getecid.C $        */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_getecid.C
///
/// @brief Get ECID string from target using SCOM
//------------------------------------------------------------------------------
// *HWP HW Owner        : Abhishek Agarwal <abagarw8@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : sunil kumar <skumar8j@in.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 2
// *HWP Consumed by     : SBE
//------------------------------------------------------------------------------

//## auto_generated
#include "p9_getecid.H"
//## auto_generated
#include "p9_const_common.H"

#include <p9_perv_scom_addresses.H>
#include <p9_perv_scom_addresses_fld.H>
#include <p9_misc_scom_addresses.H>
#include <p9_misc_scom_addresses_fld.H>
#include <p9_const_common.H>

enum P9_SBE_COMMON_Private_Constants
{
    OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT = 1 // OTPROM mode register MODE_ECC_ENABLE field/bit definitions
};

fapi2::ReturnCode p9_getecid(const
                             fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip, fapi2::variable_buffer& o_fuseString)
{
    uint64_t attr_data[2];
    bool secure_mode = false;
    fapi2::buffer<uint64_t> l_ecid_part0_data64 = 0;
    fapi2::buffer<uint64_t> l_ecid_part1_data64 = 0;
    fapi2::buffer<uint64_t> l_ecid_part1_data48 = 0;
    fapi2::buffer<uint64_t> l_local = 0;
    FAPI_INF("Entering ...");

    FAPI_DBG("determine if security is enabled");
    fapi2::buffer<uint64_t> l_data64;
    FAPI_TRY(fapi2::getScom(i_target_chip, PERV_CBS_CS_SCOM, l_data64));
    secure_mode = l_data64.getBit<4>();

    FAPI_DBG("clear ECC enable before reading ECID data (read-modify-write OTPROM Mode register), insecure mode only");

    if (!secure_mode)
    {
        fapi2::buffer<uint64_t> l_data64;
        FAPI_TRY(fapi2::getScom(i_target_chip, PU_MODE_REGISTER, l_data64));
        l_data64.clearBit<OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT>();
        FAPI_TRY(fapi2::putScom(i_target_chip, PU_MODE_REGISTER, l_data64));
    }

    FAPI_DBG("extract and manipulate ECID data");
    FAPI_TRY(fapi2::getScom(i_target_chip, PU_OTPROM0_ECID_PART0_REGISTER, l_ecid_part0_data64));
    FAPI_TRY(fapi2::getScom(i_target_chip, PU_OTPROM0_ECID_PART1_REGISTER, l_ecid_part1_data64));
    l_ecid_part0_data64.reverse();
    l_ecid_part1_data64.reverse();

    l_local.insertFromRight<0, 64>(l_ecid_part0_data64);
    attr_data[0] = l_local;
    l_local.insertFromRight<0, 64>(l_ecid_part1_data64);
    attr_data[1] = l_local;
    o_fuseString.insert(l_ecid_part0_data64, 0, 64, 0);
    l_ecid_part1_data64.extractToRight<0, 48>(l_ecid_part1_data48);
    o_fuseString.insert(l_ecid_part1_data48, 64, 48, 0);

    FAPI_DBG("push fuse string into attribute");
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_ECID, i_target_chip, attr_data));

    FAPI_DBG("restore ECC enable setting (insecure mode only)");

    if (!secure_mode)
    {
        fapi2::buffer<uint64_t> l_data64;
        FAPI_TRY(fapi2::getScom(i_target_chip, PU_MODE_REGISTER, l_data64));
        l_data64.setBit<OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT>();
        FAPI_TRY(fapi2::putScom(i_target_chip, PU_MODE_REGISTER, l_data64));
    }

    FAPI_INF("Exiting ...");

//    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    return fapi2::current_err;

}
<commit_msg>Level 2 HWP p9_getecid<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_getecid.C $        */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_getecid.C
///
/// @brief Get ECID string from target using SCOM
//------------------------------------------------------------------------------
// *HWP HW Owner        : Abhishek Agarwal <abagarw8@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : sunil kumar <skumar8j@in.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 2
// *HWP Consumed by     : SBE
//------------------------------------------------------------------------------

//## auto_generated
#include "p9_getecid.H"
//## auto_generated
#include "p9_const_common.H"

#include <p9_perv_scom_addresses.H>
#include <p9_perv_scom_addresses_fld.H>
#include <p9_misc_scom_addresses.H>
#include <p9_misc_scom_addresses_fld.H>
#include <p9_const_common.H>

enum P9_SBE_COMMON_Private_Constants
{
    OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT = 1 // OTPROM mode register MODE_ECC_ENABLE field/bit definitions
};

fapi2::ReturnCode p9_getecid(const
                             fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip, fapi2::variable_buffer& o_fuseString)
{
    uint64_t attr_data[2];
    bool secure_mode = false;
    fapi2::buffer<uint64_t> l_ecid_part0_data64 = 0;
    fapi2::buffer<uint64_t> l_ecid_part1_data64 = 0;
    FAPI_INF("Entering ...");

    FAPI_DBG("determine if security is enabled");
    fapi2::buffer<uint64_t> l_data64;
    FAPI_TRY(fapi2::getScom(i_target_chip, PERV_CBS_CS_SCOM, l_data64));
    secure_mode = l_data64.getBit<4>();

    FAPI_DBG("clear ECC enable before reading ECID data (read-modify-write OTPROM Mode register), insecure mode only");

    if (!secure_mode)
    {
        fapi2::buffer<uint64_t> l_data64;
        FAPI_TRY(fapi2::getScom(i_target_chip, PU_MODE_REGISTER, l_data64));
        l_data64.clearBit<OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT>();
        FAPI_TRY(fapi2::putScom(i_target_chip, PU_MODE_REGISTER, l_data64));
    }

    FAPI_DBG("extract and manipulate ECID data");
    FAPI_TRY(fapi2::getScom(i_target_chip, PU_OTPROM0_ECID_PART0_REGISTER, l_ecid_part0_data64));
    FAPI_TRY(fapi2::getScom(i_target_chip, PU_OTPROM0_ECID_PART1_REGISTER, l_ecid_part1_data64));

    l_ecid_part0_data64.reverse();
    l_ecid_part1_data64.reverse();

    attr_data[0] = l_ecid_part0_data64();
    attr_data[1] = l_ecid_part1_data64();

    FAPI_TRY(o_fuseString.insert(l_ecid_part0_data64(), 0, 64));

    FAPI_TRY(o_fuseString.insert(l_ecid_part1_data64(), 64, 48));

    FAPI_DBG("push fuse string into attribute");

    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_ECID, i_target_chip, attr_data));

    FAPI_DBG("restore ECC enable setting (insecure mode only)");

    if (!secure_mode)
    {
        fapi2::buffer<uint64_t> l_data64;
        FAPI_TRY(fapi2::getScom(i_target_chip, PU_MODE_REGISTER, l_data64));
        l_data64.setBit<OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT>();
        FAPI_TRY(fapi2::putScom(i_target_chip, PU_MODE_REGISTER, l_data64));
    }

    FAPI_INF("Exiting ...");

//    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    return fapi2::current_err;

}
<|endoftext|>


<commit_before>#include "OI.h"
#include "RobotMap.h"
#include "ControlIntakeHorizontal.h"
#include "Subsystems/IntakeHorizontal.h"
#include "Misc/ToggleClass.h"

#include <math.h>

ControlIntakeHorizontal::ControlIntakeHorizontal()
{
	Requires(IntakeHorizontal::GetInstance());
	IntakeArmPositionOut = new Toggle<bool>(false,true);
}

// Called just before this Command runs the first time
void ControlIntakeHorizontal::Initialize()
{
	IntakeHorizontal::GetInstance()->Actuate(false);
}

// Called repeatedly when this Command is scheduled to run
void ControlIntakeHorizontal::Execute()
{
	OI* oi = OI::GetInstance();

	//Toggles actuator position on button press
	IntakeHorizontal::GetInstance()->Actuate(IntakeArmPositionOut->toggleStatusOnEdgeChange(fabs(oi->gamepad->GetRawAxis(AXS_INTAKEHORIZONTAL) > 0.1)));
}

// Make this return true when this Command no longer needs to run execute()
bool ControlIntakeHorizontal::IsFinished()
{
	return false;
}

// Called once after isFinished returns true
void ControlIntakeHorizontal::End()
{
	IntakeHorizontal::GetInstance()->Actuate(false);
}

// Called when another command which requires one or more of the same
// subsystems is scheduled to run
void ControlIntakeHorizontal::Interrupted()
{

}
<commit_msg>Added changes for horizontal<commit_after>#include "OI.h"
#include "RobotMap.h"
#include "ControlIntakeHorizontal.h"
#include "Subsystems/IntakeHorizontal.h"
#include "Misc/ToggleClass.h"

#include <math.h>

ControlIntakeHorizontal::ControlIntakeHorizontal()
{
	Requires(IntakeHorizontal::GetInstance());
	IntakeArmPositionOut = new Toggle<bool>(false,true);
}

// Called just before this Command runs the first time
void ControlIntakeHorizontal::Initialize()
{
	IntakeHorizontal::GetInstance()->Actuate(false);

	IntakeArmPositionOut->setStatus(false);
}

// Called repeatedly when this Command is scheduled to run
void ControlIntakeHorizontal::Execute()
{
	OI* oi = OI::GetInstance();

	//Toggles actuator position on button press
	IntakeHorizontal::GetInstance()->Actuate(IntakeArmPositionOut->toggleStatusOnEdgeChange(fabs(oi->gamepad->GetRawAxis(AXS_INTAKEHORIZONTAL) > 0.1)));
}

// Make this return true when this Command no longer needs to run execute()
bool ControlIntakeHorizontal::IsFinished()
{
	return false;
}

// Called once after isFinished returns true
void ControlIntakeHorizontal::End()
{
	IntakeHorizontal::GetInstance()->Actuate(false);
}

// Called when another command which requires one or more of the same
// subsystems is scheduled to run
void ControlIntakeHorizontal::Interrupted()
{

}
<|endoftext|>