<commit_before>/** -*- c++ -*-
 * progressdialog.cpp
 *
 *  Copyright (c) 2004 Till Adam <adam@kde.org>,
 *                     David Faure <faure@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; version 2 of the License
 *
 *  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.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <qapplication.h>
#include <qlayout.h>
#include <qprogressbar.h>
#include <qtimer.h>
#include <qheader.h>
#include <qobject.h>
#include <qscrollview.h>
#include <qtoolbutton.h>
#include <qpushbutton.h>
#include <qvbox.h>
#include <qtooltip.h>

#include <klocale.h>
#include <kdialog.h>
#include <kstdguiitem.h>
#include <kiconloader.h>
#include <kdebug.h>

#include "progressdialog.h"
#include "progressmanager.h"
#include "ssllabel.h"
#include <qwhatsthis.h>

namespace KPIM {

class TransactionItem;

TransactionItemView::TransactionItemView( QWidget * parent,
                                          const char * name,
                                          WFlags f )
    : QScrollView( parent, name, f ) {
  setFrameStyle( NoFrame );
  mBigBox = new QVBox( viewport() );
  mBigBox->setSpacing( 5 );
  addChild( mBigBox );
  setResizePolicy( QScrollView::AutoOneFit ); // Fit so that the box expands horizontally
}

TransactionItem* TransactionItemView::addTransactionItem( ProgressItem* item, bool first )
{
   TransactionItem *ti = new TransactionItem( mBigBox, item, first );
   ti->hide();
   QTimer::singleShot( 1000, ti, SLOT( show() ) );
   return ti;
}

void TransactionItemView::resizeContents( int w, int h )
{
  //kdDebug(5300) << k_funcinfo << w << "," << h << endl;
  QScrollView::resizeContents( w, h );
  // Tell the layout in the parent (progressdialog) that our size changed
  updateGeometry();
  // Resize the parent (progressdialog) - this works but resize horizontally too often
  //parentWidget()->adjustSize();

  QApplication::sendPostedEvents( 0, QEvent::ChildInserted );
  QApplication::sendPostedEvents( 0, QEvent::LayoutHint );
  QSize sz = parentWidget()->sizeHint();
  int currentWidth = parentWidget()->width();
  // Don't resize to sz.width() every time when it only reduces a little bit
  if ( currentWidth < sz.width() || currentWidth > sz.width() + 100 )
    currentWidth = sz.width();
  parentWidget()->resize( currentWidth, sz.height() );
}

QSize TransactionItemView::sizeHint() const
{
  return minimumSizeHint();
}

QSize TransactionItemView::minimumSizeHint() const
{
  int f = 2 * frameWidth();
  // Make room for a vertical scrollbar in all cases, to avoid a horizontal one
  int vsbExt = verticalScrollBar()->sizeHint().width();
  int minw = topLevelWidget()->width() / 3;
  int maxh = topLevelWidget()->height() / 2;
  QSize sz( mBigBox->minimumSizeHint() );
  sz.setWidth( QMAX( sz.width(), minw ) + f + vsbExt );
  sz.setHeight( QMIN( sz.height(), maxh ) + f );
  return sz;
}

void TransactionItemView::slotLayoutFirstItem()
{
  /*
     The below relies on some details in Qt's behaviour regarding deleting
     objects. This slot is called from the destroyed signal of an item just
     going away. That item is at that point still in the  list of chilren, but
     since the vtable is already gone, it will have type QObject. The first
     one with both the right name and the right class therefor is what will
     be the first item very shortly. That's the one we want to remove the
     hline for.
  */
  QObject *o = mBigBox->child( "TransactionItem", "KPIM::TransactionItem" );
  TransactionItem *ti = dynamic_cast<TransactionItem*>( o );
  if ( ti ) {
    ti->hideHLine();
  }
}

// ----------------------------------------------------------------------------

TransactionItem::TransactionItem( QWidget* parent,
                                  ProgressItem *item, bool first )
  : QVBox( parent, "TransactionItem" ), mCancelButton( 0 ), mItem( item )

{
  setSpacing( 2 );
  setMargin( 2 );
  setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );

  mFrame = new QFrame( this );
  mFrame->setFrameShape( QFrame::HLine );
  mFrame->setFrameShadow( QFrame::Raised );
  mFrame->show();
  setStretchFactor( mFrame, 3 );

  QHBox *h = new QHBox( this );
  h->setSpacing( 5 );

  mItemLabel = new QLabel( item->label(), h );
  h->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );

  if ( item->canBeCanceled() ) {
    mCancelButton = new QPushButton( SmallIcon( "cancel" ), QString::null, h );
    QToolTip::add( mCancelButton, i18n("Cancel this operation.") );
    connect ( mCancelButton, SIGNAL( clicked() ),
              this, SLOT( slotItemCanceled() ));
  }
  mProgress = new QProgressBar( 100, h );
  mProgress->setProgress( item->progress() );

  h = new QHBox( this );
  h->setSpacing( 5 );
  h->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
  mSSLLabel = new SSLLabel( h );
  mSSLLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
  mItemStatus =  new QLabel( item->status(), h );
  setCrypto( item->usesCrypto() );
  if( first ) hideHLine();
}

TransactionItem::~TransactionItem()
{
}

void TransactionItem::hideHLine()
{
    mFrame->hide();
}

void TransactionItem::setProgress( int progress )
{
  mProgress->setProgress( progress );
}

void TransactionItem::setLabel( const QString& label )
{
  mItemLabel->setText( label );
}

void TransactionItem::setStatus( const QString& status )
{
  mItemStatus->setText( status );
}

void TransactionItem::setCrypto( bool on )
{
  if (on)
    mSSLLabel->setEncrypted( true );
  else
    mSSLLabel->setEncrypted( false );

  mSSLLabel->setState( mSSLLabel->lastState() );
}

void TransactionItem::slotItemCanceled()
{
  if ( mItem )
    mItem->cancel();
}

void TransactionItem::addSubTransaction( ProgressItem* /*item*/ )
{

}

// ---------------------------------------------------------------------------

ProgressDialog::ProgressDialog( QWidget* alignWidget, QWidget* parent, const char* name )
    : OverlayWidget( alignWidget, parent, name )
{
    setFrameStyle( QFrame::Panel | QFrame::Sunken ); // QFrame
    setSpacing( 0 ); // QHBox
    setMargin( 1 );

    mScrollView = new TransactionItemView( this, "ProgressScrollView" );

    QVBox* rightBox = new QVBox( this );
    QToolButton* pbClose = new QToolButton( rightBox );
    pbClose->setAutoRaise(true);
    pbClose->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
    pbClose->setFixedSize( 16, 16 );
    pbClose->setIconSet( KGlobal::iconLoader()->loadIconSet( "fileclose", KIcon::Small, 14 ) );
    QToolTip::add( pbClose, i18n( "Hide detailed progress window" ) );
    connect(pbClose, SIGNAL(clicked()), this, SLOT(slotClose()));
    QWidget* spacer = new QWidget( rightBox ); // don't let the close button take up all the height
    rightBox->setStretchFactor( spacer, 100 );

    /*
     * Get the singleton ProgressManager item which will inform us of
     * appearing and vanishing items.
     */
    ProgressManager *pm = ProgressManager::instance();
    connect ( pm, SIGNAL( progressItemAdded( KPIM::ProgressItem* ) ),
              this, SLOT( slotTransactionAdded( KPIM::ProgressItem* ) ) );
    connect ( pm, SIGNAL( progressItemCompleted( KPIM::ProgressItem* ) ),
              this, SLOT( slotTransactionCompleted( KPIM::ProgressItem* ) ) );
    connect ( pm, SIGNAL( progressItemProgress( KPIM::ProgressItem*, unsigned int ) ),
              this, SLOT( slotTransactionProgress( KPIM::ProgressItem*, unsigned int ) ) );
    connect ( pm, SIGNAL( progressItemStatus( KPIM::ProgressItem*, const QString& ) ),
              this, SLOT( slotTransactionStatus( KPIM::ProgressItem*, const QString& ) ) );
    connect ( pm, SIGNAL( progressItemLabel( KPIM::ProgressItem*, const QString& ) ),
              this, SLOT( slotTransactionLabel( KPIM::ProgressItem*, const QString& ) ) );
    connect ( pm, SIGNAL( progressItemUsesCrypto(KPIM::ProgressItem*, bool) ),
              this, SLOT( slotTransactionUsesCrypto( KPIM::ProgressItem*, bool ) ) );
    connect ( pm, SIGNAL( showProgressDialog() ),
              this, SLOT( slotShow() ) );
}

void ProgressDialog::closeEvent( QCloseEvent* e )
{
  e->accept();
  hide();
}

/*
 *  Destructor
 */
ProgressDialog::~ProgressDialog()
{
    // no need to delete child widgets.
}

void ProgressDialog::slotTransactionAdded( ProgressItem *item )
{
   TransactionItem *parent = 0;
   if ( item->parent() ) {
     if ( mTransactionsToListviewItems.contains( item->parent() ) ) {
       parent = mTransactionsToListviewItems[ item->parent() ];
       parent->addSubTransaction( item );
     }
   } else {
     TransactionItem *ti = mScrollView->addTransactionItem( item, mTransactionsToListviewItems.empty() );
     if ( ti )
       mTransactionsToListviewItems.replace( item, ti );
   }
}

void ProgressDialog::slotTransactionCompleted( ProgressItem *item )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     mTransactionsToListviewItems.remove( item );
     ti->setItemComplete();
     QTimer::singleShot( 3000, ti, SLOT( deleteLater() ) );
     // see the slot for comments as to why that works
     connect ( ti, SIGNAL( destroyed() ),
               mScrollView, SLOT( slotLayoutFirstItem() ) );
   }
   // This was the last item, hide.
   if ( mTransactionsToListviewItems.empty() )
     QTimer::singleShot( 3000, this, SLOT( slotHide() ) );
}

void ProgressDialog::slotTransactionCanceled( ProgressItem* )
{
}

void ProgressDialog::slotTransactionProgress( ProgressItem *item,
                                              unsigned int progress )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setProgress( progress );
   }
}

void ProgressDialog::slotTransactionStatus( ProgressItem *item,
                                            const QString& status )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setStatus( status );
   }
}

void ProgressDialog::slotTransactionLabel( ProgressItem *item,
                                           const QString& label )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setLabel( label );
   }
}

void ProgressDialog::slotTransactionUsesCrypto( ProgressItem *item,
                                                bool value )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setCrypto( value );
   }
}

void ProgressDialog::slotShow()
{
   setVisible( true );
}

void ProgressDialog::slotHide()
{
  // check if a new item showed up since we started the timer. If not, hide
  if ( mTransactionsToListviewItems.isEmpty() ) {
    setVisible( false );
  }
}

void ProgressDialog::slotClose()
{
  setVisible( false );
}

void ProgressDialog::setVisible( bool b )
{
  if ( b )
      show();
    else
      hide();
  emit visibilityChanged( b );
}

void ProgressDialog::slotToggleVisibility()
{
  /* Since we are only hiding with a timeout, there is a short period of
   * time where the last item is still visible, but clicking on it in
   * the statusbarwidget should not display the dialog, because there
   * are no items to be shown anymore. Guard against that.
   */
  if ( isShown() || !mTransactionsToListviewItems.isEmpty() )
    setVisible( !isShown() );
}

}

#include "progressdialog.moc"
<commit_msg>Move the cancel button to the right of the progress bar, so they are all aligned and remove the dialog cancel button, since it's not used, apparently, and not needed, since we hide via click on the status bar widget and the arrow button.<commit_after>/** -*- c++ -*-
 * progressdialog.cpp
 *
 *  Copyright (c) 2004 Till Adam <adam@kde.org>,
 *                     David Faure <faure@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; version 2 of the License
 *
 *  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.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <qapplication.h>
#include <qlayout.h>
#include <qprogressbar.h>
#include <qtimer.h>
#include <qheader.h>
#include <qobject.h>
#include <qscrollview.h>
#include <qtoolbutton.h>
#include <qpushbutton.h>
#include <qvbox.h>
#include <qtooltip.h>

#include <klocale.h>
#include <kdialog.h>
#include <kstdguiitem.h>
#include <kiconloader.h>
#include <kdebug.h>

#include "progressdialog.h"
#include "progressmanager.h"
#include "ssllabel.h"
#include <qwhatsthis.h>

namespace KPIM {

class TransactionItem;

TransactionItemView::TransactionItemView( QWidget * parent,
                                          const char * name,
                                          WFlags f )
    : QScrollView( parent, name, f ) {
  setFrameStyle( NoFrame );
  mBigBox = new QVBox( viewport() );
  mBigBox->setSpacing( 5 );
  addChild( mBigBox );
  setResizePolicy( QScrollView::AutoOneFit ); // Fit so that the box expands horizontally
}

TransactionItem* TransactionItemView::addTransactionItem( ProgressItem* item, bool first )
{
   TransactionItem *ti = new TransactionItem( mBigBox, item, first );
   ti->hide();
   QTimer::singleShot( 1000, ti, SLOT( show() ) );
   return ti;
}

void TransactionItemView::resizeContents( int w, int h )
{
  //kdDebug(5300) << k_funcinfo << w << "," << h << endl;
  QScrollView::resizeContents( w, h );
  // Tell the layout in the parent (progressdialog) that our size changed
  updateGeometry();
  // Resize the parent (progressdialog) - this works but resize horizontally too often
  //parentWidget()->adjustSize();

  QApplication::sendPostedEvents( 0, QEvent::ChildInserted );
  QApplication::sendPostedEvents( 0, QEvent::LayoutHint );
  QSize sz = parentWidget()->sizeHint();
  int currentWidth = parentWidget()->width();
  // Don't resize to sz.width() every time when it only reduces a little bit
  if ( currentWidth < sz.width() || currentWidth > sz.width() + 100 )
    currentWidth = sz.width();
  parentWidget()->resize( currentWidth, sz.height() );
}

QSize TransactionItemView::sizeHint() const
{
  return minimumSizeHint();
}

QSize TransactionItemView::minimumSizeHint() const
{
  int f = 2 * frameWidth();
  // Make room for a vertical scrollbar in all cases, to avoid a horizontal one
  int vsbExt = verticalScrollBar()->sizeHint().width();
  int minw = topLevelWidget()->width() / 3;
  int maxh = topLevelWidget()->height() / 2;
  QSize sz( mBigBox->minimumSizeHint() );
  sz.setWidth( QMAX( sz.width(), minw ) + f + vsbExt );
  sz.setHeight( QMIN( sz.height(), maxh ) + f );
  return sz;
}

void TransactionItemView::slotLayoutFirstItem()
{
  /*
     The below relies on some details in Qt's behaviour regarding deleting
     objects. This slot is called from the destroyed signal of an item just
     going away. That item is at that point still in the  list of chilren, but
     since the vtable is already gone, it will have type QObject. The first
     one with both the right name and the right class therefor is what will
     be the first item very shortly. That's the one we want to remove the
     hline for.
  */
  QObject *o = mBigBox->child( "TransactionItem", "KPIM::TransactionItem" );
  TransactionItem *ti = dynamic_cast<TransactionItem*>( o );
  if ( ti ) {
    ti->hideHLine();
  }
}

// ----------------------------------------------------------------------------

TransactionItem::TransactionItem( QWidget* parent,
                                  ProgressItem *item, bool first )
  : QVBox( parent, "TransactionItem" ), mCancelButton( 0 ), mItem( item )

{
  setSpacing( 2 );
  setMargin( 2 );
  setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );

  mFrame = new QFrame( this );
  mFrame->setFrameShape( QFrame::HLine );
  mFrame->setFrameShadow( QFrame::Raised );
  mFrame->show();
  setStretchFactor( mFrame, 3 );

  QHBox *h = new QHBox( this );
  h->setSpacing( 5 );

  mItemLabel = new QLabel( item->label(), h );
  h->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );

  mProgress = new QProgressBar( 100, h );
  mProgress->setProgress( item->progress() );

  if ( item->canBeCanceled() ) {
    mCancelButton = new QPushButton( SmallIcon( "cancel" ), QString::null, h );
    QToolTip::add( mCancelButton, i18n("Cancel this operation.") );
    connect ( mCancelButton, SIGNAL( clicked() ),
              this, SLOT( slotItemCanceled() ));
  }

  h = new QHBox( this );
  h->setSpacing( 5 );
  h->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
  mSSLLabel = new SSLLabel( h );
  mSSLLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
  mItemStatus =  new QLabel( item->status(), h );
  setCrypto( item->usesCrypto() );
  if( first ) hideHLine();
}

TransactionItem::~TransactionItem()
{
}

void TransactionItem::hideHLine()
{
    mFrame->hide();
}

void TransactionItem::setProgress( int progress )
{
  mProgress->setProgress( progress );
}

void TransactionItem::setLabel( const QString& label )
{
  mItemLabel->setText( label );
}

void TransactionItem::setStatus( const QString& status )
{
  mItemStatus->setText( status );
}

void TransactionItem::setCrypto( bool on )
{
  if (on)
    mSSLLabel->setEncrypted( true );
  else
    mSSLLabel->setEncrypted( false );

  mSSLLabel->setState( mSSLLabel->lastState() );
}

void TransactionItem::slotItemCanceled()
{
  if ( mItem )
    mItem->cancel();
}

void TransactionItem::addSubTransaction( ProgressItem* /*item*/ )
{

}

// ---------------------------------------------------------------------------

ProgressDialog::ProgressDialog( QWidget* alignWidget, QWidget* parent, const char* name )
    : OverlayWidget( alignWidget, parent, name )
{
    setFrameStyle( QFrame::Panel | QFrame::Sunken ); // QFrame
    setSpacing( 0 ); // QHBox
    setMargin( 1 );

    mScrollView = new TransactionItemView( this, "ProgressScrollView" );

    // No more close button for now, since there is no more autoshow
    /*
    QVBox* rightBox = new QVBox( this );
    QToolButton* pbClose = new QToolButton( rightBox );
    pbClose->setAutoRaise(true);
    pbClose->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
    pbClose->setFixedSize( 16, 16 );
    pbClose->setIconSet( KGlobal::iconLoader()->loadIconSet( "fileclose", KIcon::Small, 14 ) );
    QToolTip::add( pbClose, i18n( "Hide detailed progress window" ) );
    connect(pbClose, SIGNAL(clicked()), this, SLOT(slotClose()));
    QWidget* spacer = new QWidget( rightBox ); // don't let the close button take up all the height
    rightBox->setStretchFactor( spacer, 100 );
    */

    /*
     * Get the singleton ProgressManager item which will inform us of
     * appearing and vanishing items.
     */
    ProgressManager *pm = ProgressManager::instance();
    connect ( pm, SIGNAL( progressItemAdded( KPIM::ProgressItem* ) ),
              this, SLOT( slotTransactionAdded( KPIM::ProgressItem* ) ) );
    connect ( pm, SIGNAL( progressItemCompleted( KPIM::ProgressItem* ) ),
              this, SLOT( slotTransactionCompleted( KPIM::ProgressItem* ) ) );
    connect ( pm, SIGNAL( progressItemProgress( KPIM::ProgressItem*, unsigned int ) ),
              this, SLOT( slotTransactionProgress( KPIM::ProgressItem*, unsigned int ) ) );
    connect ( pm, SIGNAL( progressItemStatus( KPIM::ProgressItem*, const QString& ) ),
              this, SLOT( slotTransactionStatus( KPIM::ProgressItem*, const QString& ) ) );
    connect ( pm, SIGNAL( progressItemLabel( KPIM::ProgressItem*, const QString& ) ),
              this, SLOT( slotTransactionLabel( KPIM::ProgressItem*, const QString& ) ) );
    connect ( pm, SIGNAL( progressItemUsesCrypto(KPIM::ProgressItem*, bool) ),
              this, SLOT( slotTransactionUsesCrypto( KPIM::ProgressItem*, bool ) ) );
    connect ( pm, SIGNAL( showProgressDialog() ),
              this, SLOT( slotShow() ) );
}

void ProgressDialog::closeEvent( QCloseEvent* e )
{
  e->accept();
  hide();
}

/*
 *  Destructor
 */
ProgressDialog::~ProgressDialog()
{
    // no need to delete child widgets.
}

void ProgressDialog::slotTransactionAdded( ProgressItem *item )
{
   TransactionItem *parent = 0;
   if ( item->parent() ) {
     if ( mTransactionsToListviewItems.contains( item->parent() ) ) {
       parent = mTransactionsToListviewItems[ item->parent() ];
       parent->addSubTransaction( item );
     }
   } else {
     TransactionItem *ti = mScrollView->addTransactionItem( item, mTransactionsToListviewItems.empty() );
     if ( ti )
       mTransactionsToListviewItems.replace( item, ti );
   }
}

void ProgressDialog::slotTransactionCompleted( ProgressItem *item )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     mTransactionsToListviewItems.remove( item );
     ti->setItemComplete();
     QTimer::singleShot( 3000, ti, SLOT( deleteLater() ) );
     // see the slot for comments as to why that works
     connect ( ti, SIGNAL( destroyed() ),
               mScrollView, SLOT( slotLayoutFirstItem() ) );
   }
   // This was the last item, hide.
   if ( mTransactionsToListviewItems.empty() )
     QTimer::singleShot( 3000, this, SLOT( slotHide() ) );
}

void ProgressDialog::slotTransactionCanceled( ProgressItem* )
{
}

void ProgressDialog::slotTransactionProgress( ProgressItem *item,
                                              unsigned int progress )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setProgress( progress );
   }
}

void ProgressDialog::slotTransactionStatus( ProgressItem *item,
                                            const QString& status )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setStatus( status );
   }
}

void ProgressDialog::slotTransactionLabel( ProgressItem *item,
                                           const QString& label )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setLabel( label );
   }
}

void ProgressDialog::slotTransactionUsesCrypto( ProgressItem *item,
                                                bool value )
{
   if ( mTransactionsToListviewItems.contains( item ) ) {
     TransactionItem *ti = mTransactionsToListviewItems[ item ];
     ti->setCrypto( value );
   }
}

void ProgressDialog::slotShow()
{
   setVisible( true );
}

void ProgressDialog::slotHide()
{
  // check if a new item showed up since we started the timer. If not, hide
  if ( mTransactionsToListviewItems.isEmpty() ) {
    setVisible( false );
  }
}

void ProgressDialog::slotClose()
{
  setVisible( false );
}

void ProgressDialog::setVisible( bool b )
{
  if ( b )
      show();
    else
      hide();
  emit visibilityChanged( b );
}

void ProgressDialog::slotToggleVisibility()
{
  /* Since we are only hiding with a timeout, there is a short period of
   * time where the last item is still visible, but clicking on it in
   * the statusbarwidget should not display the dialog, because there
   * are no items to be shown anymore. Guard against that.
   */
  if ( isShown() || !mTransactionsToListviewItems.isEmpty() )
    setVisible( !isShown() );
}

}

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


<commit_before>/*
   Min Kao Drone Tour
   Modified by Elliot Greenlee
 */

#include "objectFollowing.h"
#include "../control.h"
#include <string>
using namespace std;

const string THRESHOLDS_FILE_NAME = "thresholds.xml";
const double dt = 1.0; //Sampling time [s]

/*
 */
ObjectFollowing::ObjectFollowing(Control *control) {
  control_ptr = control;
  kalman = cv::KalmanFilter(4, 2, 0);

  // XML save data for object following color thresholds
  cv::FileStorage fs(THRESHOLDS_FILE_NAME, cv::FileStorage::READ);

  // If there is a save file then read it
  if (fs.isOpened()) {
    maxH = fs["H_MAX"];
    minH = fs["H_MIN"];
    maxS = fs["S_MAX"];
    minS = fs["S_MIN"];
    maxV = fs["V_MAX"];
    minV = fs["V_MIN"];
    fs.release();
  }

  // Create a window
  cv::namedWindow("binalized");
  cv::createTrackbar("Hue max", "binalized", &maxH, 255);
  cv::createTrackbar("Hue min", "binalized", &minH, 255);
  cv::createTrackbar("Saturation max", "binalized", &maxS, 255);
  cv::createTrackbar("Saturation min", "binalized", &minS, 255);
  cv::createTrackbar("Value max", "binalized", &maxV, 255);
  cv::createTrackbar("Value min", "binalized", &minV, 255);
  cv::resizeWindow("binalized", 0, 0);

  // Transition matrix (x, y, vx, vy)
  cv::Mat1f A(4, 4);
  A << 1.0, 0.0,  dt, 0.0,
    0.0, 1.0, 0.0,  dt,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0;
  kalman.transitionMatrix = A;

  // Measurement matrix (x, y)
  cv::Mat1f H(2, 4);
  H << 1, 0, 0, 0,
    0, 1, 0, 0;
  kalman.measurementMatrix = H;

  // Process noise covairance (x, y, vx, vy)
  cv::Mat1f Q(4, 4);
  Q << 1e-5,  0.0,  0.0,  0.0,
    0.0, 1e-5,  0.0,  0.0,
    0.0,  0.0, 1e-5,  0.0,
    0.0,  0.0,  0.0, 1e-5;
  kalman.processNoiseCov = Q;

  // Measurement noise covariance (x, y)
  cv::Mat1f R(2, 2);
  R << 1e-1,  0.0,
    0.0, 1e-1;
  kalman.measurementNoiseCov = R;
}

/*
 */
void ObjectFollowing::close() {
  //Save thresholds
  cv::FileStorage fs(THRESHOLDS_FILE_NAME, cv::FileStorage::READ);
  fs.open(THRESHOLDS_FILE_NAME, cv::FileStorage::WRITE);
  if (fs.isOpened()) {
    cv::write(fs, "H_MAX", maxH);
    cv::write(fs, "H_MIN", minH);
    cv::write(fs, "S_MAX", maxS);
    cv::write(fs, "S_MIN", minS);
    cv::write(fs, "V_MAX", maxV);
    cv::write(fs, "V_MIN", minV);
    fs.release();
  }
}

/*
   returns heading for control
 */
void ObjectFollowing::fly() {

  ControlMovements *controlMovements = &(control_ptr->velocities);
  cv::Mat *image = &(control_ptr->image);

  cv::Vec3b hsvSample;
  int tolerance = 50;
  int avgHue;
  int avgSaturation;
  int avgValue;
  int numPoints;
  cv::Scalar green = CV_RGB(0,255,0); //putText color value

  //switch between learning and non-learning mode
  if (control_ptr->key == 'l') {
    learnMode = !learnMode;
    if (learnMode) {
      printf("Learning mode is enabled\n");
      printf("The color at the crosshairs is being learned\n");
      printf("Press l again to turn off learning mode\n\n");
    }
    else {
      printf("Learning mode is disabled\n");
      printf("The color last at the crosshairs will be targeted\n");
      printf("Press l again to learn a different color\n\n");
    }
  }

  // HSV image
  cv::Mat hsv;
  cv::cvtColor(*image, hsv, cv::COLOR_BGR2HSV_FULL);

  // Binalize
  cv::Mat binalized;
  cv::Scalar lower(minH, minS, minV);
  cv::Scalar upper(maxH, maxS, maxV);
  cv::inRange(hsv, lower, upper, binalized);

  // Show result
  cv::imshow("binalized", binalized);

  // De-noising
  cv::Mat kernel = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
  cv::morphologyEx(binalized, binalized, cv::MORPH_CLOSE, kernel);

  // Detect contours
  vector<vector<cv::Point> > contours;
  cv::findContours(binalized.clone(), contours, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);

  // Find largest contour
  int contour_index = -1;
  double max_area = 0.0;
  for (size_t i = 0; i < contours.size(); i++) {
    double area = fabs(cv::contourArea(contours[i]));
    if (area > max_area) {
      contour_index = i;
      max_area = area;
    }
  }

  // Object detected
  if (contour_index >= 0) {

    // Moments
    cv::Moments moments = cv::moments(contours[contour_index], true);
    double marker_y = (int)(moments.m01 / moments.m00);
    double marker_x = (int)(moments.m10 / moments.m00);

    // Measurements
    cv::Mat measurement = (cv::Mat1f(2, 1) << marker_x, marker_y);

    // Correction
    cv::Mat estimated = kalman.correct(measurement);

    // Show result
    rect = cv::boundingRect(contours[contour_index]);
    cv::rectangle(*image, rect, cv::Scalar(0, 255, 0));

    // Calculate average hsv for the object within the coutour
    //avgHue = hsvSample[0];
    //avgSaturation = hsvSample[1];
    //avgValue = hsvSample[2];
    numPoints = 1;

    //for x in rectangle
    for (int x = rect.x; x < rect.x + rect.width; x++) {
      //for y in rectangle
      for (int y = rect.y; y < rect.y + rect.height; y++) {
        // TODO: If this is to slow, use rectangle average or do every second, third, etc point in rectangle for loop
        //if (inContour(x, y, contours[contour_index])) {
        cv::Point pt(x,y);
        if (rect.contains(pt)) {
          cv::Vec3b hsvPoint = hsv.at<cv::Vec3b>(cvPoint(x, y));
          numPoints++;
          avgHue += hsvPoint[0];
          avgSaturation += hsvPoint[1];
          avgValue += hsvPoint[2];
        }
      }
    }

    avgHue = ((double)avgHue)/numPoints;
    avgSaturation = ((double)avgSaturation)/numPoints;
    avgValue = ((double)avgValue)/numPoints;
  }

  // Prediction
  cv::Mat1f prediction = kalman.predict();
  int radius = 1e+3 * kalman.errorCovPre.at<float>(0, 0);

  // Show predicted position
  cv::circle(*image, cv::Point(prediction(0, 0), prediction(0, 1)), radius, green, 2);

  // Calculate object heading fraction
  float rHeading = -(((*image).cols/2) - prediction(0, 0))/((*image).cols/2);
  float zHeading = -(((*image).rows/2) - prediction(0, 1))/((*image).rows/2);

/*
  if (abs(rHeading) <= 0.6 && abs(zHeading) <= 0.6) {
    hsvSample[0] = avgHue;
    hsvSample[1] = avgSaturation;
    hsvSample[2] = avgValue;

    minH = avgHue - tolerance;
    maxH = avgHue + tolerance;
    minS = avgSaturation - tolerance;
    maxS = avgSaturation + tolerance;
    minV = avgValue - tolerance;
    maxV = avgValue + tolerance;
  }
 */

  //Emergency landing
  if (abs(rHeading) <= 0.95 && abs(zHeading) <= 0.95) {
    lastSearchTime = time(0);
  }
  time_t currentTime = time(0);
  double elapsedTime = difftime(currentTime, lastSearchTime);
  printf("CALEB- elapsedTime: %f\n", elapsedTime);
  if (elapsedTime >= 4) {
    control_ptr->ardrone.landing();
  }

  // Sample the object color
  if(learnMode) {
    // Show targeting crosshairs
    cv::line(*image, cvPoint((*image).cols/2, 0), cvPoint((*image).cols/2, (*image).rows/2 - 2), green); //top vertical crosshair
    cv::line(*image, cvPoint((*image).cols/2, (*image).rows/2 + 2), cvPoint((*image).cols/2, (*image).rows), green); //bottom vertical crosshair
    cv::line(*image, cvPoint(0, (*image).rows/2), cvPoint((*image).cols/2 - 2, (*image).rows/2), green); //left horizontal crosshair
    cv::line(*image, cvPoint((*image).cols/2 + 2, (*image).rows/2), cvPoint((*image).cols, (*image).rows/2), green); //right horizontal crosshair

    hsvSample = hsv.at<cv::Vec3b>(cvPoint((*image).cols/2, (*image).rows/2));
    setHSVTrackBarPositions(hsvSample[0], hsvSample[1], hsvSample[2], tolerance);
  }

  displayObjectFollowingInfo(image, rHeading, zHeading, hsvSample[0], hsvSample[1], hsvSample[2]);

  rect_area = rect.width * rect.height;

  // Set forward/backward movement
  controlMovements->vx = (goalArea - rect_area)/((double)goalArea);

  if(controlMovements->vx > 1) {
    controlMovements->vx = 1;
  }
  else if (controlMovements->vx < -1){
    controlMovements->vx = -1;
  }

  time_t current_time = time(0);
  double elapsed_time = difftime(current_time, control_ptr->takeoff_time);
  if (elapsed_time < 5){
    controlMovements->vx = 0;
    controlMovements->vy = 0;
    controlMovements->vz = 0;
    controlMovements->vr = 0;
  } else {
    printf("elapsed time: %f\n", elapsed_time);
    controlMovements->vz = -(zHeading * 0.2);
    controlMovements->vr = -(rHeading * 0.5);
    if (controlMovements->vx < 0.5 && controlMovements->vx > 0) {
      controlMovements->vx = pow(controlMovements->vx, 2);
    }
  }

  return;
}

//Auto set Hue, Saturation, and Value tracking bars
void setHSVTrackBarPositions(int hue, int saturation, int value, int tolerance) {
  cv::setTrackbarPos("Hue max", "binalized", hue + (tolerance - 40));
  cv::setTrackbarPos("Hue min", "binalized", hue - (tolerance - 40));

  cv::setTrackbarPos("Saturation max", "binalized", saturation + tolerance);
  cv::setTrackbarPos("Saturation min", "binalized", saturation - tolerance);

  cv::setTrackbarPos("Value max", "binalized", value + tolerance);
  cv::setTrackbarPos("Value min", "binalized", value - tolerance);

}

/*
 */
void ObjectFollowing::displayObjectFollowingInfo(cv::Mat *image, double rHeading, double zHeading, int hue, int saturation, int value) {
  char rHeadingDisplay[80]; //print buffer for rHeading
  char zHeadingDisplay[80]; //print buffer for zHeading
  char hsvSampleDisplay[80]; //print buffer for learning HSV values
  char moveStatusDisplay[80]; //print buffer for stop/go status

  cv::Scalar green = CV_RGB(0,255,0); //putText color value

  sprintf(rHeadingDisplay, "rHeading = %+3.2f", rHeading);
  sprintf(zHeadingDisplay, "zHeading = %+3.2f", zHeading);
  sprintf(hsvSampleDisplay, "hsvSample = %3d, %3d, %3d", hue, saturation, value);
  if (moveStatus) {
    sprintf(moveStatusDisplay, "move status = GO");
  }
  else {
    sprintf(moveStatusDisplay, "move status = STOP");
  }

  putText(*image, rHeadingDisplay, cvPoint(30, 120), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  putText(*image, zHeadingDisplay, cvPoint(30, 140), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  putText(*image, hsvSampleDisplay, cvPoint(30, 160), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  putText(*image, moveStatusDisplay, cvPoint(30, 180), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

}

/*
bool inContour(int x, int y, Contour c){
  cv::Point p = new cv::Point(x,y);
  cv::MatOfPoint2f m = new cv::MatOfPoint2f(c.pointMat.toArray());

  double r = cv::Imgproc.pointPolygonTest(m,p, false);

  return r == 1;
}
*/
<commit_msg>Demo ready changes.<commit_after>/*
   Min Kao Drone Tour
   Modified by Elliot Greenlee
 */

#include "objectFollowing.h"
#include "../control.h"
#include <string>
using namespace std;

const string THRESHOLDS_FILE_NAME = "thresholds.xml";
const double dt = 1.0; //Sampling time [s]

/*
 */
ObjectFollowing::ObjectFollowing(Control *control) {
  control_ptr = control;
  kalman = cv::KalmanFilter(4, 2, 0);

  // XML save data for object following color thresholds
  cv::FileStorage fs(THRESHOLDS_FILE_NAME, cv::FileStorage::READ);

  // If there is a save file then read it
  if (fs.isOpened()) {
    maxH = fs["H_MAX"];
    minH = fs["H_MIN"];
    maxS = fs["S_MAX"];
    minS = fs["S_MIN"];
    maxV = fs["V_MAX"];
    minV = fs["V_MIN"];
    fs.release();
  }

  // Create a window
  cv::namedWindow("binalized");
  cv::createTrackbar("Hue max", "binalized", &maxH, 255);
  cv::createTrackbar("Hue min", "binalized", &minH, 255);
  cv::createTrackbar("Saturation max", "binalized", &maxS, 255);
  cv::createTrackbar("Saturation min", "binalized", &minS, 255);
  cv::createTrackbar("Value max", "binalized", &maxV, 255);
  cv::createTrackbar("Value min", "binalized", &minV, 255);
  cv::resizeWindow("binalized", 0, 0);

  // Transition matrix (x, y, vx, vy)
  cv::Mat1f A(4, 4);
  A << 1.0, 0.0,  dt, 0.0,
    0.0, 1.0, 0.0,  dt,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0;
  kalman.transitionMatrix = A;

  // Measurement matrix (x, y)
  cv::Mat1f H(2, 4);
  H << 1, 0, 0, 0,
    0, 1, 0, 0;
  kalman.measurementMatrix = H;

  // Process noise covairance (x, y, vx, vy)
  cv::Mat1f Q(4, 4);
  Q << 1e-5,  0.0,  0.0,  0.0,
    0.0, 1e-5,  0.0,  0.0,
    0.0,  0.0, 1e-5,  0.0,
    0.0,  0.0,  0.0, 1e-5;
  kalman.processNoiseCov = Q;

  // Measurement noise covariance (x, y)
  cv::Mat1f R(2, 2);
  R << 1e-1,  0.0,
    0.0, 1e-1;
  kalman.measurementNoiseCov = R;
}

/*
 */
void ObjectFollowing::close() {
  //Save thresholds
  cv::FileStorage fs(THRESHOLDS_FILE_NAME, cv::FileStorage::READ);
  fs.open(THRESHOLDS_FILE_NAME, cv::FileStorage::WRITE);
  if (fs.isOpened()) {
    cv::write(fs, "H_MAX", maxH);
    cv::write(fs, "H_MIN", minH);
    cv::write(fs, "S_MAX", maxS);
    cv::write(fs, "S_MIN", minS);
    cv::write(fs, "V_MAX", maxV);
    cv::write(fs, "V_MIN", minV);
    fs.release();
  }
}

/*
   returns heading for control
 */
void ObjectFollowing::fly() {

  ControlMovements *controlMovements = &(control_ptr->velocities);
  cv::Mat *image = &(control_ptr->image);

  cv::Vec3b hsvSample;
  int tolerance = 50;
  int avgHue;
  int avgSaturation;
  int avgValue;
  int numPoints;
  cv::Scalar green = CV_RGB(0,255,0); //putText color value

  //switch between learning and non-learning mode
  if (control_ptr->key == 'l') {
    learnMode = !learnMode;
    if (learnMode) {
      printf("Learning mode is enabled\n");
      printf("The color at the crosshairs is being learned\n");
      printf("Press l again to turn off learning mode\n\n");
    }
    else {
      printf("Learning mode is disabled\n");
      printf("The color last at the crosshairs will be targeted\n");
      printf("Press l again to learn a different color\n\n");
    }
  }

  // HSV image
  cv::Mat hsv;
  cv::cvtColor(*image, hsv, cv::COLOR_BGR2HSV_FULL);

  // Binalize
  cv::Mat binalized;
  cv::Scalar lower(minH, minS, minV);
  cv::Scalar upper(maxH, maxS, maxV);
  cv::inRange(hsv, lower, upper, binalized);

  // Show result
  cv::imshow("binalized", binalized);

  // De-noising
  cv::Mat kernel = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
  cv::morphologyEx(binalized, binalized, cv::MORPH_CLOSE, kernel);

  // Detect contours
  vector<vector<cv::Point> > contours;
  cv::findContours(binalized.clone(), contours, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);

  // Find largest contour
  int contour_index = -1;
  double max_area = 0.0;
  for (size_t i = 0; i < contours.size(); i++) {
    double area = fabs(cv::contourArea(contours[i]));
    if (area > max_area) {
      contour_index = i;
      max_area = area;
    }
  }

  // Object detected
  if (contour_index >= 0) {

    // Moments
    cv::Moments moments = cv::moments(contours[contour_index], true);
    double marker_y = (int)(moments.m01 / moments.m00);
    double marker_x = (int)(moments.m10 / moments.m00);

    // Measurements
    cv::Mat measurement = (cv::Mat1f(2, 1) << marker_x, marker_y);

    // Correction
    cv::Mat estimated = kalman.correct(measurement);

    // Show result
    rect = cv::boundingRect(contours[contour_index]);
    cv::rectangle(*image, rect, cv::Scalar(0, 255, 0));

    // Calculate average hsv for the object within the coutour
    //avgHue = hsvSample[0];
    //avgSaturation = hsvSample[1];
    //avgValue = hsvSample[2];
    numPoints = 1;

    //for x in rectangle
    for (int x = rect.x; x < rect.x + rect.width; x++) {
      //for y in rectangle
      for (int y = rect.y; y < rect.y + rect.height; y++) {
        // TODO: If this is to slow, use rectangle average or do every second, third, etc point in rectangle for loop
        //if (inContour(x, y, contours[contour_index])) {
        cv::Point pt(x,y);
        if (rect.contains(pt)) {
          cv::Vec3b hsvPoint = hsv.at<cv::Vec3b>(cvPoint(x, y));
          numPoints++;
          avgHue += hsvPoint[0];
          avgSaturation += hsvPoint[1];
          avgValue += hsvPoint[2];
        }
      }
    }

    avgHue = ((double)avgHue)/numPoints;
    avgSaturation = ((double)avgSaturation)/numPoints;
    avgValue = ((double)avgValue)/numPoints;
  }

  // Prediction
  cv::Mat1f prediction = kalman.predict();
  int radius = 1e+3 * kalman.errorCovPre.at<float>(0, 0);

  // Show predicted position
  cv::circle(*image, cv::Point(prediction(0, 0), prediction(0, 1)), radius, green, 2);

  // Calculate object heading fraction
  float rHeading = -(((*image).cols/2) - prediction(0, 0))/((*image).cols/2);
  float zHeading = -(((*image).rows/2) - prediction(0, 1))/((*image).rows/2);

/*
  if (abs(rHeading) <= 0.6 && abs(zHeading) <= 0.6) {
    hsvSample[0] = avgHue;
    hsvSample[1] = avgSaturation;
    hsvSample[2] = avgValue;

    minH = avgHue - tolerance;
    maxH = avgHue + tolerance;
    minS = avgSaturation - tolerance;
    maxS = avgSaturation + tolerance;
    minV = avgValue - tolerance;
    maxV = avgValue + tolerance;
  }
 */

  // Sample the object color
  if(learnMode) {
    // Show targeting crosshairs
    cv::line(*image, cvPoint((*image).cols/2, 0), cvPoint((*image).cols/2, (*image).rows/2 - 2), green); //top vertical crosshair
    cv::line(*image, cvPoint((*image).cols/2, (*image).rows/2 + 2), cvPoint((*image).cols/2, (*image).rows), green); //bottom vertical crosshair
    cv::line(*image, cvPoint(0, (*image).rows/2), cvPoint((*image).cols/2 - 2, (*image).rows/2), green); //left horizontal crosshair
    cv::line(*image, cvPoint((*image).cols/2 + 2, (*image).rows/2), cvPoint((*image).cols, (*image).rows/2), green); //right horizontal crosshair

    hsvSample = hsv.at<cv::Vec3b>(cvPoint((*image).cols/2, (*image).rows/2));
    setHSVTrackBarPositions(hsvSample[0], hsvSample[1], hsvSample[2], tolerance);
  }

  displayObjectFollowingInfo(image, rHeading, zHeading, hsvSample[0], hsvSample[1], hsvSample[2]);

  rect_area = rect.width * rect.height;

  // Set forward/backward movement
  controlMovements->vx = (goalArea - rect_area)/((double)goalArea);

  if(controlMovements->vx > 1) {
    controlMovements->vx = 1;
  }
  else if (controlMovements->vx < -1){
    controlMovements->vx = -1;
  }

  //Emergency landing
  if (abs(rHeading) <= 0.95 && abs(zHeading) <= 0.95) {
    lastSearchTime = time(0);
  }
  else {
    controlMovements->vx = 0;
    controlMovements->vy = 0;
    controlMovements->vz = 0;
  }
  time_t currentTime = time(0);
  double elapsedTime = difftime(currentTime, lastSearchTime);
  printf("CALEB- elapsedTime: %f\n", elapsedTime);
  if (elapsedTime >= 4) {
    control_ptr->ardrone.landing();
  }

  time_t current_time = time(0);
  double elapsed_time = difftime(current_time, control_ptr->takeoff_time);
  if (elapsed_time < 5){
    controlMovements->vx = 0;
    controlMovements->vy = 0;
    controlMovements->vz = 0;
    controlMovements->vr = 0;
  } else {
    printf("elapsed time: %f\n", elapsed_time);
    controlMovements->vz = -(zHeading * 0.2);
    controlMovements->vr = -(rHeading * 0.5);
    if (controlMovements->vx < 0.5 && controlMovements->vx > 0) {
      controlMovements->vx = pow(controlMovements->vx, 2);
    }
  }

  return;
}

//Auto set Hue, Saturation, and Value tracking bars
void setHSVTrackBarPositions(int hue, int saturation, int value, int tolerance) {
  cv::setTrackbarPos("Hue max", "binalized", hue + (tolerance - 40));
  cv::setTrackbarPos("Hue min", "binalized", hue - (tolerance - 40));

  cv::setTrackbarPos("Saturation max", "binalized", saturation + tolerance);
  cv::setTrackbarPos("Saturation min", "binalized", saturation - tolerance);

  cv::setTrackbarPos("Value max", "binalized", value + tolerance);
  cv::setTrackbarPos("Value min", "binalized", value - tolerance);

}

/*
 */
void ObjectFollowing::displayObjectFollowingInfo(cv::Mat *image, double rHeading, double zHeading, int hue, int saturation, int value) {
  char rHeadingDisplay[80]; //print buffer for rHeading
  char zHeadingDisplay[80]; //print buffer for zHeading
  char hsvSampleDisplay[80]; //print buffer for learning HSV values
  char moveStatusDisplay[80]; //print buffer for stop/go status

  cv::Scalar green = CV_RGB(0,255,0); //putText color value

  sprintf(rHeadingDisplay, "rHeading = %+3.2f", rHeading);
  sprintf(zHeadingDisplay, "zHeading = %+3.2f", zHeading);
  sprintf(hsvSampleDisplay, "hsvSample = %3d, %3d, %3d", hue, saturation, value);
  if (moveStatus) {
    sprintf(moveStatusDisplay, "move status = GO");
  }
  else {
    sprintf(moveStatusDisplay, "move status = STOP");
  }

  putText(*image, rHeadingDisplay, cvPoint(30, 120), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  putText(*image, zHeadingDisplay, cvPoint(30, 140), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  putText(*image, hsvSampleDisplay, cvPoint(30, 160), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  putText(*image, moveStatusDisplay, cvPoint(30, 180), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

}

/*
bool inContour(int x, int y, Contour c){
  cv::Point p = new cv::Point(x,y);
  cv::MatOfPoint2f m = new cv::MatOfPoint2f(c.pointMat.toArray());

  double r = cv::Imgproc.pointPolygonTest(m,p, false);

  return r == 1;
}
*/
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: mkdir -p %T/subdir && clang -DCLING_EXPORT=%dllexport -shared %S/call_lib.c -o %T/subdir/libtest%shlibext
// RUN: cat %s | %cling -I %S -DENVVAR_LIB="\"%/T/subdir\"" -DENVVAR_INC="\"%/p/subdir\"" -Xclang -verify 2>&1 | FileCheck %s

extern "C" int cling_testlibrary_function();

// For gcc setenv
#ifndef __THROW
 #define __THROW
#endif
extern "C" int setenv(const char *name, const char *value, int overwrite) __THROW;
extern "C" int _putenv_s(const char *name, const char *value);
static void setup() {
#ifdef _WIN32
 #define setenv(n, v, o) _putenv_s(n,v)
#endif
  ::setenv("ENVVAR_INC", ENVVAR_INC, 1);
  ::setenv("ENVVAR_LIB", ENVVAR_LIB, 1);
}
setup();

#pragma cling add_include_path("$ENVVAR_INC")
#include "Include_header.h"
include_test()
// CHECK: OK(int) 0

#pragma cling add_library_path("$ENVVAR_LIB")
#pragma cling load("libtest")
cling_testlibrary_function()
// CHECK: (int) 66

#pragma cling add_library_path("$NONEXISTINGVARNAME")
//expected-no-diagnostics
<commit_msg>Fix setenv declaration for gcc on OS X.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: mkdir -p %T/subdir && clang -DCLING_EXPORT=%dllexport -shared %S/call_lib.c -o %T/subdir/libtest%shlibext
// RUN: cat %s | %cling -I %S -DENVVAR_LIB="\"%/T/subdir\"" -DENVVAR_INC="\"%/p/subdir\"" -Xclang -verify 2>&1 | FileCheck %s

extern "C" int cling_testlibrary_function();

#ifndef _WIN32
 #include <stdlib.h>
#else
 extern "C" int _putenv_s(const char *name, const char *value);
 #define setenv(n, v, o) _putenv_s(n,v)
#endif

::setenv("ENVVAR_INC", ENVVAR_INC, 1);
::setenv("ENVVAR_LIB", ENVVAR_LIB, 1);

#pragma cling add_include_path("$ENVVAR_INC")
#include "Include_header.h"
include_test()
// CHECK: OK(int) 0

#pragma cling add_library_path("$ENVVAR_LIB")
#pragma cling load("libtest")
cling_testlibrary_function()
// CHECK: (int) 66

#pragma cling add_library_path("$NONEXISTINGVARNAME")
//expected-no-diagnostics
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "include/script.h"
#include "include/exceptions.h"
#include "include/debug.h"
#include "include/file.h"

namespace yappy {
namespace lua {

LuaError::LuaError(const std::string &msg, lua_State *L) :
	runtime_error("")
{
	const char *str = lua_tostring(L, -1);
	if (str == nullptr) {
		m_what = msg;
	}
	else {
		m_what = msg + ": " + str;
	}
	lua_pop(L, 1);
}

namespace {

// Error happens outside protected env
// This is fatal and exit application
int atpanic(lua_State *L)
{
	throw std::runtime_error("Lua panic");
	// Don't return
}

///////////////////////////////////////////////////////////////////////////////
// Copied from linit.c
///////////////////////////////////////////////////////////////////////////////
const luaL_Reg loadedlibs[] = {
	{ "_G", luaopen_base },
//	{ LUA_LOADLIBNAME, luaopen_package },
	{ LUA_COLIBNAME, luaopen_coroutine },
	{ LUA_TABLIBNAME, luaopen_table },
//	{ LUA_IOLIBNAME, luaopen_io },
//	{ LUA_OSLIBNAME, luaopen_os },
	{ LUA_STRLIBNAME, luaopen_string },
	{ LUA_MATHLIBNAME, luaopen_math },
	{ LUA_UTF8LIBNAME, luaopen_utf8 },
//	{ LUA_DBLIBNAME, luaopen_debug },
	{ NULL, NULL }
};

LUALIB_API void my_luaL_openlibs(lua_State *L) {
	const luaL_Reg *lib;
	/* "require" functions from 'loadedlibs' and set results to global table */
	for (lib = loadedlibs; lib->func; lib++) {
		luaL_requiref(L, lib->name, lib->func, 1);
		lua_pop(L, 1);  /* remove lib */
	}
}
///////////////////////////////////////////////////////////////////////////////
// Copied from linit.c END
///////////////////////////////////////////////////////////////////////////////

}	// namespace

void Lua::LuaDeleter::operator()(lua_State *lua)
{
	::lua_close(lua);
}

void *Lua::luaAlloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
	auto *lua = reinterpret_cast<Lua *>(ud);
	if (nsize == 0) {
		// free(ptr);
		//debug::writef(L"luaAlloc(free)    %p, %08zx, %08zx", ptr, osize, nsize);
		if (ptr != nullptr) {
			BOOL ret = ::HeapFree(lua->m_heap.get(), 0, ptr);
			if (!ret) {
				debug::writeLine(L"[warning] HeapFree() failed");
			}
		}
		return nullptr;
	}
	else {
		// realloc(ptr, nsize);
		if (nsize >= 0x7FFF8) {
			debug::writef(L"[warning] Attempt to allocate %zu bytes", nsize);
		}
		if (ptr == nullptr) {
			//debug::writef(L"luaAlloc(alloc)   %p, %08zx, %08zx", ptr, osize, nsize);
			return ::HeapAlloc(lua->m_heap.get(), 0, nsize);
		}
		else {
			//debug::writef(L"luaAlloc(realloc) %p, %08zx, %08zx", ptr, osize, nsize);
			return ::HeapReAlloc(lua->m_heap.get(), 0, ptr, nsize);
		}
	}
}

Lua::Lua(bool debugEnable, size_t maxHeapSize, size_t initHeapSize,
	int instLimit) :
	m_debugEnable(debugEnable)
{
	debug::writeLine("Initializing lua...");

	HANDLE tmpHeap = ::HeapCreate(HeapOption, initHeapSize, maxHeapSize);
	error::checkWin32Result(tmpHeap != nullptr, "HeapCreate() failed");
	m_heap.reset(tmpHeap);

	lua_State *tmpLua = lua_newstate(luaAlloc, this);
	if (tmpLua == nullptr) {
		throw std::bad_alloc();
	}
	m_lua.reset(tmpLua);

	m_dbg = std::make_unique<debugger::LuaDebugger>(m_lua.get(), debugEnable, instLimit);

	debug::writeLine("Initializing lua OK");

	::lua_atpanic(m_lua.get(), atpanic);
	my_luaL_openlibs(m_lua.get());

	// delete load function
	lua_State *L = m_lua.get();
	lua_pushnil(L);
	lua_setglobal(L, "dofile");
	lua_pushnil(L);
	lua_setglobal(L, "loadfile");
	lua_pushnil(L);
	lua_setglobal(L, "load");
}

lua_State *Lua::getLuaState() const
{
	return m_lua.get();
}

Lua::~Lua()
{
	debug::writeLine("Finalize lua");
}

void Lua::loadTraceLib()
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::trace_RegList);
	lua_setglobal(L, "trace");
}

void Lua::loadSysLib()
{
	lua_State *L = m_lua.get();
	luaL_newlibtable(L, export::trace_RegList);
	// upvalue[1]: Lua *this
	lua_pushlightuserdata(L, this);
	luaL_setfuncs(L, export::sys_RegList, 1);
	lua_setglobal(L, "sys");
}

void Lua::loadResourceLib(framework::Application *app)
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::resource_RegList);
	lua_pushstring(L, export::resource_RawFieldName);
	lua_pushlightuserdata(L, app);
	lua_settable(L, -3);
	lua_setglobal(L, "resource");
}

void Lua::loadGraphLib(framework::Application *app)
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::graph_RegList);
	lua_pushstring(L, export::graph_RawFieldName);
	lua_pushlightuserdata(L, app);
	lua_settable(L, -3);
	lua_setglobal(L, "graph");
}

void Lua::loadSoundLib(framework::Application *app)
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::sound_RegList);
	lua_pushstring(L, export::sound_RawFieldName);
	lua_pushlightuserdata(L, app);
	lua_settable(L, -3);
	lua_setglobal(L, "sound");
}

void Lua::loadFile(const wchar_t *fileName, bool autoBreak)
{
	lua_State *L = m_lua.get();

	file::Bytes buf = file::loadFile(fileName);

	// push chunk function
	std::string chunkName("@");
	chunkName += util::wc2utf8(fileName).get();
	int ret = ::luaL_loadbufferx(L,
		reinterpret_cast<const char *>(buf.data()), buf.size(),
		chunkName.c_str(), "t");
	if (ret != LUA_OK) {
		throw LuaError("Load script failed", L);
	}
	// prepare debug info
	m_dbg->loadDebugInfo(chunkName.c_str(),
		reinterpret_cast<const char *>(buf.data()), buf.size());
	// call it
	pcallInternal(0, 0, autoBreak);
}

void Lua::pcallInternal(int narg, int nret, bool autoBreak)
{
	m_dbg->pcall(narg, nret, autoBreak);
}

std::vector<std::string> luaValueToStrList(lua_State *L, int ind, int maxDepth, int depth)
{
	std::vector<std::string> result;

	int tind = lua_absindex(L, ind);

	int type = lua_type(L, ind);
	if (type == LUA_TNONE) {
		throw std::logic_error("invalid index: " + std::to_string(ind));
	}
	const char *typestr = lua_typename(L, type);
	// copy and tostring it
	lua_pushvalue(L, ind);
	const char *valstr = lua_tostring(L, -1);
	valstr = (valstr == NULL) ? "" : valstr;
	// pop copy
	lua_pop(L, 1);
	// boolean cannot be tostring
	if (type == LUA_TBOOLEAN) {
		valstr = lua_toboolean(L, ind) ? "true" : "false";
	}

	{
		std::string str;
		for (int i = 0; i < depth; i++) {
			str += "    ";
		}
		str += "(";
		str += typestr;
		str += ") ";
		str += valstr;
		result.emplace_back(std::move(str));
	}
	if (type == LUA_TTABLE && depth < maxDepth) {
		lua_pushnil(L);
		while (lua_next(L, tind) != 0) {
			// key:-2, value:-1
			auto key = luaValueToStrList(L, -2, maxDepth, depth + 1);
			auto val = luaValueToStrList(L, -1, maxDepth, depth + 1);
			// TODO: bug
			result.insert(result.end(), key.begin(), key.end());
			result.insert(result.end(), key.begin(), key.end());
			// pop value, keep key
			lua_pop(L, 1);
		}
	}
	return result;
}

}
}
<commit_msg>Fix debugger table dump bug<commit_after>#include "stdafx.h"
#include "include/script.h"
#include "include/exceptions.h"
#include "include/debug.h"
#include "include/file.h"

namespace yappy {
namespace lua {

LuaError::LuaError(const std::string &msg, lua_State *L) :
	runtime_error("")
{
	const char *str = lua_tostring(L, -1);
	if (str == nullptr) {
		m_what = msg;
	}
	else {
		m_what = msg + ": " + str;
	}
	lua_pop(L, 1);
}

namespace {

// Error happens outside protected env
// This is fatal and exit application
int atpanic(lua_State *L)
{
	throw std::runtime_error("Lua panic");
	// Don't return
}

///////////////////////////////////////////////////////////////////////////////
// Copied from linit.c
///////////////////////////////////////////////////////////////////////////////
const luaL_Reg loadedlibs[] = {
	{ "_G", luaopen_base },
//	{ LUA_LOADLIBNAME, luaopen_package },
	{ LUA_COLIBNAME, luaopen_coroutine },
	{ LUA_TABLIBNAME, luaopen_table },
//	{ LUA_IOLIBNAME, luaopen_io },
//	{ LUA_OSLIBNAME, luaopen_os },
	{ LUA_STRLIBNAME, luaopen_string },
	{ LUA_MATHLIBNAME, luaopen_math },
	{ LUA_UTF8LIBNAME, luaopen_utf8 },
//	{ LUA_DBLIBNAME, luaopen_debug },
	{ NULL, NULL }
};

LUALIB_API void my_luaL_openlibs(lua_State *L) {
	const luaL_Reg *lib;
	/* "require" functions from 'loadedlibs' and set results to global table */
	for (lib = loadedlibs; lib->func; lib++) {
		luaL_requiref(L, lib->name, lib->func, 1);
		lua_pop(L, 1);  /* remove lib */
	}
}
///////////////////////////////////////////////////////////////////////////////
// Copied from linit.c END
///////////////////////////////////////////////////////////////////////////////

}	// namespace

void Lua::LuaDeleter::operator()(lua_State *lua)
{
	::lua_close(lua);
}

void *Lua::luaAlloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
	auto *lua = reinterpret_cast<Lua *>(ud);
	if (nsize == 0) {
		// free(ptr);
		//debug::writef(L"luaAlloc(free)    %p, %08zx, %08zx", ptr, osize, nsize);
		if (ptr != nullptr) {
			BOOL ret = ::HeapFree(lua->m_heap.get(), 0, ptr);
			if (!ret) {
				debug::writeLine(L"[warning] HeapFree() failed");
			}
		}
		return nullptr;
	}
	else {
		// realloc(ptr, nsize);
		if (nsize >= 0x7FFF8) {
			debug::writef(L"[warning] Attempt to allocate %zu bytes", nsize);
		}
		if (ptr == nullptr) {
			//debug::writef(L"luaAlloc(alloc)   %p, %08zx, %08zx", ptr, osize, nsize);
			return ::HeapAlloc(lua->m_heap.get(), 0, nsize);
		}
		else {
			//debug::writef(L"luaAlloc(realloc) %p, %08zx, %08zx", ptr, osize, nsize);
			return ::HeapReAlloc(lua->m_heap.get(), 0, ptr, nsize);
		}
	}
}

Lua::Lua(bool debugEnable, size_t maxHeapSize, size_t initHeapSize,
	int instLimit) :
	m_debugEnable(debugEnable)
{
	debug::writeLine("Initializing lua...");

	HANDLE tmpHeap = ::HeapCreate(HeapOption, initHeapSize, maxHeapSize);
	error::checkWin32Result(tmpHeap != nullptr, "HeapCreate() failed");
	m_heap.reset(tmpHeap);

	lua_State *tmpLua = lua_newstate(luaAlloc, this);
	if (tmpLua == nullptr) {
		throw std::bad_alloc();
	}
	m_lua.reset(tmpLua);

	m_dbg = std::make_unique<debugger::LuaDebugger>(m_lua.get(), debugEnable, instLimit);

	debug::writeLine("Initializing lua OK");

	::lua_atpanic(m_lua.get(), atpanic);
	my_luaL_openlibs(m_lua.get());

	// delete load function
	lua_State *L = m_lua.get();
	lua_pushnil(L);
	lua_setglobal(L, "dofile");
	lua_pushnil(L);
	lua_setglobal(L, "loadfile");
	lua_pushnil(L);
	lua_setglobal(L, "load");
}

lua_State *Lua::getLuaState() const
{
	return m_lua.get();
}

Lua::~Lua()
{
	debug::writeLine("Finalize lua");
}

void Lua::loadTraceLib()
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::trace_RegList);
	lua_setglobal(L, "trace");
}

void Lua::loadSysLib()
{
	lua_State *L = m_lua.get();
	luaL_newlibtable(L, export::trace_RegList);
	// upvalue[1]: Lua *this
	lua_pushlightuserdata(L, this);
	luaL_setfuncs(L, export::sys_RegList, 1);
	lua_setglobal(L, "sys");
}

void Lua::loadResourceLib(framework::Application *app)
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::resource_RegList);
	lua_pushstring(L, export::resource_RawFieldName);
	lua_pushlightuserdata(L, app);
	lua_settable(L, -3);
	lua_setglobal(L, "resource");
}

void Lua::loadGraphLib(framework::Application *app)
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::graph_RegList);
	lua_pushstring(L, export::graph_RawFieldName);
	lua_pushlightuserdata(L, app);
	lua_settable(L, -3);
	lua_setglobal(L, "graph");
}

void Lua::loadSoundLib(framework::Application *app)
{
	lua_State *L = m_lua.get();
	luaL_newlib(L, export::sound_RegList);
	lua_pushstring(L, export::sound_RawFieldName);
	lua_pushlightuserdata(L, app);
	lua_settable(L, -3);
	lua_setglobal(L, "sound");
}

void Lua::loadFile(const wchar_t *fileName, bool autoBreak)
{
	lua_State *L = m_lua.get();

	file::Bytes buf = file::loadFile(fileName);

	// push chunk function
	std::string chunkName("@");
	chunkName += util::wc2utf8(fileName).get();
	int ret = ::luaL_loadbufferx(L,
		reinterpret_cast<const char *>(buf.data()), buf.size(),
		chunkName.c_str(), "t");
	if (ret != LUA_OK) {
		throw LuaError("Load script failed", L);
	}
	// prepare debug info
	m_dbg->loadDebugInfo(chunkName.c_str(),
		reinterpret_cast<const char *>(buf.data()), buf.size());
	// call it
	pcallInternal(0, 0, autoBreak);
}

void Lua::pcallInternal(int narg, int nret, bool autoBreak)
{
	m_dbg->pcall(narg, nret, autoBreak);
}

std::vector<std::string> luaValueToStrList(lua_State *L, int ind, int maxDepth, int depth)
{
	std::vector<std::string> result;

	int tind = lua_absindex(L, ind);

	int type = lua_type(L, ind);
	if (type == LUA_TNONE) {
		throw std::logic_error("invalid index: " + std::to_string(ind));
	}
	const char *typestr = lua_typename(L, type);
	// copy and tostring it
	lua_pushvalue(L, ind);
	const char *valstr = lua_tostring(L, -1);
	valstr = (valstr == NULL) ? "" : valstr;
	// pop copy
	lua_pop(L, 1);
	// boolean cannot be tostring
	if (type == LUA_TBOOLEAN) {
		valstr = lua_toboolean(L, ind) ? "true" : "false";
	}

	{
		std::string str;
		for (int i = 0; i < depth; i++) {
			str += "    ";
		}
		str += "(";
		str += typestr;
		str += ") ";
		str += valstr;
		result.emplace_back(std::move(str));
	}
	if (type == LUA_TTABLE && depth < maxDepth) {
		lua_pushnil(L);
		while (lua_next(L, tind) != 0) {
			// key:-2, value:-1
			auto key = luaValueToStrList(L, -2, maxDepth, depth + 1);
			auto val = luaValueToStrList(L, -1, maxDepth, depth + 1);
			result.insert(result.end(), key.begin(), key.end());
			result.insert(result.end(), val.begin(), val.end());
			// pop value, keep key
			lua_pop(L, 1);
		}
	}
	return result;
}

}
}
<|endoftext|>


<commit_before>
#include <nstd/Event.h>
#include <nstd/String.h>
#include <nstd/Debug.h>

void testEvent()
{
  class MyEmitter : public Event::Source
  {
  public:
    virtual ~MyEmitter() {}
    void emitMySignal(const String& arg)
    {
      emit(&MyEmitter::mySignal, arg);
    }

    void emitMySignal2(const String& arg0, int arg1)
    {
      emit(&MyEmitter::mySignal2, arg0, arg1);
    }

  public: // signals
    void mySignal(String arg) {}
    void mySignal2(String arg, int arg1) {}
  };

  class MyReceiver : public Event::Listener
  {
  public:
    MyReceiver* check;
    MyEmitter* emitter;

    virtual ~MyReceiver() {}

  public: // slots
    virtual void mySlot(String arg)
    {
      ASSERT(this == check);
    }
    void selfDelete(String arg)
    {
      ASSERT(this == check);
      delete this;
    }
    void selfDisconnect(String arg)
    {
      ASSERT(this == check);
      Event::disconnect(emitter, &MyEmitter::mySignal, this, &MyReceiver::selfDisconnect);
    }
    void emitterDelete(String arg)
    {
      ASSERT(this == check);
      Event::disconnect(emitter, &MyEmitter::mySignal, this, &MyReceiver::emitterDelete);
      delete emitter;
    }
  };

  // test simple connect and disconnect
  {
    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;

    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    emitter.emitMySignal("test");
    emitter.emitMySignal2("test", 123);
  }

  // test slots in derived classes
  {
    class A
    {
      int a;

      virtual void ha(String arg){}
    };

    class MyReceiver3 : public MyReceiver, public A
    {
    public:
      MyReceiver3* check3;
      int mySlotCalled;

      MyReceiver3() : mySlotCalled(0) {}

    public: // slots
      void mySlot3(String arg)
      {
        ASSERT(this == check);
      }

      virtual void mySlot(String arg)
      {
        ++mySlotCalled;
      }
    };

    class MyReceiver4 : public A, public MyReceiver
    {
    public:
      MyReceiver4* check4;

    public: // slots
      void mySlot4(String arg)
      {
        ASSERT(this == check);
      }
    };

    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;
    MyReceiver3 receiver3;
    receiver3.check = &receiver3;
    receiver3.check3 = &receiver3;
    ASSERT((void*)receiver3.check == (void*)receiver3.check3);
    MyReceiver4 receiver4;
    receiver4.check = &receiver4;
    receiver4.check4 = &receiver4;
    ASSERT((void*)receiver4.check != (void*)receiver4.check4);

    Event::connect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver3::mySlot3);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver3::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver4::mySlot4);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver4::mySlot);
    emitter.emitMySignal("test");
    emitter.emitMySignal2("test", 123);
    ASSERT(receiver3.mySlotCalled == 2);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver3::mySlot3);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver::mySlot);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver4::mySlot4);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver::mySlot);
  }

  // test destructor of Receiver
  {
    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;

    MyReceiver* receiver2 = new MyReceiver;
    Event::connect(&emitter, &MyEmitter::mySignal, receiver2, &MyReceiver::mySlot);
    delete receiver2;

    emitter.emitMySignal("test2");
  }

  // test destructor of Emitter
  {
    MyReceiver receiver;
    receiver.check = &receiver;

    MyEmitter* emitter2 = new MyEmitter;
    Event::connect(emitter2, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    delete emitter2;
  }

  // test delete of receiver in slot
  {
    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;
    MyReceiver* receiverSelfDelete = new MyReceiver;
    receiverSelfDelete->check = receiverSelfDelete;
    Event::connect(&emitter, &MyEmitter::mySignal, receiverSelfDelete, &MyReceiver::selfDelete);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    emitter.emitMySignal("test2");
    emitter.emitMySignal("test2");
  }

  // test disconnect of receiver in slot
  {
    MyEmitter emitter;
    MyReceiver receiver1;
    receiver1.check = &receiver1;
    receiver1.emitter = &emitter;
    MyReceiver receiver2;
    receiver2.check = &receiver2;
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver1, &MyReceiver::selfDisconnect);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver2, &MyReceiver::mySlot);
    emitter.emitMySignal("test2");
    emitter.emitMySignal("test2");
  }

  // test delete of emitter in slot
  {
    MyEmitter* emitter = new MyEmitter;
    MyEmitter emitter2;
    MyReceiver receiver1;
    receiver1.check = &receiver1;
    receiver1.emitter = emitter;
    MyReceiver receiver2;
    receiver2.check = &receiver2;
    Event::connect(emitter, &MyEmitter::mySignal, &receiver1, &MyReceiver::emitterDelete);
    Event::connect(emitter, &MyEmitter::mySignal, &receiver2, &MyReceiver::mySlot);
    Event::connect(&emitter2, &MyEmitter::mySignal, &receiver2, &MyReceiver::mySlot);
    emitter->emitMySignal("test2");
    emitter2.emitMySignal("test2");
  }

  // test signal/slot with 8 arguments
  {
    class MyEmitter8 : public Event::Source
    {
    public:
      virtual ~MyEmitter8() {}
      void emitMySignal()
      {
        emit(&MyEmitter8::mySignal, 1, 2, 3, 4, 5, 6, 7, 8);
      }
    public: // signals
      void mySignal(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {}
    };

    class MyReceiver8 : public Event::Listener
    {
    public:
      bool slotCalled;
      MyReceiver8() : slotCalled(false) {}
    public: // slots
      virtual void mySlot(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {slotCalled = true;}
    };

    MyEmitter8 emitter;
    MyReceiver8 receiver;
    Event::connect(&emitter, &MyEmitter8::mySignal, &receiver, &MyReceiver8::mySlot);
    emitter.emitMySignal();
    Event::disconnect(&emitter, &MyEmitter8::mySignal, &receiver, &MyReceiver8::mySlot);
    emitter.emitMySignal();
  }
}
<commit_msg>Event: Added test of event with const reference argument<commit_after>
#include <nstd/Event.h>
#include <nstd/String.h>
#include <nstd/Debug.h>

void testEvent()
{
  class MyEmitter : public Event::Source
  {
  public:
    virtual ~MyEmitter() {}
    void emitMySignal(const String& arg)
    {
      emit(&MyEmitter::mySignal, arg);
    }

    void emitMySignal2(const String& arg0, int arg1)
    {
      emit(&MyEmitter::mySignal2, arg0, arg1);
    }

    void emitMySignal3()
    {
      emit<MyEmitter, const String&>(&MyEmitter::mySignal3, "test");
    }

  public: // signals
    void mySignal(String arg) {}
    void mySignal2(String arg, int arg1) {}
    void mySignal3(const String& arg) {}
  };

  class MyReceiver : public Event::Listener
  {
  public:
    MyReceiver* check;
    MyEmitter* emitter;

    virtual ~MyReceiver() {}

  public: // slots
    virtual void mySlot(String arg)
    {
      ASSERT(this == check);
    }
    void selfDelete(String arg)
    {
      ASSERT(this == check);
      delete this;
    }
    void selfDisconnect(String arg)
    {
      ASSERT(this == check);
      Event::disconnect(emitter, &MyEmitter::mySignal, this, &MyReceiver::selfDisconnect);
    }
    void emitterDelete(String arg)
    {
      ASSERT(this == check);
      Event::disconnect(emitter, &MyEmitter::mySignal, this, &MyReceiver::emitterDelete);
      delete emitter;
    }
  };

  // test simple connect and disconnect
  {
    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;

    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    emitter.emitMySignal("test");
    emitter.emitMySignal2("test", 123);
  }

  // test signal with const String& argument
  {
    MyEmitter emitter;
    emitter.emitMySignal3();
  }

  // test slots in derived classes
  {
    class A
    {
      int a;

      virtual void ha(String arg){}
    };

    class MyReceiver3 : public MyReceiver, public A
    {
    public:
      MyReceiver3* check3;
      int mySlotCalled;

      MyReceiver3() : mySlotCalled(0) {}

    public: // slots
      void mySlot3(String arg)
      {
        ASSERT(this == check);
      }

      virtual void mySlot(String arg)
      {
        ++mySlotCalled;
      }
    };

    class MyReceiver4 : public A, public MyReceiver
    {
    public:
      MyReceiver4* check4;

    public: // slots
      void mySlot4(String arg)
      {
        ASSERT(this == check);
      }
    };

    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;
    MyReceiver3 receiver3;
    receiver3.check = &receiver3;
    receiver3.check3 = &receiver3;
    ASSERT((void*)receiver3.check == (void*)receiver3.check3);
    MyReceiver4 receiver4;
    receiver4.check = &receiver4;
    receiver4.check4 = &receiver4;
    ASSERT((void*)receiver4.check != (void*)receiver4.check4);

    Event::connect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver3::mySlot3);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver3::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver4::mySlot4);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver::mySlot);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver4::mySlot);
    emitter.emitMySignal("test");
    emitter.emitMySignal2("test", 123);
    ASSERT(receiver3.mySlotCalled == 2);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver3::mySlot3);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver3, &MyReceiver::mySlot);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver4::mySlot4);
    Event::disconnect(&emitter, &MyEmitter::mySignal, &receiver4, &MyReceiver::mySlot);
  }

  // test destructor of Receiver
  {
    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;

    MyReceiver* receiver2 = new MyReceiver;
    Event::connect(&emitter, &MyEmitter::mySignal, receiver2, &MyReceiver::mySlot);
    delete receiver2;

    emitter.emitMySignal("test2");
  }

  // test destructor of Emitter
  {
    MyReceiver receiver;
    receiver.check = &receiver;

    MyEmitter* emitter2 = new MyEmitter;
    Event::connect(emitter2, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    delete emitter2;
  }

  // test delete of receiver in slot
  {
    MyEmitter emitter;
    MyReceiver receiver;
    receiver.check = &receiver;
    MyReceiver* receiverSelfDelete = new MyReceiver;
    receiverSelfDelete->check = receiverSelfDelete;
    Event::connect(&emitter, &MyEmitter::mySignal, receiverSelfDelete, &MyReceiver::selfDelete);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver, &MyReceiver::mySlot);
    emitter.emitMySignal("test2");
    emitter.emitMySignal("test2");
  }

  // test disconnect of receiver in slot
  {
    MyEmitter emitter;
    MyReceiver receiver1;
    receiver1.check = &receiver1;
    receiver1.emitter = &emitter;
    MyReceiver receiver2;
    receiver2.check = &receiver2;
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver1, &MyReceiver::selfDisconnect);
    Event::connect(&emitter, &MyEmitter::mySignal, &receiver2, &MyReceiver::mySlot);
    emitter.emitMySignal("test2");
    emitter.emitMySignal("test2");
  }

  // test delete of emitter in slot
  {
    MyEmitter* emitter = new MyEmitter;
    MyEmitter emitter2;
    MyReceiver receiver1;
    receiver1.check = &receiver1;
    receiver1.emitter = emitter;
    MyReceiver receiver2;
    receiver2.check = &receiver2;
    Event::connect(emitter, &MyEmitter::mySignal, &receiver1, &MyReceiver::emitterDelete);
    Event::connect(emitter, &MyEmitter::mySignal, &receiver2, &MyReceiver::mySlot);
    Event::connect(&emitter2, &MyEmitter::mySignal, &receiver2, &MyReceiver::mySlot);
    emitter->emitMySignal("test2");
    emitter2.emitMySignal("test2");
  }

  // test signal/slot with 8 arguments
  {
    class MyEmitter8 : public Event::Source
    {
    public:
      virtual ~MyEmitter8() {}
      void emitMySignal()
      {
        emit(&MyEmitter8::mySignal, 1, 2, 3, 4, 5, 6, 7, 8);
      }
    public: // signals
      void mySignal(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {}
    };

    class MyReceiver8 : public Event::Listener
    {
    public:
      bool slotCalled;
      MyReceiver8() : slotCalled(false) {}
    public: // slots
      virtual void mySlot(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {slotCalled = true;}
    };

    MyEmitter8 emitter;
    MyReceiver8 receiver;
    Event::connect(&emitter, &MyEmitter8::mySignal, &receiver, &MyReceiver8::mySlot);
    emitter.emitMySignal();
    Event::disconnect(&emitter, &MyEmitter8::mySignal, &receiver, &MyReceiver8::mySlot);
    emitter.emitMySignal();
  }
}
<|endoftext|>


<commit_before>#include "persistentstore.h"
#include "debug.h"

#include <QSettings>
#include <QFileInfo>
#include <QFile>

PersistentStore::PersistentStore(QObject *parent) : QObject(parent), _initialized(false)
{
    init();
}

bool PersistentStore::init()
{
    QMutexLocker locker(&_mutex);

    QSettings settings;
    QString appdata = settings.value("app/app_data").toString();
    if(appdata.isEmpty())
    {
        DEBUG << "Error creating the PersistentStore: app.appdata not set.";
        return false;
    }
    bool create = false;
    QString dbUrl(appdata + QDir::separator() + DEFAULT_DBNAME);
    QFileInfo dbFileInfo(dbUrl);

    _db = _db.addDatabase("QSQLITE");
    _db.setConnectOptions("QSQLITE_OPEN_URI");
    _db.setDatabaseName(dbUrl);

    if(!dbFileInfo.exists())
    {
        create = true;
    }
    else if(!dbFileInfo.isFile() || !dbFileInfo.isReadable())
    {
        DEBUG << "Error creating the PersistentStore: DB file is not accessible " << dbUrl;
        return false;
    }
    else if (!_db.open())
    {
        DEBUG << "Error opening the PersistentStore DB: " << _db.lastError().text();
        return false;
    }
    else
    {
        QStringList tables = _db.tables();
        if (!tables.contains("archives", Qt::CaseInsensitive))
        {
            _db.close();
            DEBUG << "Invalid PersistentStore DB found. Attempting to recover.";
            if(!QFile::rename(dbUrl, dbUrl + "." + QString::number(QDateTime::currentMSecsSinceEpoch())))
            {
                DEBUG << "Failed to rename current invalid PersistentStore DB. Please manually cleanup the DB directory " << appdata;
                return false;
            }
            create = true;
        }
        else
        {
            if(!tables.contains("version", Qt::CaseInsensitive))
            {
                if(!upgradeVersion0())
                {
                    DEBUG << "Failed to upgrade PersistentStore DB. It's best to start from scratch by purging the existing DB in " << appdata;
                    return false;
                }
            }
            int version = -1;
            QSqlQuery query(_db);
            if (query.exec("SELECT version FROM version"))
            {
                query.next();
                version = query.value(0).toInt();
            }
            else
            {
                DEBUG << "Failed to get current DB version: " << query.lastError().text();
                return false;
            }
            if((version == 0) && upgradeVersion1())
                DEBUG << "DB upgraded to version 1.";
            if((version == 1) && upgradeVersion2())
                DEBUG << "DB upgraded to version 2.";
        }
    }

    if(create)
    {
        QFile dbTemplate(":/dbtemplate.db");
        if(!dbTemplate.copy(dbUrl))
        {
            DEBUG << "Failed to create the PersistentStore DB.";
            return false;
        }
        // Work around the fact that QFile::copy from the resource system does not set u+w on the resulted file
        QFile dbFile(dbUrl);
        dbFile.setPermissions(dbFile.permissions() | QFileDevice::WriteOwner);
        dbFile.close();
        if (!_db.open())
        {
            DEBUG << "Error opening the PersistentStore DB: " << _db.lastError().text();
            return false;
        }
    }
    return _initialized = true;
}

void PersistentStore::deinit()
{
    QMutexLocker locker(&_mutex);

    if(_initialized)
    {
        _db.close();
        _db = QSqlDatabase();
        _db.removeDatabase("QSQLITE");
        _initialized = false;
    }
}
QMutex* PersistentStore::mutex()
{
    return &_mutex;
}

QSqlQuery PersistentStore::createQuery()
{
    if (_initialized)
    {
        return QSqlQuery(_db);
    }
    else
    {
        DEBUG << "PersistentStore not initialized.";
        return QSqlQuery();
    }
}

PersistentStore::~PersistentStore()
{
    deinit();
}

void PersistentStore::purge()
{
    if(_initialized)
    {
        QString dbUrl = _db.databaseName();
        deinit();
        QFile dbFile(dbUrl);
        if(dbFile.exists())
            dbFile.remove();
        else
            DEBUG << "DB file not accessible: " << dbUrl;
    }
    else
    {
        DEBUG << "DB not initialized.";
    }
}

void PersistentStore::lock()
{
    _mutex.lock();
}

void PersistentStore::unlock()
{
    _mutex.unlock();
}

bool PersistentStore::runQuery(QSqlQuery query)
{
    QMutexLocker locker(&_mutex);

    bool result = false;
    if(_initialized)
    {
        if(!query.exec())
            DEBUG << query.lastError().text();
        else
            result = true;
    }
    else
    {
        DEBUG << "DB not initialized.";
    }

    return result;
}

bool PersistentStore::upgradeVersion0()
{
    bool result = false;
    QSqlQuery query(_db);

    if((result = query.exec("CREATE TABLE version (version INTEGER NOT NULL);")))
        result = query.exec("INSERT INTO version VALUES (0);");

    if (!result)
    {
        DEBUG << query.lastError().text();
        DEBUG << "Failed to upgrade DB to version 0." << _db;
    }
    return result;
}

bool PersistentStore::upgradeVersion1()
{
    bool result = false;
    QSqlQuery query(_db);

    if((result = query.exec("ALTER TABLE jobs ADD COLUMN optionScheduledEnabled INTEGER;")))
        result = query.exec("UPDATE version SET version = 1;");

    // Handle the special case, since I started versioning DB after two app
    // releases and this change in between...
    if(!result && query.lastError().text().contains("duplicate column name"))
        result = query.exec("UPDATE version SET version = 1;");

    if (!result)
    {
        DEBUG << query.lastError().text();
        DEBUG << "Failed to upgrade DB to version 1." << _db.databaseName();
    }
    return result;
}

bool PersistentStore::upgradeVersion2()
{
    bool result = false;
    QSqlQuery query(_db);

    if((result = query.exec("ALTER TABLE jobs ADD COLUMN optionSkipFiles INTEGER;")))
        result = query.exec("ALTER TABLE jobs ADD COLUMN optionSkipFilesPatterns TEXT;");

    if(result)
        result = query.exec("UPDATE version SET version = 2;");

    if (!result)
    {
        DEBUG << query.lastError().text();
        DEBUG << "Failed to upgrade DB to version 2." << _db.databaseName();
    }
    return result;
}
<commit_msg>Upgrade DB all the way to the latest in one shot.<commit_after>#include "persistentstore.h"
#include "debug.h"

#include <QSettings>
#include <QFileInfo>
#include <QFile>

PersistentStore::PersistentStore(QObject *parent) : QObject(parent), _initialized(false)
{
    init();
}

bool PersistentStore::init()
{
    QMutexLocker locker(&_mutex);

    QSettings settings;
    QString appdata = settings.value("app/app_data").toString();
    if(appdata.isEmpty())
    {
        DEBUG << "Error creating the PersistentStore: app.appdata not set.";
        return false;
    }
    bool create = false;
    QString dbUrl(appdata + QDir::separator() + DEFAULT_DBNAME);
    QFileInfo dbFileInfo(dbUrl);

    _db = _db.addDatabase("QSQLITE");
    _db.setConnectOptions("QSQLITE_OPEN_URI");
    _db.setDatabaseName(dbUrl);

    if(!dbFileInfo.exists())
    {
        create = true;
    }
    else if(!dbFileInfo.isFile() || !dbFileInfo.isReadable())
    {
        DEBUG << "Error creating the PersistentStore: DB file is not accessible " << dbUrl;
        return false;
    }
    else if (!_db.open())
    {
        DEBUG << "Error opening the PersistentStore DB: " << _db.lastError().text();
        return false;
    }
    else
    {
        QStringList tables = _db.tables();
        if (!tables.contains("archives", Qt::CaseInsensitive))
        {
            _db.close();
            DEBUG << "Invalid PersistentStore DB found. Attempting to recover.";
            if(!QFile::rename(dbUrl, dbUrl + "." + QString::number(QDateTime::currentMSecsSinceEpoch())))
            {
                DEBUG << "Failed to rename current invalid PersistentStore DB. Please manually cleanup the DB directory " << appdata;
                return false;
            }
            create = true;
        }
        else
        {
            if(!tables.contains("version", Qt::CaseInsensitive))
            {
                if(!upgradeVersion0())
                {
                    DEBUG << "Failed to upgrade PersistentStore DB. It's best to start from scratch by purging the existing DB in " << appdata;
                    return false;
                }
            }
            int version = -1;
            QSqlQuery query(_db);
            if (query.exec("SELECT version FROM version"))
            {
                query.next();
                version = query.value(0).toInt();
            }
            else
            {
                DEBUG << "Failed to get current DB version: " << query.lastError().text();
                return false;
            }
            if((version == 0) && upgradeVersion1())
            {
                DEBUG << "DB upgraded to version 1.";
                version = 1;
            }
            if((version == 1) && upgradeVersion2())
            {
                DEBUG << "DB upgraded to version 2.";
                version = 2;
            }
        }
    }

    if(create)
    {
        QFile dbTemplate(":/dbtemplate.db");
        if(!dbTemplate.copy(dbUrl))
        {
            DEBUG << "Failed to create the PersistentStore DB.";
            return false;
        }
        // Work around the fact that QFile::copy from the resource system does not set u+w on the resulted file
        QFile dbFile(dbUrl);
        dbFile.setPermissions(dbFile.permissions() | QFileDevice::WriteOwner);
        dbFile.close();
        if (!_db.open())
        {
            DEBUG << "Error opening the PersistentStore DB: " << _db.lastError().text();
            return false;
        }
    }
    return _initialized = true;
}

void PersistentStore::deinit()
{
    QMutexLocker locker(&_mutex);

    if(_initialized)
    {
        _db.close();
        _db = QSqlDatabase();
        _db.removeDatabase("QSQLITE");
        _initialized = false;
    }
}
QMutex* PersistentStore::mutex()
{
    return &_mutex;
}

QSqlQuery PersistentStore::createQuery()
{
    if (_initialized)
    {
        return QSqlQuery(_db);
    }
    else
    {
        DEBUG << "PersistentStore not initialized.";
        return QSqlQuery();
    }
}

PersistentStore::~PersistentStore()
{
    deinit();
}

void PersistentStore::purge()
{
    if(_initialized)
    {
        QString dbUrl = _db.databaseName();
        deinit();
        QFile dbFile(dbUrl);
        if(dbFile.exists())
            dbFile.remove();
        else
            DEBUG << "DB file not accessible: " << dbUrl;
    }
    else
    {
        DEBUG << "DB not initialized.";
    }
}

void PersistentStore::lock()
{
    _mutex.lock();
}

void PersistentStore::unlock()
{
    _mutex.unlock();
}

bool PersistentStore::runQuery(QSqlQuery query)
{
    QMutexLocker locker(&_mutex);

    bool result = false;
    if(_initialized)
    {
        if(!query.exec())
            DEBUG << query.lastError().text();
        else
            result = true;
    }
    else
    {
        DEBUG << "DB not initialized.";
    }

    return result;
}

bool PersistentStore::upgradeVersion0()
{
    bool result = false;
    QSqlQuery query(_db);

    if((result = query.exec("CREATE TABLE version (version INTEGER NOT NULL);")))
        result = query.exec("INSERT INTO version VALUES (0);");

    if (!result)
    {
        DEBUG << query.lastError().text();
        DEBUG << "Failed to upgrade DB to version 0." << _db;
    }
    return result;
}

bool PersistentStore::upgradeVersion1()
{
    bool result = false;
    QSqlQuery query(_db);

    if((result = query.exec("ALTER TABLE jobs ADD COLUMN optionScheduledEnabled INTEGER;")))
        result = query.exec("UPDATE version SET version = 1;");

    // Handle the special case, since I started versioning DB after two app
    // releases and this change in between...
    if(!result && query.lastError().text().contains("duplicate column name"))
        result = query.exec("UPDATE version SET version = 1;");

    if (!result)
    {
        DEBUG << query.lastError().text();
        DEBUG << "Failed to upgrade DB to version 1." << _db.databaseName();
    }
    return result;
}

bool PersistentStore::upgradeVersion2()
{
    bool result = false;
    QSqlQuery query(_db);

    if((result = query.exec("ALTER TABLE jobs ADD COLUMN optionSkipFiles INTEGER;")))
        result = query.exec("ALTER TABLE jobs ADD COLUMN optionSkipFilesPatterns TEXT;");

    if(result)
        result = query.exec("UPDATE version SET version = 2;");

    if (!result)
    {
        DEBUG << query.lastError().text();
        DEBUG << "Failed to upgrade DB to version 2." << _db.databaseName();
    }
    return result;
}
<|endoftext|>