<commit_before>/*
    kncollectionview.cpp

    KNode, the KDE newsreader
    Copyright (c) 2004 Volker Krause <volker.krause@rwth-aachen.de>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, US
*/

#include <qcursor.h>
#include <qheader.h>

#include <kiconloader.h>
#include <klistview.h>
#include <klocale.h>
#include <kpopupmenu.h>

#include "knglobals.h"
#include "knconfig.h"
#include "knconfigmanager.h"
#include "knnntpaccount.h"
#include "knaccountmanager.h"
#include "kngroup.h"
#include "kngroupmanager.h"
#include "knfolder.h"
#include "knfoldermanager.h"
#include "headerview.h"
#include "kncollectionview.h"
#include "kncollectionviewitem.h"

KNCollectionView::KNCollectionView(QWidget *parent, const char* name) :
  KFolderTree(parent, name),
  mActiveItem( 0 ),
  mPopup( 0 )
{
  setDragEnabled(true);
  addAcceptableDropMimetype("x-knode-drag/article", false);
  addAcceptableDropMimetype("x-knode-drag/folder", true);
  addColumn(i18n("Name"),162);
  setDropHighlighter(true);

  // popup menu to enable/disable unread and total columns
  header()->setClickEnabled( true );
  header()->installEventFilter( this );
  mPopup = new KPopupMenu( this );
  mPopup->insertTitle( i18n("View Columns") );
  mPopup->setCheckable( true );
  mUnreadPop = mPopup->insertItem( i18n("Unread Column"), this, SLOT(toggleUnreadColumn()) );
  mTotalPop = mPopup->insertItem( i18n("Total Column"), this, SLOT(toggleTotalColumn()) );

  // add unread and total columns if necessary
  readConfig();

  // load accounts and folders
  reloadAccounts();
  reloadFolders();

  // connect to the account manager
  KNAccountManager* am = knGlobals.accountManager();
  connect(am, SIGNAL(accountAdded(KNNntpAccount*)), SLOT(addAccount(KNNntpAccount*)));
  connect(am, SIGNAL(accountRemoved(KNNntpAccount*)), SLOT(removeAccount(KNNntpAccount*)));
  connect(am, SIGNAL(accountModified(KNNntpAccount*)), SLOT(updateAccount(KNNntpAccount*)));

  // connect to the group manager
  KNGroupManager* gm = knGlobals.groupManager();
  connect(gm, SIGNAL(groupAdded(KNGroup*)), SLOT(addGroup(KNGroup*)));
  connect(gm, SIGNAL(groupRemoved(KNGroup*)), SLOT(removeGroup(KNGroup*)));
  connect(gm, SIGNAL(groupUpdated(KNGroup*)), SLOT(updateGroup(KNGroup*)));

  // connect to the folder manager
  KNFolderManager* fm = knGlobals.folderManager();
  connect(fm, SIGNAL(folderAdded(KNFolder*)), SLOT(addPendingFolders()));
  connect(fm, SIGNAL(folderRemoved(KNFolder*)), SLOT(removeFolder(KNFolder*)));
  connect(fm, SIGNAL(folderActivated(KNFolder*)), SLOT(activateFolder(KNFolder*)));

  installEventFilter(this);
}

KNCollectionView::~KNCollectionView()
{
  writeConfig();
}

void KNCollectionView::readConfig()
{
  KConfig *conf = knGlobals.config();
  conf->setGroup( "GroupView" );

  // execute the listview layout stuff only once
  static bool initDone = false;
  if (!initDone) {
    initDone = true;
    const int unreadColumn = conf->readNumEntry("UnreadColumn", 1);
    const int totalColumn = conf->readNumEntry("TotalColumn", 2);

    // we need to _activate_ them in the correct order
    // this is ugly because we can't use header()->moveSection
    // but otherwise the restoreLayout doesn't know that to do
    if (unreadColumn != -1 && unreadColumn < totalColumn)
      addUnreadColumn( i18n("Unread"), 48 );
    if (totalColumn != -1)
      addTotalColumn( i18n("Total"), 36 );
    if (unreadColumn != -1 && unreadColumn > totalColumn)
      addUnreadColumn( i18n("Unread"), 48 );
    updatePopup();

    restoreLayout( knGlobals.config(), "GroupView" );
  }

  // font & color settings
  KNConfig::Appearance *app = knGlobals.configManager()->appearance();
  setFont( app->groupListFont() );

  QPalette p = palette();
  p.setColor( QColorGroup::Base, app->backgroundColor() );
  p.setColor( QColorGroup::Text, app->textColor() );
  setPalette( p );
  setAlternateBackground( app->backgroundColor() );
  // FIXME: make this configurable
  mPaintInfo.colUnread = QColor( "blue" );
  mPaintInfo.colFore = app->textColor();
  mPaintInfo.colBack = app->backgroundColor();
}

void KNCollectionView::writeConfig()
{
  KConfig *conf = knGlobals.config();
  conf->setGroup( "GroupView" );
  saveLayout( knGlobals.config(), "GroupView" );
  conf->writeEntry( "UnreadColumn", unreadIndex() );
  conf->writeEntry( "TotalColumn", totalIndex() );
}

void KNCollectionView::addAccount(KNNntpAccount *a)
{
  // add account item
  KNCollectionViewItem* it = new KNCollectionViewItem(this, KFolderTreeItem::News);
  a->setListItem(it);
  it->setOpen(a->wasOpen());

  // add groups for this account
  QPtrList<KNGroup> groups;
  groups.setAutoDelete(false);
  knGlobals.groupManager()->getGroupsOfAccount(a, &groups);
  for(KNGroup *g = groups.first(); g; g = groups.next()) {
    KNCollectionViewItem *gitem = new KNCollectionViewItem(it, KFolderTreeItem::News);
    g->setListItem(gitem);
    g->updateListItem();
  }
}

void KNCollectionView::removeAccount(KNNntpAccount *a)
{
  if(!a->listItem())
    return;
  KNCollectionViewItem *child = 0, *aitem = a->listItem();
  while((child = static_cast<KNCollectionViewItem*>(aitem->firstChild())))
    removeGroup(static_cast<KNGroup*>(child->coll));
  delete aitem;
  a->setListItem(0);
}

void KNCollectionView::updateAccount(KNNntpAccount *a)
{
  a->updateListItem();
}

void KNCollectionView::reloadAccounts()
{
  KNAccountManager* am = knGlobals.accountManager();
  for(KNNntpAccount *a = am->first(); a; a = am->next()) {
    removeAccount(a);
    addAccount(a);
  }
}

void KNCollectionView::addGroup(KNGroup *g)
{
  if (!g->account()->listItem())
    return;

  KNCollectionViewItem *gitem =
      new KNCollectionViewItem( g->account()->listItem(), KFolderTreeItem::News );
  g->setListItem(gitem);
  updateGroup(g);
}

void KNCollectionView::removeGroup(KNGroup *g)
{
  if (!g->listItem())
    return;

  delete g->listItem();
  g->setListItem(0);
}

void KNCollectionView::updateGroup(KNGroup *g)
{
  g->updateListItem();
}

void KNCollectionView::addFolder(KNFolder *f)
{
  KNCollectionViewItem *it;

  if (!f->parent()) {
    // root folder
    it = new KNCollectionViewItem(this, KFolderTreeItem::Local);
  } else {
    // make sure the parent folder has already been added
    if (!f->parent()->listItem())
      addFolder( static_cast<KNFolder*>(f->parent()) );
    // handle special folders
    KFolderTreeItem::Type type = KFolderTreeItem::Other;
    switch ( f->id() ) {
      case 1:
        type = KFolderTreeItem::Drafts; break;
      case 2:
        type = KFolderTreeItem::Outbox; break;
      case 3:
        type = KFolderTreeItem::SentMail; break;
    }
    it = new KNCollectionViewItem( f->parent()->listItem(), KFolderTreeItem::Local, type );
  }
  f->setListItem( it );
  updateFolder( f );
}

void KNCollectionView::removeFolder(KNFolder* f)
{
  if(!f->listItem())
    return;
  KNCollectionViewItem *child = 0, *it = f->listItem();
  while((child = static_cast<KNCollectionViewItem*>(it->firstChild())))
    removeFolder(static_cast<KNFolder*>(child->coll));
  delete f->listItem();
  f->setListItem(0);
}

void KNCollectionView::reloadFolders()
{
  // remove existing folder items
  removeFolder(knGlobals.folderManager()->root());

  // add folder items
  addPendingFolders();
}

void KNCollectionView::addPendingFolders()
{
  QPtrList<KNFolder> folders = knGlobals.folderManager()->folders();
  for(KNFolder *f = folders.first(); f; f = folders.next())
    if(!f->listItem())
      addFolder(f);
  // now open the folders if they were open in the last session
  for(KNFolder *f = folders.first(); f; f = folders.next())
    if (f->listItem())
      f->listItem()->setOpen(f->wasOpen());
}

void KNCollectionView::activateFolder(KNFolder* f)
{
  if(f->listItem())
    setActive( f->listItem() );
}

void KNCollectionView::updateFolder(KNFolder* f)
{
  f->updateListItem();
}

void KNCollectionView::reload()
{
  reloadAccounts();
  reloadFolders();
}

void KNCollectionView::setActive( QListViewItem *i )
{
  if (!i || mActiveItem == i)
    return;

  clearSelection();
  setSelected( i, true );
  setCurrentItem( i );
  mActiveItem = i;
  emit( selectionChanged( i ) );
}

void KNCollectionView::nextGroup()
{
  incCurrentFolder();
  setActive( currentItem() );
}

void KNCollectionView::prevGroup()
{
  decCurrentFolder();
  setActive( currentItem() );
}

void KNCollectionView::decCurrentFolder()
{
  QListViewItemIterator it( currentItem() );
  --it;
  KFolderTreeItem* fti = static_cast<KFolderTreeItem*>(it.current());
  if (fti) {
    ensureItemVisible( fti );
    setFocus();
    setCurrentItem( fti );
  }
}

void KNCollectionView::incCurrentFolder()
{
  QListViewItemIterator it( currentItem() );
  ++it;
  KFolderTreeItem* fti = static_cast<KFolderTreeItem*>(it.current());
  if (fti) {
    ensureItemVisible( fti );
    setFocus();
    setCurrentItem( fti );
  }
}

void KNCollectionView::selectCurrentFolder()
{
  KFolderTreeItem* fti = static_cast<KFolderTreeItem*>( currentItem() );
  if (fti) {
    ensureItemVisible( fti );
    setActive( fti );
  }
}

QDragObject* KNCollectionView::dragObject()
{
  KFolderTreeItem *item = static_cast<KFolderTreeItem*>
      (itemAt(viewport()->mapFromGlobal(QCursor::pos())));
  if (item->protocol() == KFolderTreeItem::Local && item->type() == KFolderTreeItem::Other) {
    QDragObject *d = new QStoredDrag( "x-knode-drag/folder", viewport() );
    d->setPixmap( SmallIcon("folder") );
    return d;
  }
  return 0;
}

void KNCollectionView::contentsDropEvent( QDropEvent *e )
{
  cleanItemHighlighter(); // necessary since we overwrite KListView::contentsDropEvent()
  QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
  KNCollectionViewItem *fti = static_cast<KNCollectionViewItem*>(item);
  if (fti && (fti->coll) && acceptDrag(e)) {
    emit folderDrop( e, fti );
    e->accept( true );
  }
  else
    e->accept( false );
}

void KNCollectionView::toggleUnreadColumn()
{
  if ( isUnreadActive() )
    removeUnreadColumn();
  else
    addUnreadColumn( i18n("Unread"), 48 );
  mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
  reload();
}

void KNCollectionView::toggleTotalColumn()
{
  if ( isTotalActive() )
    removeTotalColumn();
  else
    addTotalColumn( i18n("Total"), 36 );
  mPopup->setItemChecked( mTotalPop, isTotalActive() );
  reload();
}

void KNCollectionView::updatePopup() const
{
  mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
  mPopup->setItemChecked( mTotalPop, isTotalActive() );
}

bool KNCollectionView::eventFilter(QObject *o, QEvent *e)
{
  if ((e->type() == QEvent::KeyPress) && (static_cast<QKeyEvent*>(e)->key() == Key_Tab)) {
    emit(focusChangeRequest(this));
    if (!hasFocus())  // focusChangeRequest was successful
      return true;
  }

  // header popup menu
  if ( e->type() == QEvent::MouseButtonPress &&
       static_cast<QMouseEvent*>(e)->button() == RightButton &&
       o->isA("QHeader") )
  {
    mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
    return true;
  }

  return KFolderTree::eventFilter(o, e);
}

void KNCollectionView::focusInEvent(QFocusEvent *e)
{
  QListView::focusInEvent(e);
  emit focusChanged(e);
}

void KNCollectionView::focusOutEvent(QFocusEvent *e)
{
  QListView::focusOutEvent(e);
  emit focusChanged(e);
}

#include "kncollectionview.moc"
<commit_msg>Fix drag&drop crash in the folder tree.<commit_after>/*
    kncollectionview.cpp

    KNode, the KDE newsreader
    Copyright (c) 2004 Volker Krause <volker.krause@rwth-aachen.de>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, US
*/

#include <qcursor.h>
#include <qheader.h>

#include <kiconloader.h>
#include <klistview.h>
#include <klocale.h>
#include <kpopupmenu.h>

#include "knglobals.h"
#include "knconfig.h"
#include "knconfigmanager.h"
#include "knnntpaccount.h"
#include "knaccountmanager.h"
#include "kngroup.h"
#include "kngroupmanager.h"
#include "knfolder.h"
#include "knfoldermanager.h"
#include "headerview.h"
#include "kncollectionview.h"
#include "kncollectionviewitem.h"

KNCollectionView::KNCollectionView(QWidget *parent, const char* name) :
  KFolderTree(parent, name),
  mActiveItem( 0 ),
  mPopup( 0 )
{
  setDragEnabled(true);
  addAcceptableDropMimetype("x-knode-drag/article", false);
  addAcceptableDropMimetype("x-knode-drag/folder", true);
  addColumn(i18n("Name"),162);
  setDropHighlighter(true);

  // popup menu to enable/disable unread and total columns
  header()->setClickEnabled( true );
  header()->installEventFilter( this );
  mPopup = new KPopupMenu( this );
  mPopup->insertTitle( i18n("View Columns") );
  mPopup->setCheckable( true );
  mUnreadPop = mPopup->insertItem( i18n("Unread Column"), this, SLOT(toggleUnreadColumn()) );
  mTotalPop = mPopup->insertItem( i18n("Total Column"), this, SLOT(toggleTotalColumn()) );

  // add unread and total columns if necessary
  readConfig();

  // load accounts and folders
  reloadAccounts();
  reloadFolders();

  // connect to the account manager
  KNAccountManager* am = knGlobals.accountManager();
  connect(am, SIGNAL(accountAdded(KNNntpAccount*)), SLOT(addAccount(KNNntpAccount*)));
  connect(am, SIGNAL(accountRemoved(KNNntpAccount*)), SLOT(removeAccount(KNNntpAccount*)));
  connect(am, SIGNAL(accountModified(KNNntpAccount*)), SLOT(updateAccount(KNNntpAccount*)));

  // connect to the group manager
  KNGroupManager* gm = knGlobals.groupManager();
  connect(gm, SIGNAL(groupAdded(KNGroup*)), SLOT(addGroup(KNGroup*)));
  connect(gm, SIGNAL(groupRemoved(KNGroup*)), SLOT(removeGroup(KNGroup*)));
  connect(gm, SIGNAL(groupUpdated(KNGroup*)), SLOT(updateGroup(KNGroup*)));

  // connect to the folder manager
  KNFolderManager* fm = knGlobals.folderManager();
  connect(fm, SIGNAL(folderAdded(KNFolder*)), SLOT(addPendingFolders()));
  connect(fm, SIGNAL(folderRemoved(KNFolder*)), SLOT(removeFolder(KNFolder*)));
  connect(fm, SIGNAL(folderActivated(KNFolder*)), SLOT(activateFolder(KNFolder*)));

  installEventFilter(this);
}

KNCollectionView::~KNCollectionView()
{
  writeConfig();
}

void KNCollectionView::readConfig()
{
  KConfig *conf = knGlobals.config();
  conf->setGroup( "GroupView" );

  // execute the listview layout stuff only once
  static bool initDone = false;
  if (!initDone) {
    initDone = true;
    const int unreadColumn = conf->readNumEntry("UnreadColumn", 1);
    const int totalColumn = conf->readNumEntry("TotalColumn", 2);

    // we need to _activate_ them in the correct order
    // this is ugly because we can't use header()->moveSection
    // but otherwise the restoreLayout doesn't know that to do
    if (unreadColumn != -1 && unreadColumn < totalColumn)
      addUnreadColumn( i18n("Unread"), 48 );
    if (totalColumn != -1)
      addTotalColumn( i18n("Total"), 36 );
    if (unreadColumn != -1 && unreadColumn > totalColumn)
      addUnreadColumn( i18n("Unread"), 48 );
    updatePopup();

    restoreLayout( knGlobals.config(), "GroupView" );
  }

  // font & color settings
  KNConfig::Appearance *app = knGlobals.configManager()->appearance();
  setFont( app->groupListFont() );

  QPalette p = palette();
  p.setColor( QColorGroup::Base, app->backgroundColor() );
  p.setColor( QColorGroup::Text, app->textColor() );
  setPalette( p );
  setAlternateBackground( app->backgroundColor() );
  // FIXME: make this configurable
  mPaintInfo.colUnread = QColor( "blue" );
  mPaintInfo.colFore = app->textColor();
  mPaintInfo.colBack = app->backgroundColor();
}

void KNCollectionView::writeConfig()
{
  KConfig *conf = knGlobals.config();
  conf->setGroup( "GroupView" );
  saveLayout( knGlobals.config(), "GroupView" );
  conf->writeEntry( "UnreadColumn", unreadIndex() );
  conf->writeEntry( "TotalColumn", totalIndex() );
}

void KNCollectionView::addAccount(KNNntpAccount *a)
{
  // add account item
  KNCollectionViewItem* it = new KNCollectionViewItem(this, KFolderTreeItem::News);
  a->setListItem(it);
  it->setOpen(a->wasOpen());

  // add groups for this account
  QPtrList<KNGroup> groups;
  groups.setAutoDelete(false);
  knGlobals.groupManager()->getGroupsOfAccount(a, &groups);
  for(KNGroup *g = groups.first(); g; g = groups.next()) {
    KNCollectionViewItem *gitem = new KNCollectionViewItem(it, KFolderTreeItem::News);
    g->setListItem(gitem);
    g->updateListItem();
  }
}

void KNCollectionView::removeAccount(KNNntpAccount *a)
{
  if(!a->listItem())
    return;
  KNCollectionViewItem *child = 0, *aitem = a->listItem();
  while((child = static_cast<KNCollectionViewItem*>(aitem->firstChild())))
    removeGroup(static_cast<KNGroup*>(child->coll));
  delete aitem;
  a->setListItem(0);
}

void KNCollectionView::updateAccount(KNNntpAccount *a)
{
  a->updateListItem();
}

void KNCollectionView::reloadAccounts()
{
  KNAccountManager* am = knGlobals.accountManager();
  for(KNNntpAccount *a = am->first(); a; a = am->next()) {
    removeAccount(a);
    addAccount(a);
  }
}

void KNCollectionView::addGroup(KNGroup *g)
{
  if (!g->account()->listItem())
    return;

  KNCollectionViewItem *gitem =
      new KNCollectionViewItem( g->account()->listItem(), KFolderTreeItem::News );
  g->setListItem(gitem);
  updateGroup(g);
}

void KNCollectionView::removeGroup(KNGroup *g)
{
  if (!g->listItem())
    return;

  delete g->listItem();
  g->setListItem(0);
}

void KNCollectionView::updateGroup(KNGroup *g)
{
  g->updateListItem();
}

void KNCollectionView::addFolder(KNFolder *f)
{
  KNCollectionViewItem *it;

  if (!f->parent()) {
    // root folder
    it = new KNCollectionViewItem(this, KFolderTreeItem::Local);
  } else {
    // make sure the parent folder has already been added
    if (!f->parent()->listItem())
      addFolder( static_cast<KNFolder*>(f->parent()) );
    // handle special folders
    KFolderTreeItem::Type type = KFolderTreeItem::Other;
    switch ( f->id() ) {
      case 1:
        type = KFolderTreeItem::Drafts; break;
      case 2:
        type = KFolderTreeItem::Outbox; break;
      case 3:
        type = KFolderTreeItem::SentMail; break;
    }
    it = new KNCollectionViewItem( f->parent()->listItem(), KFolderTreeItem::Local, type );
  }
  f->setListItem( it );
  updateFolder( f );
}

void KNCollectionView::removeFolder(KNFolder* f)
{
  if(!f->listItem())
    return;
  KNCollectionViewItem *child = 0, *it = f->listItem();
  while((child = static_cast<KNCollectionViewItem*>(it->firstChild())))
    removeFolder(static_cast<KNFolder*>(child->coll));
  delete f->listItem();
  f->setListItem(0);
}

void KNCollectionView::reloadFolders()
{
  // remove existing folder items
  removeFolder(knGlobals.folderManager()->root());

  // add folder items
  addPendingFolders();
}

void KNCollectionView::addPendingFolders()
{
  QPtrList<KNFolder> folders = knGlobals.folderManager()->folders();
  for(KNFolder *f = folders.first(); f; f = folders.next())
    if(!f->listItem())
      addFolder(f);
  // now open the folders if they were open in the last session
  for(KNFolder *f = folders.first(); f; f = folders.next())
    if (f->listItem())
      f->listItem()->setOpen(f->wasOpen());
}

void KNCollectionView::activateFolder(KNFolder* f)
{
  if(f->listItem())
    setActive( f->listItem() );
}

void KNCollectionView::updateFolder(KNFolder* f)
{
  f->updateListItem();
}

void KNCollectionView::reload()
{
  reloadAccounts();
  reloadFolders();
}

void KNCollectionView::setActive( QListViewItem *i )
{
  if (!i || mActiveItem == i)
    return;

  clearSelection();
  setSelected( i, true );
  setCurrentItem( i );
  mActiveItem = i;
  emit( selectionChanged( i ) );
}

void KNCollectionView::nextGroup()
{
  incCurrentFolder();
  setActive( currentItem() );
}

void KNCollectionView::prevGroup()
{
  decCurrentFolder();
  setActive( currentItem() );
}

void KNCollectionView::decCurrentFolder()
{
  QListViewItemIterator it( currentItem() );
  --it;
  KFolderTreeItem* fti = static_cast<KFolderTreeItem*>(it.current());
  if (fti) {
    ensureItemVisible( fti );
    setFocus();
    setCurrentItem( fti );
  }
}

void KNCollectionView::incCurrentFolder()
{
  QListViewItemIterator it( currentItem() );
  ++it;
  KFolderTreeItem* fti = static_cast<KFolderTreeItem*>(it.current());
  if (fti) {
    ensureItemVisible( fti );
    setFocus();
    setCurrentItem( fti );
  }
}

void KNCollectionView::selectCurrentFolder()
{
  KFolderTreeItem* fti = static_cast<KFolderTreeItem*>( currentItem() );
  if (fti) {
    ensureItemVisible( fti );
    setActive( fti );
  }
}

QDragObject* KNCollectionView::dragObject()
{
  KFolderTreeItem *item = static_cast<KFolderTreeItem*>
      (itemAt(viewport()->mapFromGlobal(QCursor::pos())));
  if ( item && item->protocol() == KFolderTreeItem::Local && item->type() == KFolderTreeItem::Other ) {
    QDragObject *d = new QStoredDrag( "x-knode-drag/folder", viewport() );
    d->setPixmap( SmallIcon("folder") );
    return d;
  }
  return 0;
}

void KNCollectionView::contentsDropEvent( QDropEvent *e )
{
  cleanItemHighlighter(); // necessary since we overwrite KListView::contentsDropEvent()
  QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
  KNCollectionViewItem *fti = static_cast<KNCollectionViewItem*>(item);
  if (fti && (fti->coll) && acceptDrag(e)) {
    emit folderDrop( e, fti );
    e->accept( true );
  }
  else
    e->accept( false );
}

void KNCollectionView::toggleUnreadColumn()
{
  if ( isUnreadActive() )
    removeUnreadColumn();
  else
    addUnreadColumn( i18n("Unread"), 48 );
  mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
  reload();
}

void KNCollectionView::toggleTotalColumn()
{
  if ( isTotalActive() )
    removeTotalColumn();
  else
    addTotalColumn( i18n("Total"), 36 );
  mPopup->setItemChecked( mTotalPop, isTotalActive() );
  reload();
}

void KNCollectionView::updatePopup() const
{
  mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
  mPopup->setItemChecked( mTotalPop, isTotalActive() );
}

bool KNCollectionView::eventFilter(QObject *o, QEvent *e)
{
  if ((e->type() == QEvent::KeyPress) && (static_cast<QKeyEvent*>(e)->key() == Key_Tab)) {
    emit(focusChangeRequest(this));
    if (!hasFocus())  // focusChangeRequest was successful
      return true;
  }

  // header popup menu
  if ( e->type() == QEvent::MouseButtonPress &&
       static_cast<QMouseEvent*>(e)->button() == RightButton &&
       o->isA("QHeader") )
  {
    mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
    return true;
  }

  return KFolderTree::eventFilter(o, e);
}

void KNCollectionView::focusInEvent(QFocusEvent *e)
{
  QListView::focusInEvent(e);
  emit focusChanged(e);
}

void KNCollectionView::focusOutEvent(QFocusEvent *e)
{
  QListView::focusOutEvent(e);
  emit focusChanged(e);
}

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


<commit_before>#include <bitcoin/bitcoin.hpp>
using namespace libbitcoin;

void show_last(const std::error_code& ec, size_t last_depth)
{
    if (ec)
    {
        log_fatal() << ec.message();
        return;
    }
    log_info() << "Last block depth: " << last_depth;
}

void blockchain_started(const std::error_code& ec)
{
    if (ec)
        log_error() << ec.message();
    else
        log_info() << "Blockchain initialized!";
}

int main()
{
    async_service service(1);
    bdb_blockchain chain(service);
    chain.start("database", blockchain_started);
    chain.fetch_last_depth(show_last);
    std::cin.get();
    service.stop();
    chain.stop();
    return 0;
}

<commit_msg>fetch last block and show its hash.<commit_after>#include <bitcoin/bitcoin.hpp>
using namespace libbitcoin;

void show_last(const std::error_code& ec, size_t last_depth)
{
    if (ec)
    {
        log_fatal() << ec.message();
        return;
    }
    log_info() << "Last block depth: " << last_depth;
}

void show_blk_hash(const std::error_code& ec, const message::block& blk)
{
    if (ec)
    {
        log_fatal() << ec.message();
        return;
    }
    log_info() << hash_block_header(blk);
}

void blockchain_started(const std::error_code& ec)
{
    if (ec)
        log_error() << ec.message();
    else
        log_info() << "Blockchain initialized!";
}

int main()
{
    async_service service(1);
    bdb_blockchain chain(service);
    chain.start("database", blockchain_started);
    chain.fetch_last_depth(show_last);
    chain.fetch_block_header(191810, show_blk_hash);
    std::cin.get();
    service.stop();
    service.join();
    chain.stop();
    return 0;
}

<|endoftext|>


<commit_before>/*
    This file is part of Kontact
    Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
    Copyright (c) 2002-2003 Daniel Molkentin <molkentin@kde.org>

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include <qhbox.h>
#include <qcombobox.h>
#include <qwhatsthis.h>
#include <qsplitter.h>
#include <qobjectlist.h>

#include <kapplication.h>
#include <kconfig.h>
#include <ktrader.h>
#include <klibloader.h>
#include <kdebug.h>
#include <kstdaction.h>
#include <klistbox.h>
#include <kiconloader.h>
#include <kstandarddirs.h>
#include <kshortcut.h>
#include <kparts/componentfactory.h>
#include <klocale.h>
#include <kstatusbar.h>
#include <kcmultidialog.h>
#include <infoextension.h>

#include <dcopclient.h>

#include "kpplugin.h"

#include "mainwindow.h"
#include "sidepane.h"

using namespace Kontact;

MainWindow::MainWindow()
  : Kontact::Core()
{
  // create the GUI
  QHBox *box = new QHBox(this);
  box->setFrameStyle(  QFrame::Panel | QFrame::Sunken );

  QSplitter *splitter = new QSplitter(box);

  m_sidePane = new SidePane(splitter);
  m_sidePane->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
  connect(m_sidePane, SIGNAL(showPart(KParts::Part*)), SLOT(showPart(KParts::Part*)));
  QVBox *vBox = new QVBox( splitter );
  vBox->setSpacing(0);

  // Initiate the headerWidget
  headerFrame = new QHBox( vBox );
  headerFrame->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Maximum );
  headerFrame->setSpacing(0);

  headerText = new QLabel( headerFrame );
  headerText->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Maximum );
  headerText->setFrameShape( QFrame::ToolBarPanel );
  headerText->setAutoMask(true);

  headerPixmap = new QLabel( headerFrame );
  headerPixmap->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum );
  headerPixmap->setFrameShape( QFrame::ToolBarPanel );
  headerPixmap->setAutoMask(true);
  headerPixmap->setAlignment( AlignRight );

  connect( this, SIGNAL( textChanged( const QString& ) ), headerText, SLOT( setText( const QString& ) ) );
  connect( this, SIGNAL( iconChanged( const QPixmap& ) ), headerPixmap, SLOT( setPixmap( const QPixmap& ) ) );
  QFont fnt(m_sidePane->font());
  fnt.setBold(true);
  fnt.setPointSize(m_sidePane->font().pointSize()+3);
  headerText->setFont(fnt);

  m_lastInfoExtension = 0L;

  m_stack = new QWidgetStack(vBox);

  setCentralWidget(box);

  statusBar()->show();

  // prepare the part manager
  m_partManager = new KParts::PartManager(this);
  connect(m_partManager, SIGNAL(activePartChanged(KParts::Part *)), this, SLOT(activePartChanged(KParts::Part *)));

  setupActions();

  loadSettings();

  loadPlugins();

  setXMLFile("kontactui.rc");

  createGUI(0);

  m_sidePane->invokeFirstEntry();

  resize(600, 400); // initial size
  setAutoSaveSettings();
}

MainWindow::~MainWindow()
{
    QPtrList<KParts::Part> parts = *m_partManager->parts();
    parts.setAutoDelete(true);
    parts.clear();
}

void MainWindow::loadSettings()
{
}

void MainWindow::saveSettings()
{
}

void MainWindow::setupActions()
{
  (void) KStdAction::quit(this, SLOT(slotQuit()), actionCollection(), "file_quit");
  (void) KStdAction::preferences(this, SLOT(slotPreferences()), actionCollection(), "settings_preferences");
  m_newActions = new KActionMenu( i18n("New"), BarIcon("filenew2"), actionCollection(), "action_new" );
}

void MainWindow::insertNewAction(KAction *action)
{
  m_newActions->insert(action);
}

void MainWindow::loadPlugins()
{
  KTrader::OfferList offers = KTrader::self()->query(QString::fromLatin1("Kontact/Plugin"), QString::null);

  for (KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it)
  {
    kdDebug(5600) << "Loading Plugin: " << (*it)->name() << endl;
    Kontact::Plugin *plugin = KParts::ComponentFactory
      ::createInstanceFromService<Kontact::Plugin>(*it, this);
    if (!plugin)
      continue;

    addPlugin(plugin);
  }
}

void MainWindow::addPlugin(Kontact::Plugin *plugin)
{
  kdDebug(5600) << "Added plugin" << endl;

  // merge the plugins GUI into the main window
  insertChildClient(plugin);
  m_plugins.append(plugin);
  m_sidePane->addEntry(plugin);
}

void MainWindow::addPart(KParts::Part *part)
{
  m_partManager->addPart(part, false);

  if (part->widget())
    m_stack->addWidget(part->widget(), 0);
}

void MainWindow::activePartChanged(KParts::Part *part)
{
  if ( !part )  // part can be 0 at shutdown
    return;

  kdDebug(5600) << "Part activated: " << part << " with stack id. "
      << m_stack->id(part->widget())<< endl;
  QObjectList *l = part->queryList( "KParts::InfoExtension" );
  KParts::InfoExtension *ie = static_cast<KParts::InfoExtension*>(l->first());
  if( ie != 0L )
  {
      disconnect( m_lastInfoExtension, SIGNAL( textChanged( const QString& ) ),
	  			 headerText, SLOT( setText( const QString& ) ) );
      connect( ie, SIGNAL( textChanged( const QString& ) ),
	  			 headerText, SLOT( setText( const QString& ) ) );
      disconnect( m_lastInfoExtension, SIGNAL( iconChanged( const QPixmap& ) ),
				 headerPixmap, SLOT( setPixmap( const QPixmap& ) ) );
      connect( ie, SIGNAL( iconChanged( const QPixmap& ) ),
				 headerPixmap, SLOT( setPixmap( const QPixmap& ) ) );
  }
  else
  {
	  headerText->setText( QString::null );
	  headerPixmap->setPixmap( QPixmap() );
  }
  m_lastInfoExtension = ie;

  createGUI(part);
}

void MainWindow::showPart(KParts::Part* part)
{
  QPtrList<KParts::Part> *partList = const_cast< QPtrList<KParts::Part>* >(m_partManager->parts());
  if (partList->find(part) == -1)
      addPart(part);

  m_partManager->setActivePart( part );
  QWidget* view = part->widget();
  Q_ASSERT(view);
  if ( view )
  {
    m_stack->raiseWidget( view );
    view->show();
    view->setFocus();
  }
}

void MainWindow::slotQuit()
{
  close();
}

void MainWindow::slotPreferences()
{
  KCMultiDialog* dialog = new KCMultiDialog("PIM", this, "KontactPreferences");

  QStringList modules;

  // find all all modules for all plugins
  QPtrListIterator<Kontact::Plugin> pit(m_plugins);
  for(; pit.current(); ++pit)
  {
     QStringList tmp = pit.current()->configModules();
     if(!tmp.isEmpty())
         modules += tmp;
  }

  // add them all
  QStringList::iterator mit;
  for (mit = modules.begin(); mit != modules.end(); ++mit)
    dialog->addModule((*mit));

  dialog->show();
  dialog->raise();
}

int MainWindow::startServiceFor( const QString& serviceType,
                           const QString& constraint,
                           const QString& preferences,
                           QString *error, QCString* dcopService, int flags )
{
  QPtrListIterator<Kontact::Plugin> it( m_plugins );
  for ( ; it.current() ; ++it )
  {
    if ( it.current()->createDCOPInterface( serviceType ) ) {
      kdDebug(5600) << "found interface for " << serviceType << endl;
      if ( dcopService )
        *dcopService = it.current()->dcopClient()->appId();
      kdDebug(5600) << "appId=" << it.current()->dcopClient()->appId() << endl;
      return 0; // success
    }
  }
  kdDebug(5600) << "Didn't find dcop interface, falling back to external process" << endl;
  return KDCOPServiceStarter::startServiceFor( serviceType, constraint, preferences, error, dcopService, flags );
}

#include "mainwindow.moc"

// vim: ts=4 sw=4 et
<commit_msg>These are superfluous...:)<commit_after>/*
    This file is part of Kontact
    Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
    Copyright (c) 2002-2003 Daniel Molkentin <molkentin@kde.org>

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include <qhbox.h>
#include <qcombobox.h>
#include <qwhatsthis.h>
#include <qsplitter.h>
#include <qobjectlist.h>

#include <kapplication.h>
#include <kconfig.h>
#include <ktrader.h>
#include <klibloader.h>
#include <kdebug.h>
#include <kstdaction.h>
#include <klistbox.h>
#include <kiconloader.h>
#include <kstandarddirs.h>
#include <kshortcut.h>
#include <kparts/componentfactory.h>
#include <klocale.h>
#include <kstatusbar.h>
#include <kcmultidialog.h>
#include <infoextension.h>

#include <dcopclient.h>

#include "kpplugin.h"

#include "mainwindow.h"
#include "sidepane.h"

using namespace Kontact;

MainWindow::MainWindow()
  : Kontact::Core()
{
  // create the GUI
  QHBox *box = new QHBox(this);
  box->setFrameStyle(  QFrame::Panel | QFrame::Sunken );

  QSplitter *splitter = new QSplitter(box);

  m_sidePane = new SidePane(splitter);
  m_sidePane->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
  connect(m_sidePane, SIGNAL(showPart(KParts::Part*)), SLOT(showPart(KParts::Part*)));
  QVBox *vBox = new QVBox( splitter );
  vBox->setSpacing(0);

  // Initiate the headerWidget
  headerFrame = new QHBox( vBox );
  headerFrame->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Maximum );
  headerFrame->setSpacing(0);

  headerText = new QLabel( headerFrame );
  headerText->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Maximum );
  headerText->setFrameShape( QFrame::ToolBarPanel );

  headerPixmap = new QLabel( headerFrame );
  headerPixmap->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum );
  headerPixmap->setFrameShape( QFrame::ToolBarPanel );
  headerPixmap->setAlignment( AlignRight );

  connect( this, SIGNAL( textChanged( const QString& ) ), headerText, SLOT( setText( const QString& ) ) );
  connect( this, SIGNAL( iconChanged( const QPixmap& ) ), headerPixmap, SLOT( setPixmap( const QPixmap& ) ) );
  QFont fnt(m_sidePane->font());
  fnt.setBold(true);
  fnt.setPointSize(m_sidePane->font().pointSize()+3);
  headerText->setFont(fnt);

  m_lastInfoExtension = 0L;

  m_stack = new QWidgetStack(vBox);

  setCentralWidget(box);

  statusBar()->show();

  // prepare the part manager
  m_partManager = new KParts::PartManager(this);
  connect(m_partManager, SIGNAL(activePartChanged(KParts::Part *)), this, SLOT(activePartChanged(KParts::Part *)));

  setupActions();

  loadSettings();

  loadPlugins();

  setXMLFile("kontactui.rc");

  createGUI(0);

  m_sidePane->invokeFirstEntry();

  resize(600, 400); // initial size
  setAutoSaveSettings();
}

MainWindow::~MainWindow()
{
    QPtrList<KParts::Part> parts = *m_partManager->parts();
    parts.setAutoDelete(true);
    parts.clear();
}

void MainWindow::loadSettings()
{
}

void MainWindow::saveSettings()
{
}

void MainWindow::setupActions()
{
  (void) KStdAction::quit(this, SLOT(slotQuit()), actionCollection(), "file_quit");
  (void) KStdAction::preferences(this, SLOT(slotPreferences()), actionCollection(), "settings_preferences");
  m_newActions = new KActionMenu( i18n("New"), BarIcon("filenew2"), actionCollection(), "action_new" );
}

void MainWindow::insertNewAction(KAction *action)
{
  m_newActions->insert(action);
}

void MainWindow::loadPlugins()
{
  KTrader::OfferList offers = KTrader::self()->query(QString::fromLatin1("Kontact/Plugin"), QString::null);

  for (KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it)
  {
    kdDebug(5600) << "Loading Plugin: " << (*it)->name() << endl;
    Kontact::Plugin *plugin = KParts::ComponentFactory
      ::createInstanceFromService<Kontact::Plugin>(*it, this);
    if (!plugin)
      continue;

    addPlugin(plugin);
  }
}

void MainWindow::addPlugin(Kontact::Plugin *plugin)
{
  kdDebug(5600) << "Added plugin" << endl;

  // merge the plugins GUI into the main window
  insertChildClient(plugin);
  m_plugins.append(plugin);
  m_sidePane->addEntry(plugin);
}

void MainWindow::addPart(KParts::Part *part)
{
  m_partManager->addPart(part, false);

  if (part->widget())
    m_stack->addWidget(part->widget(), 0);
}

void MainWindow::activePartChanged(KParts::Part *part)
{
  if ( !part )  // part can be 0 at shutdown
    return;

  kdDebug(5600) << "Part activated: " << part << " with stack id. "
      << m_stack->id(part->widget())<< endl;
  QObjectList *l = part->queryList( "KParts::InfoExtension" );
  KParts::InfoExtension *ie = static_cast<KParts::InfoExtension*>(l->first());
  if( ie != 0L )
  {
      disconnect( m_lastInfoExtension, SIGNAL( textChanged( const QString& ) ),
	  			 headerText, SLOT( setText( const QString& ) ) );
      connect( ie, SIGNAL( textChanged( const QString& ) ),
	  			 headerText, SLOT( setText( const QString& ) ) );
      disconnect( m_lastInfoExtension, SIGNAL( iconChanged( const QPixmap& ) ),
				 headerPixmap, SLOT( setPixmap( const QPixmap& ) ) );
      connect( ie, SIGNAL( iconChanged( const QPixmap& ) ),
				 headerPixmap, SLOT( setPixmap( const QPixmap& ) ) );
  }
  else
  {
	  headerText->setText( QString::null );
	  headerPixmap->setPixmap( QPixmap() );
  }
  m_lastInfoExtension = ie;

  createGUI(part);
}

void MainWindow::showPart(KParts::Part* part)
{
  QPtrList<KParts::Part> *partList = const_cast< QPtrList<KParts::Part>* >(m_partManager->parts());
  if (partList->find(part) == -1)
      addPart(part);

  m_partManager->setActivePart( part );
  QWidget* view = part->widget();
  Q_ASSERT(view);
  if ( view )
  {
    m_stack->raiseWidget( view );
    view->show();
    view->setFocus();
  }
}

void MainWindow::slotQuit()
{
  close();
}

void MainWindow::slotPreferences()
{
  KCMultiDialog* dialog = new KCMultiDialog("PIM", this, "KontactPreferences");

  QStringList modules;

  // find all all modules for all plugins
  QPtrListIterator<Kontact::Plugin> pit(m_plugins);
  for(; pit.current(); ++pit)
  {
     QStringList tmp = pit.current()->configModules();
     if(!tmp.isEmpty())
         modules += tmp;
  }

  // add them all
  QStringList::iterator mit;
  for (mit = modules.begin(); mit != modules.end(); ++mit)
    dialog->addModule((*mit));

  dialog->show();
  dialog->raise();
}

int MainWindow::startServiceFor( const QString& serviceType,
                           const QString& constraint,
                           const QString& preferences,
                           QString *error, QCString* dcopService, int flags )
{
  QPtrListIterator<Kontact::Plugin> it( m_plugins );
  for ( ; it.current() ; ++it )
  {
    if ( it.current()->createDCOPInterface( serviceType ) ) {
      kdDebug(5600) << "found interface for " << serviceType << endl;
      if ( dcopService )
        *dcopService = it.current()->dcopClient()->appId();
      kdDebug(5600) << "appId=" << it.current()->dcopClient()->appId() << endl;
      return 0; // success
    }
  }
  kdDebug(5600) << "Didn't find dcop interface, falling back to external process" << endl;
  return KDCOPServiceStarter::startServiceFor( serviceType, constraint, preferences, error, dcopService, flags );
}

#include "mainwindow.moc"

// vim: ts=4 sw=4 et
<|endoftext|>


<commit_before>#include "Globals.h"

#include "MainObject.h"
#include "Sphere.h"

SphereObject::SphereObject()
{
	MainObject::MainObject();

	SlowDown = true;

	mSpeed = Vec3f::zero();

	state = CREATION_FAST;

	age = 0.0;
	lifespan = 100.0;
}

SphereObject::SphereObject(float sred, float sgreen, float sblue, float salpha, float ssize, int stexturenumber)
{
	SphereObject::SphereObject();

	red = sred;
	blue = sblue;
	green = sgreen;

	alpha = salpha;

	size = ssize;

	texturenumber = stexturenumber;
}

SphereObject::SphereObject(float x, float y, float z)
{
	SphereObject::SphereObject();

	red = 1.0f;
	blue = 0.2f;
	green = 0.2f;

	alpha = 0.0f;

	size = 1.00f;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;

	texturenumber = 0;

	state = CREATION_OSCILLATION;
	lifespan = 50.0;
}

SphereObject::SphereObject(float x, float y, float z, int mstate)
{
	SphereObject::SphereObject();

	state = mstate;

	red = rand() % 10 / 10.0f;
	blue = rand() % 10 / 10.0f;
	green = rand() % 10 / 10.0f;

	alpha = rand() % 10 / 10.0f;

	size = rand() % 100 / 100.0f;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;
}

SphereObject::SphereObject(float x, float y, float z, float msize, float speedx, float speedy, float speedz)
{
	SphereObject::SphereObject();

	red = 1.0f;
	green = 0.2f;
	blue = 0.2f;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;

	size = msize / 2;

	if (size > 0.25f)
		texturenumber = 1;
	else
		texturenumber = 2;

	mSpeed.x = speedx;
	mSpeed.y = speedy;
	mSpeed.z = speedz;

	state = CREATION_FAST;
	lifespan = 50.0;
}

SphereObject::SphereObject(float sred, float sgreen, float sblue, float salpha, float ssize, int stexturenumber, float x, float y, float z)
{
	SphereObject::SphereObject();

	SlowDown = true;

	red = sred;
	blue = sblue;
	green = sgreen;

	alpha = salpha;

	size = ssize;

	texturenumber = stexturenumber;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;

	mSpeed = Vec3f::zero();
}

void SphereObject::Update(double elapsed, vector <SphereObject *> *objects, Vec3f camerapoint)
{
	Vec3f distance = mPos - camerapoint;

	int dist = (int)distance.length();

	quality = 60 - (dist / 2);

	if (quality <= 6)
		quality = 6;

	if (GetSelected()) {
		SetShine(0.0f);
	}
		else {
			SetShine(100.0f);
			RandMovement();
			age += elapsed;
		}

		mPos += mSpeed * (float)elapsed;
		SpeedUpdate(elapsed);
		mTransform.setToIdentity();
		mTransform.setTranslate(mPos);
		//mTransform.createRotation(mRotation);

	/*	if ((mPos.x < -BORDERX) || (mPos.x > BORDERX) || (mPos.y < -BORDERY)
			|| (mPos.y > BORDERY) || (mPos.z < -BORDERZ) || (mPos.z > BORDERZ))
		{
			mSpeed = -mSpeed;
		}*/

	if (state == CREATION_FAST) {

		if (alpha < 1.0f) {
			alpha += 0.2f *(float)elapsed;
		}
		else
			SetState(NORMAL);
	}

	else if (state == DECAY) {
		if (blue < 1.0f) {
			blue += 0.05f *(float)elapsed;
			//red -= 0.05f *(float)elapsed;
			//green -= 0.05f *(float)elapsed;
		}
		if (alpha > 0.0f) {
			alpha -= 0.075f *(float)elapsed;
			if (size > 0.25f) {
				if (rand() % 350 == 1) {
					SphereObject *sphere = new SphereObject(mPos.x, mPos.y, mPos.z, size, (rand() % 20 - 10) / 10.0f, (rand() % 20 - 10) / 10.0f, (rand() % 20 - 10) / 10.0f);
					objects->push_back(sphere);
				}
			}
		}
		else SetState(DEAD);

	}

	else if (state == CREATION_OSCILLATION) {
		if (alpha < 1.0f) {
			alpha = (cosf((float)getElapsedSeconds() * 2.0f) * 0.4f) + (age / 15.0f);
			if (alpha < 0.1f) { alpha = 0.1f; }
		}
		else
			SetState(NORMAL);
	}

	else { // state must be NORMAL
		if (red > 0.2f) {
			red -= 0.3f *(float)elapsed;
		}
		mTransform.rotate(Vec3f::yAxis(), (float)getElapsedSeconds() * 0.3f);
		if (age >= lifespan)
		{
			SetState(DECAY);
		}
	}
}

void SphereObject::SpeedUpdate(double elapsed)
{
	if (mSpeed.x > 0.5f) { mSpeed.x = 0.5f; }
	if (mSpeed.y > 0.5f) { mSpeed.y = 0.5f; }
	if (mSpeed.z > 0.5f) { mSpeed.z = 0.5f; }
	if (mSpeed.x < -0.5f) { mSpeed.x = -0.5f; }
	if (mSpeed.y < -0.5f) { mSpeed.y = -0.5f; }
	if (mSpeed.z < -0.5f) { mSpeed.z = -0.5f; }

	if (CheckSlowDown()) {
		if (mSpeed.x > 0.2f)
			mSpeed.x -= 0.1f * (float) elapsed;
		else if (mSpeed.x < 0.2f)
			mSpeed.x += 0.1f * (float) elapsed;

		if (mSpeed.y > 0.2f)
			mSpeed.y -= 0.1f * (float) elapsed;
		else if (mSpeed.y < 0.2f)
			mSpeed.y += 0.1f * (float) elapsed;

		if (mSpeed.z > 0.2f)
			mSpeed.z -= 0.1f * (float) elapsed;
		else if (mSpeed.z < 0.2f)
			mSpeed.z += 0.1f * (float) elapsed;

	}
}

void SphereObject::RandMovement()
{
	if (mSpeed.x <= 0.01f && mSpeed.y <= 0.01f && mSpeed.z <= 0.01f )
	{
		mSpeed.x += (rand() % 20 - 10) / 10.0f;
		mSpeed.y += (rand() % 20 - 10) / 10.0f;
		mSpeed.z += (rand() % 20 - 10) / 10.0f;
	}
}
<commit_msg>Update Sphere.cpp<commit_after>#include "Globals.h"

#include "MainObject.h"
#include "Sphere.h"

SphereObject::SphereObject()
{
	MainObject::MainObject();

	SlowDown = true;

	mSpeed = Vec3f::zero();

	state = CREATION_FAST;

	age = 0.0;
	lifespan = 100.0;
    decayed = false;
}

SphereObject::SphereObject(float sred, float sgreen, float sblue, float salpha, float ssize, int stexturenumber)
{
	SphereObject::SphereObject();

	red = sred;
	blue = sblue;
	green = sgreen;

	alpha = salpha;

	size = ssize;

	texturenumber = stexturenumber;
    decayed = false;
}

SphereObject::SphereObject(float x, float y, float z)
{
	SphereObject::SphereObject();

	red = 1.0f;
	blue = 0.2f;
	green = 0.2f;

	alpha = 0.0f;

	size = 1.00f;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;

	texturenumber = 0;

    decayed = false;

	state = CREATION_OSCILLATION;
	lifespan = 50.0;
}

SphereObject::SphereObject(float x, float y, float z, int mstate)
{
	SphereObject::SphereObject();

	state = mstate;

	red = rand() % 10 / 10.0f;
	blue = rand() % 10 / 10.0f;
	green = rand() % 10 / 10.0f;

	alpha = rand() % 10 / 10.0f;

	size = rand() % 100 / 100.0f;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;
    decayed = false;
}

SphereObject::SphereObject(float x, float y, float z, float msize, float speedx, float speedy, float speedz)
{
	SphereObject::SphereObject();

	red = 1.0f;
	green = 0.2f;
	blue = 0.2f;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;

	size = msize / 2;

	if (size > 0.25f)
		texturenumber = 1;
	else
		texturenumber = 2;

	mSpeed.x = speedx;
	mSpeed.y = speedy;
	mSpeed.z = speedz;
    decayed = false;

	state = CREATION_FAST;
	lifespan = 50.0;
}

SphereObject::SphereObject(float sred, float sgreen, float sblue, float salpha, float ssize, int stexturenumber, float x, float y, float z)
{
	SphereObject::SphereObject();

	SlowDown = true;

	red = sred;
	blue = sblue;
	green = sgreen;

	alpha = salpha;

	size = ssize;

	texturenumber = stexturenumber;

	mPos.x = x;
	mPos.y = y;
	mPos.z = z;

    decayed = false;

	mSpeed = Vec3f::zero();
}

void SphereObject::Update(double elapsed, vector <SphereObject *> *objects, Vec3f camerapoint, ProgramSettings settings)
{
	Vec3f distance = mPos - camerapoint;

	int dist = (int)distance.length();

    if(dist > settings.MAXRENDERDISTANCE)
    {
        SetShow(false); //do not render if too far away
    } else {
        SetShow(true); //RENDER IF NOT CALCULATED OR IN RANGE
    }

	quality = 60 - (dist / 2);

	if (quality <= 6)
		quality = 6;

	if (GetSelected()) {
		SetShine(0.0f);
	}
		else {
			SetShine(100.0f);
			RandMovement();
			age += elapsed;
		}

		mPos += mSpeed * (float)elapsed;
		SpeedUpdate(elapsed);
		mTransform.setToIdentity();
		mTransform.setTranslate(mPos);
    green = 0.2f;
    if(!settings.drawsphere) {                      //IF DRAWING CIRCLES INSTEAD OF SPHERES
            mTransform.rotate(Vec3f::yAxis(), 45.0f);
    }
		//mTransform.createRotation(mRotation);

	/*	if ((mPos.x < -BORDERX) || (mPos.x > BORDERX) || (mPos.y < -BORDERY)
			|| (mPos.y > BORDERY) || (mPos.z < -BORDERZ) || (mPos.z > BORDERZ))
		{
			mSpeed = -mSpeed;
		}*/

	if (state == CREATION_FAST) {

		if (alpha < 1.0f) {
			alpha += 0.2f *(float)elapsed;
		}
		else
			SetState(NORMAL);
	}

	else if (state == DECAY) {
		if (blue < 1.0f) {
			blue += 0.05f *(float)elapsed;
			//red -= 0.05f *(float)elapsed;
			//green -= 0.05f *(float)elapsed;
		}
		if (alpha > 0.0f) {
			alpha -= 0.075f *(float)elapsed;

				if (rand() % 350 == 1) {

				}

		} else SetState(DEAD);
        if(alpha <= 0.2f)
        {
            if(!decayed) {
                decayed = true;
            if (size > 0.25f) {
            int spawn = 2 + randGaussian();
            for (int i = 0; i < spawn; i++) {
                SphereObject *sphere = new SphereObject(mPos.x, mPos.y, mPos.z, size, (rand() % 20 - 10) / 10.0f, (rand() % 20 - 10) / 10.0f, (rand() % 20 - 10) / 10.0f);
                objects->push_back(sphere);
            }
            }
            }
        }

	}

	else if (state == CREATION_OSCILLATION) {
		if (alpha < 1.0f) {
			alpha = (cosf((float)getElapsedSeconds() * 2.0f) * 0.4f) + (age / 15.0f);
			if (alpha < 0.1f) { alpha = 0.1f; }
		}
		else
			SetState(NORMAL);
	}

	else { // state must be NORMAL
		if (red > 0.2f) {
			red -= 0.3f *(float)elapsed;
		}
        if(settings.drawsphere) {
            mTransform.rotate(Vec3f::yAxis(), ((float)getElapsedSeconds() * 0.3f) * settings.ProgramSpeed);
        } else { green = 1.0f; }

		if (age >= lifespan)
		{
			SetState(DECAY);
		}
	}

}

void SphereObject::SpeedUpdate(double elapsed)
{
	if (mSpeed.x > 0.5f) { mSpeed.x = 0.5f; }
	if (mSpeed.y > 0.5f) { mSpeed.y = 0.5f; }
	if (mSpeed.z > 0.5f) { mSpeed.z = 0.5f; }
	if (mSpeed.x < -0.5f) { mSpeed.x = -0.5f; }
	if (mSpeed.y < -0.5f) { mSpeed.y = -0.5f; }
	if (mSpeed.z < -0.5f) { mSpeed.z = -0.5f; }

	if (CheckSlowDown()) {
		if (mSpeed.x > 0.2f)
			mSpeed.x -= 0.1f * (float) elapsed;
		else if (mSpeed.x < 0.2f)
			mSpeed.x += 0.1f * (float) elapsed;

		if (mSpeed.y > 0.2f)
			mSpeed.y -= 0.1f * (float) elapsed;
		else if (mSpeed.y < 0.2f)
			mSpeed.y += 0.1f * (float) elapsed;

		if (mSpeed.z > 0.2f)
			mSpeed.z -= 0.1f * (float) elapsed;
		else if (mSpeed.z < 0.2f)
			mSpeed.z += 0.1f * (float) elapsed;

	}
}

void SphereObject::RandMovement()
{
	if (mSpeed.x <= 0.01f && mSpeed.y <= 0.01f && mSpeed.z <= 0.01f )
	{
		mSpeed.x += (rand() % 20 - 10) / 10.0f;
		mSpeed.y += (rand() % 20 - 10) / 10.0f;
		mSpeed.z += (rand() % 20 - 10) / 10.0f;
	}
}
<|endoftext|>


<commit_before><commit_msg>CppunitTest_sd_export_tests: fix validation errors<commit_after><|endoftext|>


<commit_before>#pragma once

#include "ksp_plugin/vessel.hpp"

#include <vector>

#include "quantities/si.hpp"
#include "testing_utilities/make_not_null.hpp"

namespace principia {

using quantities::si::Kilogram;

namespace ksp_plugin {

inline Vessel::Vessel(not_null<Celestial const*> const parent)
    : body_(),
      parent_(parent) {}

inline not_null<MasslessBody const*> Vessel::body() const {
  return &body_;
}

inline bool Vessel::is_synchronized() const {
  bool const synchronized = history_ != nullptr;
  if (synchronized) {
    CHECK(owned_prolongation_ == nullptr);
  }
  return synchronized;
}

inline bool Vessel::is_initialized() const {
  bool const initialized = prolongation_ != nullptr;
  if (!initialized) {
    CHECK(owned_prolongation_ == nullptr);
  }
  return initialized;
}

inline not_null<Celestial const*> Vessel::parent() const {
  return parent_;
}

inline void Vessel::set_parent(not_null<Celestial const*> const parent) {
  parent_ = parent;
}

inline DiscreteTrajectory<Barycentric> const& Vessel::history() const {
  CHECK(is_synchronized());
  return *history_;
}

inline not_null<DiscreteTrajectory<Barycentric>*> Vessel::mutable_history() {
  CHECK(is_synchronized());
  return history_.get();
}

inline DiscreteTrajectory<Barycentric> const& Vessel::prolongation() const {
  CHECK(is_initialized());
  return *prolongation_;
}

inline not_null<DiscreteTrajectory<Barycentric>*>
Vessel::mutable_prolongation() {
  CHECK(is_initialized());
  return prolongation_;
}

inline not_null<FlightPlan*> Vessel::flight_plan() const {
  CHECK(is_initialized());
  return flight_plan_.get();
}

inline bool Vessel::has_flight_plan() const {
  return flight_plan_ != nullptr;
}

inline DiscreteTrajectory<Barycentric> const& Vessel::prediction() const {
  CHECK(has_prediction());
  return *prediction_;
}

inline bool Vessel::has_prediction() const {
  return prediction_ != nullptr;
}

inline void Vessel::CreateProlongation(
    Instant const& time,
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom) {
  CHECK(!is_synchronized());
  CHECK(!is_initialized());
  CHECK(owned_prolongation_ == nullptr);
  owned_prolongation_ = std::make_unique<DiscreteTrajectory<Barycentric>>();
  owned_prolongation_->Append(time, degrees_of_freedom);
  prolongation_ = owned_prolongation_.get();
}

inline void Vessel::CreateHistoryAndForkProlongation(
    Instant const& time,
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom) {
  CHECK(!is_synchronized());
  history_ = std::make_unique<DiscreteTrajectory<Barycentric>>();
  history_->Append(time, degrees_of_freedom);
  prolongation_ = history_->NewForkAtLast();
  owned_prolongation_.reset();
}

inline void Vessel::ResetProlongation(Instant const& time) {
  CHECK(is_initialized());
  CHECK(is_synchronized());
  CHECK(owned_prolongation_ == nullptr);
  history_->DeleteFork(&prolongation_);
  prolongation_ = history_->NewForkWithCopy(time);
}

inline void Vessel::CreateFlightPlan(
    Instant const& final_time,
    Mass const& initial_mass,
    not_null<Ephemeris<Barycentric>*> ephemeris,
    AdaptiveStepSizeIntegrator<
        Ephemeris<Barycentric>::NewtonianMotionEquation> const& integrator,
    Length const& length_integration_tolerance,
    Speed const& speed_integration_tolerance) {
  if (!is_synchronized()) {
    return;
  }
  flight_plan_ = std::make_unique<FlightPlan>(
                     mutable_history()->NewForkAtLast(),
                     /*initial_time=*/history().last().time(),
                     /*final_time=*/final_time,
                     initial_mass,
                     ephemeris,
                     integrator,
                     length_integration_tolerance,
                     speed_integration_tolerance);
}

inline void Vessel::DeleteFlightPlan() {
  flight_plan_.reset();
}

inline void Vessel::UpdatePrediction(
    not_null<Ephemeris<Barycentric>*> ephemeris,
    AdaptiveStepSizeIntegrator<
        Ephemeris<Barycentric>::NewtonianMotionEquation> const& integrator,
    Instant const& last_time,
    Length const& prediction_length_tolerance,
    Speed const& prediction_speed_tolerance) {
  if (!is_synchronized()) {
    return;
  }
  DeletePrediction();
  prediction_ = mutable_history()->NewForkAtLast();
  if (history().last().time() != prolongation().last().time()) {
    prediction_->Append(prolongation().last().time(),
                        prolongation().last().degrees_of_freedom());
  }
  ephemeris->FlowWithAdaptiveStep(
      prediction_,
      Ephemeris<Barycentric>::kNoIntrinsicAcceleration,
      prediction_length_tolerance,
      prediction_speed_tolerance,
      integrator,
      last_time);
}

inline void Vessel::DeletePrediction() {
  if (has_prediction()) {
    mutable_history()->DeleteFork(&prediction_);
  }
}

inline void Vessel::WriteToMessage(
    not_null<serialization::Vessel*> const message) const {
  CHECK(is_initialized());
  body_.WriteToMessage(message->mutable_body());
  if (is_synchronized()) {
    history_->WriteToMessage(
        message->mutable_history_and_prolongation()->mutable_history());
    prolongation_->WritePointerToMessage(
        message->mutable_history_and_prolongation()->mutable_prolongation());
  } else {
    owned_prolongation_->WriteToMessage(message->mutable_owned_prolongation());
  }
}

inline not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
    serialization::Vessel const& message,
    not_null<Celestial const*> const parent) {
  auto vessel = make_not_null_unique<Vessel>(parent);
  // NOTE(egg): for now we do not read the |MasslessBody| as it can contain no
  // information.
  if (message.has_history_and_prolongation()) {
    vessel->history_ =
        DiscreteTrajectory<Barycentric>::ReadFromMessage(
            message.history_and_prolongation().history());
    vessel->prolongation_ =
        DiscreteTrajectory<Barycentric>::ReadPointerFromMessage(
            message.history_and_prolongation().prolongation(),
            vessel->history_.get());
  } else if (message.has_owned_prolongation()) {
    vessel->owned_prolongation_ =
        DiscreteTrajectory<Barycentric>::ReadFromMessage(
            message.owned_prolongation());
    vessel->prolongation_ = vessel->owned_prolongation_.get();
  } else {
    LOG(FATAL) << "message does not represent an initialized Vessel";
    base::noreturn();
  }
  return vessel;
}

inline Vessel::Vessel()
    : parent_(testing_utilities::make_not_null<Celestial const*>()) {}

}  // namespace ksp_plugin
}  // namespace principia
<commit_msg>an error.<commit_after>#pragma once

#include "ksp_plugin/vessel.hpp"

#include <vector>

#include "quantities/si.hpp"
#include "testing_utilities/make_not_null.hpp"

namespace principia {

using quantities::si::Kilogram;

namespace ksp_plugin {

inline Vessel::Vessel(not_null<Celestial const*> const parent)
    : body_(),
      parent_(parent) {}

inline not_null<MasslessBody const*> Vessel::body() const {
  return &body_;
}

inline bool Vessel::is_synchronized() const {
  bool const synchronized = history_ != nullptr;
  if (synchronized) {
    CHECK(owned_prolongation_ == nullptr);
  }
  return synchronized;
}

inline bool Vessel::is_initialized() const {
  bool const initialized = prolongation_ != nullptr;
  if (!initialized) {
    CHECK(owned_prolongation_ == nullptr);
  }
  return initialized;
}

inline not_null<Celestial const*> Vessel::parent() const {
  return parent_;
}

inline void Vessel::set_parent(not_null<Celestial const*> const parent) {
  parent_ = parent;
}

inline DiscreteTrajectory<Barycentric> const& Vessel::history() const {
  CHECK(is_synchronized());
  return *history_;
}

inline not_null<DiscreteTrajectory<Barycentric>*> Vessel::mutable_history() {
  CHECK(is_synchronized());
  return history_.get();
}

inline DiscreteTrajectory<Barycentric> const& Vessel::prolongation() const {
  CHECK(is_initialized());
  return *prolongation_;
}

inline not_null<DiscreteTrajectory<Barycentric>*>
Vessel::mutable_prolongation() {
  CHECK(is_initialized());
  return prolongation_;
}

inline not_null<FlightPlan*> Vessel::flight_plan() const {
  CHECK(is_initialized());
  return flight_plan_.get();
}

inline bool Vessel::has_flight_plan() const {
  return flight_plan_ != nullptr;
}

inline DiscreteTrajectory<Barycentric> const& Vessel::prediction() const {
  CHECK(has_prediction());
  return *prediction_;
}

inline bool Vessel::has_prediction() const {
  return prediction_ != nullptr;
}

inline void Vessel::CreateProlongation(
    Instant const& time,
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom) {
  CHECK(!is_synchronized());
  CHECK(!is_initialized());
  CHECK(owned_prolongation_ == nullptr);
  owned_prolongation_ = std::make_unique<DiscreteTrajectory<Barycentric>>();
  owned_prolongation_->Append(time, degrees_of_freedom);
  prolongation_ = owned_prolongation_.get();
}

inline void Vessel::CreateHistoryAndForkProlongation(
    Instant const& time,
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom) {
  CHECK(!is_synchronized());
  history_ = std::make_unique<DiscreteTrajectory<Barycentric>>();
  history_->Append(time, degrees_of_freedom);
  prolongation_ = history_->NewForkAtLast();
  owned_prolongation_.reset();
}

inline void Vessel::ResetProlongation(Instant const& time) {
  CHECK(is_initialized());
  CHECK(is_synchronized());
  CHECK(owned_prolongation_ == nullptr);
  history_->DeleteFork(&prolongation_);
  prolongation_ = history_->NewForkWithCopy(time);
}

inline void Vessel::CreateFlightPlan(
    Instant const& final_time,
    Mass const& initial_mass,
    not_null<Ephemeris<Barycentric>*> ephemeris,
    AdaptiveStepSizeIntegrator<
        Ephemeris<Barycentric>::NewtonianMotionEquation> const& integrator,
    Length const& length_integration_tolerance,
    Speed const& speed_integration_tolerance) {
  if (!is_synchronized()) {
    return;
  }
  flight_plan_ = std::make_unique<FlightPlan>(
                     mutable_history()->NewForkAtLast(),
                     /*initial_time=*/history().last().time(),
                     /*final_time=*/final_time,
                     initial_mass,
                     ephemeris,
                     integrator,
                     length_integration_tolerance,
                     speed_integration_tolerance);
}

inline void Vessel::DeleteFlightPlan() {
  flight_plan_.reset();
}

inline void Vessel::UpdatePrediction(
    not_null<Ephemeris<Barycentric>*> ephemeris,
    AdaptiveStepSizeIntegrator<
        Ephemeris<Barycentric>::NewtonianMotionEquation> const& integrator,
    Instant const& last_time,
    Length const& prediction_length_tolerance,
    Speed const& prediction_speed_tolerance) {
  if (!is_synchronized()) {
    return;
  }
  DeletePrediction();
  prediction_ = mutable_history()->NewForkAtLast();
  if (history().last().time() != prolongation().last().time()) {
    prediction_->Append(prolongation().last().time(),
                        prolongation().last().degrees_of_freedom());
  }
  ephemeris->FlowWithAdaptiveStep(
      prediction_,
      Ephemeris<Barycentric>::kNoIntrinsicAcceleration,
      prediction_length_tolerance,
      prediction_speed_tolerance,
      integrator,
      last_time);
}

inline void Vessel::DeletePrediction() {
  if (has_prediction()) {
    mutable_history()->DeleteFork(&prediction_);
  }
}

inline void Vessel::WriteToMessage(
    not_null<serialization::Vessel*> const message) const {
  CHECK(is_initialized());
  body_.WriteToMessage(message->mutable_body());
  if (is_synchronized()) {
    history_->WriteToMessage(
        message->mutable_history_and_prolongation()->mutable_history());
    prolongation_->WritePointerToMessage(
        message->mutable_history_and_prolongation()->mutable_prolongation());
  } else {
    owned_prolongation_->WriteToMessage(message->mutable_owned_prolongation());
  }
}

inline not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
    serialization::Vessel const& message,
    not_null<Celestial const*> const parent) {
  auto vessel = make_not_null_unique<Vessel>(parent);
  // NOTE(egg): for now we do not read the |MasslessBody| as it can contain no
  // information.
  if (message.has_history_and_prolongation()) {
    vessel->history_ =
        DiscreteTrajectory<Barycentric>::ReadFromMessage(
            message.history_and_prolongation().history());
    vessel->prolongation_ =
        DiscreteTrajectory<Barycentric>::ReadPointerFromMessage(
            message.history_and_prolongation().prolongation(),
            vessel->history_.get());
  } else if (message.has_owned_prolongation()) {
    vessel->owned_prolongation_ =
        DiscreteTrajectory<Barycentric>::ReadFromMessage(
            message.owned_prolongation());
    vessel->prolongation_ = vessel->owned_prolongation_.get();
  } else {
    LOG(FATAL) << "message does not represent an initialized Vessel";
    base::noreturn();
  }
  return vessel;
}

inline Vessel::Vessel()
    : body_(),
      parent_(testing_utilities::make_not_null<Celestial const*>()) {}

}  // namespace ksp_plugin
}  // namespace principia
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "Terrain.h"

#include <QUrl>
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QTimer>

QGC_LOGGING_CATEGORY(ElevationProviderLog, "ElevationProviderLog")

Q_GLOBAL_STATIC(TerrainBatchManager, _terrainBatchManager)

TerrainBatchManager::TerrainBatchManager(void)
{
    _batchTimer.setSingleShot(true);
    _batchTimer.setInterval(_batchTimeout);
    connect(&_batchTimer, &QTimer::timeout, this, &TerrainBatchManager::_sendNextBatch);
}

void TerrainBatchManager::addQuery(ElevationProvider* elevationProvider, const QList<QGeoCoordinate>& coordinates)
{
    if (coordinates.length() > 0) {
        qCDebug(ElevationProviderLog) << "addQuery: elevationProvider:coordinates.count" << elevationProvider << coordinates.count();
        connect(elevationProvider, &ElevationProvider::destroyed, this, &TerrainBatchManager::_elevationProviderDestroyed);
        QueuedRequestInfo_t queuedRequestInfo = { elevationProvider, coordinates };
        _requestQueue.append(queuedRequestInfo);
        if (!_batchTimer.isActive()) {
            _batchTimer.start();
        }
    }
}

void TerrainBatchManager::_sendNextBatch(void)
{
    qCDebug(ElevationProviderLog) << "_sendNextBatch _state:_requestQueue.count:_sentRequests.count" << _stateToString(_state) << _requestQueue.count() << _sentRequests.count();

    if (_state != State::Idle) {
        // Waiting for last download the complete, wait some more
        _batchTimer.start();
        return;
    }

    if (_requestQueue.count() == 0) {
        return;
    }

    _sentRequests.clear();

    // Convert coordinates to point strings for json query
    QString points;
    foreach (const QueuedRequestInfo_t& requestInfo, _requestQueue) {
        SentRequestInfo_t sentRequestInfo = { requestInfo.elevationProvider, false, requestInfo.coordinates.count() };
        qCDebug(ElevationProviderLog) << "Building request: coordinate count" << requestInfo.coordinates.count();
        _sentRequests.append(sentRequestInfo);

        foreach (const QGeoCoordinate& coord, requestInfo.coordinates) {
            points += QString::number(coord.latitude(), 'f', 10) + ","
                    + QString::number(coord.longitude(), 'f', 10) + ",";
        }

    }
    points = points.mid(0, points.length() - 1); // remove the last ',' from string
    _requestQueue.clear();

    QUrlQuery query;
    query.addQueryItem(QStringLiteral("points"), points);
    QUrl url(QStringLiteral("https://api.airmap.com/elevation/stage/srtm1/ele"));
    url.setQuery(query);

    QNetworkRequest request(url);

    QNetworkProxy tProxy;
    tProxy.setType(QNetworkProxy::DefaultProxy);
    _networkManager.setProxy(tProxy);

    QNetworkReply* networkReply = _networkManager.get(request);
    if (!networkReply) {
        _batchFailed();
        return;
    }

    connect(networkReply, &QNetworkReply::finished, this, &TerrainBatchManager::_requestFinished);

    _state = State::Downloading;
}

void TerrainBatchManager::_batchFailed(void)
{
    QList<float>    noAltitudes;

    foreach (const SentRequestInfo_t& sentRequestInfo, _sentRequests) {
        if (!sentRequestInfo.providerDestroyed) {
            disconnect(sentRequestInfo.elevationProvider, &ElevationProvider::destroyed, this, &TerrainBatchManager::_elevationProviderDestroyed);
            sentRequestInfo.elevationProvider->_signalTerrainData(false, noAltitudes);
        }
    }
    _sentRequests.clear();
}

void TerrainBatchManager::_requestFinished()
{
    qCDebug(ElevationProviderLog) << "_requestFinished";
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());

    _state = State::Idle;

    // When an error occurs we still end up here
    if (reply->error() != QNetworkReply::NoError) {
        _batchFailed();
        reply->deleteLater();
        return;
    }

    QByteArray responseBytes = reply->readAll();

    QJsonParseError parseError;
    QJsonDocument responseJson = QJsonDocument::fromJson(responseBytes, &parseError);
    if (parseError.error != QJsonParseError::NoError) {
        _batchFailed();
        reply->deleteLater();
        return;
    }

    QJsonObject rootObject = responseJson.object();
    QString status = rootObject["status"].toString();
    if (status != "success") {
        _batchFailed();
        reply->deleteLater();
        return;
    }

    QList<float> altitudes;
    const QJsonArray& dataArray = rootObject["data"].toArray();
    for (int i = 0; i < dataArray.count(); i++) {
        altitudes.push_back(dataArray[i].toDouble());
    }

    int currentIndex = 0;
    foreach (const SentRequestInfo_t& sentRequestInfo, _sentRequests) {
        if (!sentRequestInfo.providerDestroyed) {
            disconnect(sentRequestInfo.elevationProvider, &ElevationProvider::destroyed, this, &TerrainBatchManager::_elevationProviderDestroyed);
            QList<float> requestAltitudes = altitudes.mid(currentIndex, sentRequestInfo.cCoord);
            sentRequestInfo.elevationProvider->_signalTerrainData(true, requestAltitudes);
            currentIndex += sentRequestInfo.cCoord;
        }
    }
    _sentRequests.clear();

    reply->deleteLater();
}

void TerrainBatchManager::_elevationProviderDestroyed(QObject* elevationProvider)
{
    // Remove/Mark deleted objects queries from queues

    qCDebug(ElevationProviderLog) << "_elevationProviderDestroyed elevationProvider" << elevationProvider;

    int i = 0;
    while (i < _requestQueue.count()) {
        const QueuedRequestInfo_t& requestInfo = _requestQueue[i];
        if (requestInfo.elevationProvider == elevationProvider) {
            qCDebug(ElevationProviderLog) << "Removing deleted provider from _requestQueue index:elevationProvider" << i << requestInfo.elevationProvider;
            _requestQueue.removeAt(i);
        } else {
            i++;
        }
    }

    for (int i=0; i<_sentRequests.count(); i++) {
        SentRequestInfo_t& sentRequestInfo = _sentRequests[i];
        if (sentRequestInfo.elevationProvider == elevationProvider) {
            qCDebug(ElevationProviderLog) << "Zombieing deleted provider from _sentRequests index:elevatationProvider" << sentRequestInfo.elevationProvider;
            sentRequestInfo.providerDestroyed = true;
        }
    }
}

QString TerrainBatchManager::_stateToString(State state)
{
    switch (state) {
    case State::Idle:
        return QStringLiteral("Idle");
    case State::Downloading:
        return QStringLiteral("Downloading");
    }
}

ElevationProvider::ElevationProvider(QObject* parent)
    : QObject(parent)
{

}
void ElevationProvider::queryTerrainData(const QList<QGeoCoordinate>& coordinates)
{
    if (coordinates.length() == 0) {
        return;
    }

    _terrainBatchManager->addQuery(this, coordinates);
}

void ElevationProvider::_signalTerrainData(bool success, QList<float>& altitudes)
{
    emit terrainData(success, altitudes);
}
<commit_msg>Fix compiler complaint<commit_after>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "Terrain.h"

#include <QUrl>
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QTimer>

QGC_LOGGING_CATEGORY(ElevationProviderLog, "ElevationProviderLog")

Q_GLOBAL_STATIC(TerrainBatchManager, _terrainBatchManager)

TerrainBatchManager::TerrainBatchManager(void)
{
    _batchTimer.setSingleShot(true);
    _batchTimer.setInterval(_batchTimeout);
    connect(&_batchTimer, &QTimer::timeout, this, &TerrainBatchManager::_sendNextBatch);
}

void TerrainBatchManager::addQuery(ElevationProvider* elevationProvider, const QList<QGeoCoordinate>& coordinates)
{
    if (coordinates.length() > 0) {
        qCDebug(ElevationProviderLog) << "addQuery: elevationProvider:coordinates.count" << elevationProvider << coordinates.count();
        connect(elevationProvider, &ElevationProvider::destroyed, this, &TerrainBatchManager::_elevationProviderDestroyed);
        QueuedRequestInfo_t queuedRequestInfo = { elevationProvider, coordinates };
        _requestQueue.append(queuedRequestInfo);
        if (!_batchTimer.isActive()) {
            _batchTimer.start();
        }
    }
}

void TerrainBatchManager::_sendNextBatch(void)
{
    qCDebug(ElevationProviderLog) << "_sendNextBatch _state:_requestQueue.count:_sentRequests.count" << _stateToString(_state) << _requestQueue.count() << _sentRequests.count();

    if (_state != State::Idle) {
        // Waiting for last download the complete, wait some more
        _batchTimer.start();
        return;
    }

    if (_requestQueue.count() == 0) {
        return;
    }

    _sentRequests.clear();

    // Convert coordinates to point strings for json query
    QString points;
    foreach (const QueuedRequestInfo_t& requestInfo, _requestQueue) {
        SentRequestInfo_t sentRequestInfo = { requestInfo.elevationProvider, false, requestInfo.coordinates.count() };
        qCDebug(ElevationProviderLog) << "Building request: coordinate count" << requestInfo.coordinates.count();
        _sentRequests.append(sentRequestInfo);

        foreach (const QGeoCoordinate& coord, requestInfo.coordinates) {
            points += QString::number(coord.latitude(), 'f', 10) + ","
                    + QString::number(coord.longitude(), 'f', 10) + ",";
        }

    }
    points = points.mid(0, points.length() - 1); // remove the last ',' from string
    _requestQueue.clear();

    QUrlQuery query;
    query.addQueryItem(QStringLiteral("points"), points);
    QUrl url(QStringLiteral("https://api.airmap.com/elevation/stage/srtm1/ele"));
    url.setQuery(query);

    QNetworkRequest request(url);

    QNetworkProxy tProxy;
    tProxy.setType(QNetworkProxy::DefaultProxy);
    _networkManager.setProxy(tProxy);

    QNetworkReply* networkReply = _networkManager.get(request);
    if (!networkReply) {
        _batchFailed();
        return;
    }

    connect(networkReply, &QNetworkReply::finished, this, &TerrainBatchManager::_requestFinished);

    _state = State::Downloading;
}

void TerrainBatchManager::_batchFailed(void)
{
    QList<float>    noAltitudes;

    foreach (const SentRequestInfo_t& sentRequestInfo, _sentRequests) {
        if (!sentRequestInfo.providerDestroyed) {
            disconnect(sentRequestInfo.elevationProvider, &ElevationProvider::destroyed, this, &TerrainBatchManager::_elevationProviderDestroyed);
            sentRequestInfo.elevationProvider->_signalTerrainData(false, noAltitudes);
        }
    }
    _sentRequests.clear();
}

void TerrainBatchManager::_requestFinished()
{
    qCDebug(ElevationProviderLog) << "_requestFinished";
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());

    _state = State::Idle;

    // When an error occurs we still end up here
    if (reply->error() != QNetworkReply::NoError) {
        _batchFailed();
        reply->deleteLater();
        return;
    }

    QByteArray responseBytes = reply->readAll();

    QJsonParseError parseError;
    QJsonDocument responseJson = QJsonDocument::fromJson(responseBytes, &parseError);
    if (parseError.error != QJsonParseError::NoError) {
        _batchFailed();
        reply->deleteLater();
        return;
    }

    QJsonObject rootObject = responseJson.object();
    QString status = rootObject["status"].toString();
    if (status != "success") {
        _batchFailed();
        reply->deleteLater();
        return;
    }

    QList<float> altitudes;
    const QJsonArray& dataArray = rootObject["data"].toArray();
    for (int i = 0; i < dataArray.count(); i++) {
        altitudes.push_back(dataArray[i].toDouble());
    }

    int currentIndex = 0;
    foreach (const SentRequestInfo_t& sentRequestInfo, _sentRequests) {
        if (!sentRequestInfo.providerDestroyed) {
            disconnect(sentRequestInfo.elevationProvider, &ElevationProvider::destroyed, this, &TerrainBatchManager::_elevationProviderDestroyed);
            QList<float> requestAltitudes = altitudes.mid(currentIndex, sentRequestInfo.cCoord);
            sentRequestInfo.elevationProvider->_signalTerrainData(true, requestAltitudes);
            currentIndex += sentRequestInfo.cCoord;
        }
    }
    _sentRequests.clear();

    reply->deleteLater();
}

void TerrainBatchManager::_elevationProviderDestroyed(QObject* elevationProvider)
{
    // Remove/Mark deleted objects queries from queues

    qCDebug(ElevationProviderLog) << "_elevationProviderDestroyed elevationProvider" << elevationProvider;

    int i = 0;
    while (i < _requestQueue.count()) {
        const QueuedRequestInfo_t& requestInfo = _requestQueue[i];
        if (requestInfo.elevationProvider == elevationProvider) {
            qCDebug(ElevationProviderLog) << "Removing deleted provider from _requestQueue index:elevationProvider" << i << requestInfo.elevationProvider;
            _requestQueue.removeAt(i);
        } else {
            i++;
        }
    }

    for (int i=0; i<_sentRequests.count(); i++) {
        SentRequestInfo_t& sentRequestInfo = _sentRequests[i];
        if (sentRequestInfo.elevationProvider == elevationProvider) {
            qCDebug(ElevationProviderLog) << "Zombieing deleted provider from _sentRequests index:elevatationProvider" << sentRequestInfo.elevationProvider;
            sentRequestInfo.providerDestroyed = true;
        }
    }
}

QString TerrainBatchManager::_stateToString(State state)
{
    switch (state) {
    case State::Idle:
        return QStringLiteral("Idle");
    case State::Downloading:
        return QStringLiteral("Downloading");
    }

    return QStringLiteral("State unknown");
}

ElevationProvider::ElevationProvider(QObject* parent)
    : QObject(parent)
{

}
void ElevationProvider::queryTerrainData(const QList<QGeoCoordinate>& coordinates)
{
    if (coordinates.length() == 0) {
        return;
    }

    _terrainBatchManager->addQuery(this, coordinates);
}

void ElevationProvider::_signalTerrainData(bool success, QList<float>& altitudes)
{
    emit terrainData(success, altitudes);
}
<|endoftext|>


<commit_before>#include "Platform.hpp"
#include "genome.pb.h"
#include "Brain.hpp"
#include "ProteinEnvironment.hpp"
#include "Neuron.hpp"
#include "Synapse.hpp"
#include "SimpleSpatialSearch.hpp"
#include "BrainPlugins.hpp"
#include "BrainPlugin.hpp"

#define INPUT_NEURONS			100
#define INPUT_REGION_MINX		0.0f
#define INPUT_REGION_MAXX		5.0f
#define INPUT_REGION_MINY		0.0f
#define INPUT_REGION_MAXY		5.0f
#define INPUT_REGION_SPACING	0.01f	//This also implies max input neurons of ((max-min)/spacing)^2
#define INPUT_AXON_SPREAD		0.0f	//The range of axon locations from input neurons
#define DEVELOPMENT_TICKS		10		//How often development neurons are re-evaluated

#include <boost/math/distributions/uniform.hpp>
#include <boost/random.hpp>

namespace Elysia {

/**
 *  @param ProteinEnvironment *proteinMap - a base protein map for the brain
 *
 *	Description:	Creates a new Brain instance using a defined protein map as a base.
 *					Also adds a new spatial search instance, sets the brain's age to 0 and
 *					initializes all requisite brain plugins
**/
Brain::Brain (ProteinEnvironment *proteinMap){
    mProteinMap=proteinMap;
    mSpatialSearch=new SimpleSpatialSearch;
    mAge=0;
	mDevelopmentCounter=0;
	createInputRegion(INPUT_NEURONS);
    makeInitialNeurons();
    BrainPlugins::constructAll(this).swap(mPlugins);
}

void Brain::syncEnvironmentNeurons(unsigned int index, ProteinEnvironment::iterator environmentIterator){
    Elysia::Genome::Effect growEffect=Elysia::Genome::GROW_NEURON;
    float neuronDensity =environmentIterator.getProteinDensity(growEffect);
    BoundingBox3f3f bounds = environmentIterator.getBoundingBox();
    float area = bounds.across().x*bounds.across().y;
    float expectedNumNeurons=neuronDensity*area;
    boost::minstd_rand randGen(1+index);//needs to be >0
    boost::uniform_real<> uni_dist(0.0f,1.0f);
    boost::variate_generator<boost::minstd_rand, boost::uniform_real<> > uniform(randGen,uni_dist);
    if (expectedNumNeurons-floor(expectedNumNeurons)<uniform()) {
        expectedNumNeurons=ceil(expectedNumNeurons);
    }else {
        expectedNumNeurons=floor(expectedNumNeurons);
    }
    int numNeurons=(unsigned int)expectedNumNeurons;
    if (numNeurons<mNumNeurons[index]) {
        //FIXME: do we want to delete excess neurons
    }
    for (int n=mNumNeurons[index];n<numNeurons;++n) {
        this->addNeuron(bounds, environmentIterator.retrieveGene(growEffect));
    }
    if (mNumNeurons[index]!=numNeurons) {
        fprintf(stderr,"The index count isn't equal to the sync count:\nthis could happen if a neuron lies at the exact edge of a lobe,\nso don't panic, but verify that this is indeed the case\nand the wrong count got updated for that neuron");
    }
}

void Brain::makeInitialNeurons() {
    unsigned int index=0;
    for (ProteinEnvironment::iterator i=mProteinMap->begin();
         i!=mProteinMap->end();
         ++i,++index) {
        mNumNeurons[i.uid()]=0;
        syncEnvironmentNeurons(index,i);
        //FIXME add numNeurons to the count in this protein zone so we can add/remove more later
    }
}

Neuron * Brain::addNeuron(const BoundingBox3f3f&generationArea, const Genome::Gene&gene) {
    Vector3f v = generationArea.min();
    v.x+=generationArea.across().x*(rand()/(double)RAND_MAX);
    v.y+=generationArea.across().y*(rand()/(double)RAND_MAX);
	v.z=0;	 //Fixing z to 0 for now.
    //v.z+=generationArea.across().z*(rand()/(double)RAND_MAX);
	Neuron *n = new Neuron(this, 2, 3, 4, 1, 1, v, gene);
    mAllNeurons.insert(n);
    return n;
}

/**
 *	Description:	One "tick" of the brain simulation code, where the following occurs:
 *					 - processNeuron() called
 *					 - processSynapes() called
 *					 - increments the current time in the simulation
 *					 - ages the brain
 *					 - updates all the plugins for this brain
**/
void Brain::tick(){
	processNeuron();
	processSynapse();
	//developAllNeurons();
    ++mCurTime;
	++mDevelopmentCounter;
	if(mDevelopmentCounter%10 == 0)this->processDevelopment();
    mAge+=1.0e-6;//fixme this is probably not correct: we probably need genes to do this
    if (mAge>1.0) mAge=1.0;
    for(std::vector<BrainPlugin*>::iterator i=mPlugins.begin(),ie=mPlugins.end();i!=ie;++i) {
        (*i)->update();
    }
}

void Brain::developAllNeurons(){
	for(std::set<Neuron*>::iterator i=mAllNeurons.begin(),ie=mAllNeurons.end();i!=ie;++i){
		(*i)->developSynapse((*i)->getActivityStats());
	}
}

/**
 *	Description:	Updates all neurons in the neuron list for this brain, then clears the list of
 *					active neurons
**/
void Brain::processNeuron(){
	for (std::list<Neuron*>::iterator i=mActiveNeurons.begin(),ie=mActiveNeurons.end();
         i!=ie;
		 ++i) {
        (*i)->tick();
	}
	mActiveNeurons.clear();
}

/**
 *	Description:	Iterates through brain's associates synapses and updates all of them using
 *					the Synapse class residualFire() method
**/
void Brain::processSynapse(){
    std::list<Synapse*>::iterator j,i=mActiveSynapses.begin(),ie=mActiveSynapses.end();
	while (i!=ie) {
        std::list<Synapse*>::iterator j=i++;
        (*j)->residualFire();
	}
}

/**
 *	@param Synapse *inactiveSynapse - synapse to remove
 *
 *	Description:	Removes a synapse from the synapse list and updates it.
**/
void Brain::inactivateSynapse(Synapse *inactiveSynapse){
    if (inactiveSynapse->mWhere!=activeSynapseListSentinel()) {
        mActiveSynapses.erase(inactiveSynapse->mWhere);
        inactiveSynapse->mWhere=activeSynapseListSentinel();
    }
}

/* Removed when AllSynapses set removed
void Brain::deleteSynapse(Synapse *deletedSynapse){

	for(std::set<Synapse*>::iterator j=mAllSynapses.begin(),je=mAllSynapses.end();j!=je; ++j) {
			 if( *j == deletedSynapse){
				 mAllSynapses.erase(*j);
			 }
	}

}
*/

/**
 *	@param Neuron *inactiveNeuron - an inactive neuron to remove
 *
 *	Description:	Removes an unused neuron from the neuron list and updates
**/
void Brain::inactivateNeuron(Neuron *inactiveNeuron){
    if (inactiveNeuron->mWhere!=activeNeuronListSentinel()) {
        mActiveNeurons.erase(inactiveNeuron->mWhere);
        inactiveNeuron->mWhere=activeNeuronListSentinel();
    }
}

void Brain::deleteNeuron(Neuron *deletedNeuron){
	for(std::set<Neuron*>::iterator i=mAllNeurons.begin(),ie=mAllNeurons.end();i!=ie; ++i) {
			 if( *i == deletedNeuron){
				 mAllNeurons.erase(*i);
				 break;
			 }
	}
}

/**
 *	@param Synapse *activeSynapse - a synapse to activate
 *	@return	the beginning element of the active synapses list for this brain
 *
 *	Description:	Adds a new synapse to the brain (at front of active synapse list)
 *					and returns the front element of the list
**/
std::list<Synapse *>::iterator Brain::activateSynapse(Synapse *activeSynapse){
    mActiveSynapses.push_front(activeSynapse);
    return mActiveSynapses.begin();
}
/**
 *	@param Neuron *activeNeuron - a neuron to activate
 *	@return	the beginning element of the active neuron list for this brain
 *
 *	Description:	Adds a new neuron to the brain (at front of active neuron list)
 *					and returns the front element of the list
**/
std::list<Neuron *>::iterator Brain::activateNeuron(Neuron *activeNeuron){
  activeNeuron->mActivity=5.0f;
  mActiveNeurons.push_front(activeNeuron);
  return mActiveNeurons.begin();
}

/**
 *	Brain destructor
**/
Brain::~Brain() {
	for(std::set<Neuron*>::iterator i=mAllNeurons.begin(),ie=mAllNeurons.end();i!=ie;++i){
		delete *i;
	}
    delete mSpatialSearch;
    delete mProteinMap;
    for (std::vector<BrainPlugin*>::iterator i=mPlugins.begin(),ie=mPlugins.end();i!=ie;++i) {
        delete *i;
    }
}

Neuron* Brain::createInputNeuron(float x, float y, float z, float spread){
	Genome::Gene gene;
    Genome::TemporalBoundingBox *sourcebb=gene.add_bounds();
    Genome::TemporalBoundingBox *dendritebb=gene.add_bounds();
    sourcebb->set_minx(x-spread);
    sourcebb->set_miny(y-spread);
    sourcebb->set_minz(0);
    sourcebb->set_maxx(x+spread);
    sourcebb->set_maxy(y+spread);
    sourcebb->set_maxz(0);

    dendritebb->set_minx(0);
    dendritebb->set_miny(0);
    dendritebb->set_minz(0);
    dendritebb->set_maxx(0);
    dendritebb->set_maxy(0);
    dendritebb->set_maxz(0);

	Vector3f v;
	v.x = x;
	v.y = y;
	v.z = z;
	Neuron *n;
	this->mAllNeurons.insert(n = new Neuron(this, 0, 0, 0, 1, 1, v,gene));
	this->mDevelopingNeurons.insert(n);
	return n;
}
void Brain::notifyPluginsNeuronDestruction(Neuron * mfd){
    for (std::vector<BrainPlugin*>::iterator i=mPlugins.begin(),ie=mPlugins.end();i!=ie;++i){
        (*i)->notifyNeuronDestruction(mfd);
    }
}
void Brain::createInputRegion(int neurons){
	//At present, reserved location of input lobe is <0,0,0> to <5,5,0> neurons are added at 0.01 increments
	float minx = INPUT_REGION_MINX;
	float maxx = INPUT_REGION_MAXX;
	float miny = INPUT_REGION_MINY;
	float maxy = INPUT_REGION_MAXY;
	float spacing = INPUT_REGION_SPACING;
	float spread = INPUT_AXON_SPREAD;

	if(neurons > (maxx-minx)*(maxy-miny)/spacing){
		assert(this);
	}
	Neuron* n;
	float x=minx;
	float y=miny;

	for(int i=0;i<neurons;i++){
		n = createInputNeuron(x,y,0,spread);
		mInputNeurons.push_back(n);
		x += spacing;
		if(x >= maxx){
			x = minx;
			y += spacing;
		}
	}
}

void Brain::fireInputNeuron(int neuronNumber){
	Neuron* n= mInputNeurons[neuronNumber];
	n->setActivity(5);
	this -> activateNeuron(n);
	//printf("input");
}

void Brain::processDevelopment(){
	for(std::set<Neuron*>::iterator i=mAllNeurons.begin(),ie=mAllNeurons.end();i!=ie;++i){
		(*i)->tick();
	}
}

/**
 * @return the bounds of all genes in the brain, i.e. where the farthest neurons may spout
 */
BoundingBox3f3f Brain::getBounds()const{

//    return BoundingBox3f3f(Vector3f(0,00,00),Vector3f(1000,1000,1000));
    return mProteinMap->getBounds();
}

}

<commit_msg>The set problem is fixed. Thanks Daniel!<commit_after>#include "Platform.hpp"
#include "genome.pb.h"
#include "Brain.hpp"
#include "ProteinEnvironment.hpp"
#include "Neuron.hpp"
#include "Synapse.hpp"
#include "SimpleSpatialSearch.hpp"
#include "BrainPlugins.hpp"
#include "BrainPlugin.hpp"

#define INPUT_NEURONS			100
#define INPUT_REGION_MINX		0.0f
#define INPUT_REGION_MAXX		5.0f
#define INPUT_REGION_MINY		0.0f
#define INPUT_REGION_MAXY		5.0f
#define INPUT_REGION_SPACING	0.01f	//This also implies max input neurons of ((max-min)/spacing)^2
#define INPUT_AXON_SPREAD		0.0f	//The range of axon locations from input neurons
#define DEVELOPMENT_TICKS		10		//How often development neurons are re-evaluated

#include <boost/math/distributions/uniform.hpp>
#include <boost/random.hpp>

namespace Elysia {

/**
 *  @param ProteinEnvironment *proteinMap - a base protein map for the brain
 *
 *	Description:	Creates a new Brain instance using a defined protein map as a base.
 *					Also adds a new spatial search instance, sets the brain's age to 0 and
 *					initializes all requisite brain plugins
**/
Brain::Brain (ProteinEnvironment *proteinMap){
    mProteinMap=proteinMap;
    mSpatialSearch=new SimpleSpatialSearch;
    mAge=0;
	mDevelopmentCounter=0;
	createInputRegion(INPUT_NEURONS);
    makeInitialNeurons();
    BrainPlugins::constructAll(this).swap(mPlugins);
}

void Brain::syncEnvironmentNeurons(unsigned int index, ProteinEnvironment::iterator environmentIterator){
    Elysia::Genome::Effect growEffect=Elysia::Genome::GROW_NEURON;
    float neuronDensity =environmentIterator.getProteinDensity(growEffect);
    BoundingBox3f3f bounds = environmentIterator.getBoundingBox();
    float area = bounds.across().x*bounds.across().y;
    float expectedNumNeurons=neuronDensity*area;
    boost::minstd_rand randGen(1+index);//needs to be >0
    boost::uniform_real<> uni_dist(0.0f,1.0f);
    boost::variate_generator<boost::minstd_rand, boost::uniform_real<> > uniform(randGen,uni_dist);
    if (expectedNumNeurons-floor(expectedNumNeurons)<uniform()) {
        expectedNumNeurons=ceil(expectedNumNeurons);
    }else {
        expectedNumNeurons=floor(expectedNumNeurons);
    }
    int numNeurons=(unsigned int)expectedNumNeurons;
    if (numNeurons<mNumNeurons[index]) {
        //FIXME: do we want to delete excess neurons
    }
    for (int n=mNumNeurons[index];n<numNeurons;++n) {
        this->addNeuron(bounds, environmentIterator.retrieveGene(growEffect));
    }
    if (mNumNeurons[index]!=numNeurons) {
        fprintf(stderr,"The index count isn't equal to the sync count:\nthis could happen if a neuron lies at the exact edge of a lobe,\nso don't panic, but verify that this is indeed the case\nand the wrong count got updated for that neuron");
    }
}

void Brain::makeInitialNeurons() {
    unsigned int index=0;
    for (ProteinEnvironment::iterator i=mProteinMap->begin();
         i!=mProteinMap->end();
         ++i,++index) {
        mNumNeurons[i.uid()]=0;
        syncEnvironmentNeurons(index,i);
        //FIXME add numNeurons to the count in this protein zone so we can add/remove more later
    }
}

Neuron * Brain::addNeuron(const BoundingBox3f3f&generationArea, const Genome::Gene&gene) {
    Vector3f v = generationArea.min();
    v.x+=generationArea.across().x*(rand()/(double)RAND_MAX);
    v.y+=generationArea.across().y*(rand()/(double)RAND_MAX);
	v.z=0;	 //Fixing z to 0 for now.
    //v.z+=generationArea.across().z*(rand()/(double)RAND_MAX);
	Neuron *n = new Neuron(this, 2, 3, 4, 1, 1, v, gene);
    mAllNeurons.insert(n);
    return n;
}

/**
 *	Description:	One "tick" of the brain simulation code, where the following occurs:
 *					 - processNeuron() called
 *					 - processSynapes() called
 *					 - increments the current time in the simulation
 *					 - ages the brain
 *					 - updates all the plugins for this brain
**/
void Brain::tick(){
	processNeuron();
	processSynapse();
	//developAllNeurons();
    ++mCurTime;
	++mDevelopmentCounter;
	if(mDevelopmentCounter%10 == 0)this->processDevelopment();
    mAge+=1.0e-6;//fixme this is probably not correct: we probably need genes to do this
    if (mAge>1.0) mAge=1.0;
    for(std::vector<BrainPlugin*>::iterator i=mPlugins.begin(),ie=mPlugins.end();i!=ie;++i) {
        (*i)->update();
    }
}

void Brain::developAllNeurons(){
	for(std::set<Neuron*>::iterator i=mAllNeurons.begin(),ie=mAllNeurons.end();i!=ie;++i){
		(*i)->developSynapse((*i)->getActivityStats());
	}
}

/**
 *	Description:	Updates all neurons in the neuron list for this brain, then clears the list of
 *					active neurons
**/
void Brain::processNeuron(){
	for (std::list<Neuron*>::iterator i=mActiveNeurons.begin(),ie=mActiveNeurons.end();
         i!=ie;
		 ++i) {
        (*i)->tick();
	}
	mActiveNeurons.clear();
}

/**
 *	Description:	Iterates through brain's associates synapses and updates all of them using
 *					the Synapse class residualFire() method
**/
void Brain::processSynapse(){
    std::list<Synapse*>::iterator j,i=mActiveSynapses.begin(),ie=mActiveSynapses.end();
	while (i!=ie) {
        std::list<Synapse*>::iterator j=i++;
        (*j)->residualFire();
	}
}

/**
 *	@param Synapse *inactiveSynapse - synapse to remove
 *
 *	Description:	Removes a synapse from the synapse list and updates it.
**/
void Brain::inactivateSynapse(Synapse *inactiveSynapse){
    if (inactiveSynapse->mWhere!=activeSynapseListSentinel()) {
        mActiveSynapses.erase(inactiveSynapse->mWhere);
        inactiveSynapse->mWhere=activeSynapseListSentinel();
    }
}

/* Removed when AllSynapses set removed
void Brain::deleteSynapse(Synapse *deletedSynapse){

	for(std::set<Synapse*>::iterator j=mAllSynapses.begin(),je=mAllSynapses.end();j!=je; ++j) {
			 if( *j == deletedSynapse){
				 mAllSynapses.erase(*j);
			 }
	}

}
*/

/**
 *	@param Neuron *inactiveNeuron - an inactive neuron to remove
 *
 *	Description:	Removes an unused neuron from the neuron list and updates
**/
void Brain::inactivateNeuron(Neuron *inactiveNeuron){
    if (inactiveNeuron->mWhere!=activeNeuronListSentinel()) {
        mActiveNeurons.erase(inactiveNeuron->mWhere);
        inactiveNeuron->mWhere=activeNeuronListSentinel();
    }
}

void Brain::deleteNeuron(Neuron *deletedNeuron){
	for(std::set<Neuron*>::iterator i=mAllNeurons.begin(),ie=mAllNeurons.end();i!=ie; ++i) {
			 if( *i == deletedNeuron){
				 mAllNeurons.erase(*i);
				 break;
			 }
	}
}

/**
 *	@param Synapse *activeSynapse - a synapse to activate
 *	@return	the beginning element of the active synapses list for this brain
 *
 *	Description:	Adds a new synapse to the brain (at front of active synapse list)
 *					and returns the front element of the list
**/
std::list<Synapse *>::iterator Brain::activateSynapse(Synapse *activeSynapse){
    mActiveSynapses.push_front(activeSynapse);
    return mActiveSynapses.begin();
}
/**
 *	@param Neuron *activeNeuron - a neuron to activate
 *	@return	the beginning element of the active neuron list for this brain
 *
 *	Description:	Adds a new neuron to the brain (at front of active neuron list)
 *					and returns the front element of the list
**/
std::list<Neuron *>::iterator Brain::activateNeuron(Neuron *activeNeuron){
  activeNeuron->mActivity=5.0f;
  mActiveNeurons.push_front(activeNeuron);
  return mActiveNeurons.begin();
}

/**
 *	Brain destructor
**/
Brain::~Brain() {
	while(!mAllNeurons.empty()){
        delete *mAllNeurons.begin();
    }
    delete mSpatialSearch;
    delete mProteinMap;
    for (std::vector<BrainPlugin*>::iterator i=mPlugins.begin(),ie=mPlugins.end();i!=ie;++i) {
        delete *i;
    }
}

Neuron* Brain::createInputNeuron(float x, float y, float z, float spread){
	Genome::Gene gene;
    Genome::TemporalBoundingBox *sourcebb=gene.add_bounds();
    Genome::TemporalBoundingBox *dendritebb=gene.add_bounds();
    sourcebb->set_minx(x-spread);
    sourcebb->set_miny(y-spread);
    sourcebb->set_minz(0);
    sourcebb->set_maxx(x+spread);
    sourcebb->set_maxy(y+spread);
    sourcebb->set_maxz(0);

    dendritebb->set_minx(0);
    dendritebb->set_miny(0);
    dendritebb->set_minz(0);
    dendritebb->set_maxx(0);
    dendritebb->set_maxy(0);
    dendritebb->set_maxz(0);

	Vector3f v;
	v.x = x;
	v.y = y;
	v.z = z;
	Neuron *n;
	this->mAllNeurons.insert(n = new Neuron(this, 0, 0, 0, 1, 1, v,gene));
	this->mDevelopingNeurons.insert(n);
	return n;
}
void Brain::notifyPluginsNeuronDestruction(Neuron * mfd){
    for (std::vector<BrainPlugin*>::iterator i=mPlugins.begin(),ie=mPlugins.end();i!=ie;++i){
        (*i)->notifyNeuronDestruction(mfd);
    }
}
void Brain::createInputRegion(int neurons){
	//At present, reserved location of input lobe is <0,0,0> to <5,5,0> neurons are added at 0.01 increments
	float minx = INPUT_REGION_MINX;
	float maxx = INPUT_REGION_MAXX;
	float miny = INPUT_REGION_MINY;
	float maxy = INPUT_REGION_MAXY;
	float spacing = INPUT_REGION_SPACING;
	float spread = INPUT_AXON_SPREAD;

	if(neurons > (maxx-minx)*(maxy-miny)/spacing){
		assert(this);
	}
	Neuron* n;
	float x=minx;
	float y=miny;

	for(int i=0;i<neurons;i++){
		n = createInputNeuron(x,y,0,spread);
		mInputNeurons.push_back(n);
		x += spacing;
		if(x >= maxx){
			x = minx;
			y += spacing;
		}
	}
}

void Brain::fireInputNeuron(int neuronNumber){
	Neuron* n= mInputNeurons[neuronNumber];
	n->setActivity(5);
	this -> activateNeuron(n);
	//printf("input");
}

void Brain::processDevelopment(){
	for(std::set<Neuron*>::iterator i=mAllNeurons.begin(),ie=mAllNeurons.end();i!=ie;++i){
		(*i)->tick();
	}
}

/**
 * @return the bounds of all genes in the brain, i.e. where the farthest neurons may spout
 */
BoundingBox3f3f Brain::getBounds()const{

//    return BoundingBox3f3f(Vector3f(0,00,00),Vector3f(1000,1000,1000));
    return mProteinMap->getBounds();
}

}

<|endoftext|>