<commit_before>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.10 2006/08/31 11:09:10 brun Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;}
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   //Fill the cache buffer with the branches in the cache

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // estimate number of entries that can fit in the cache
   // compare it to the original value of fBufferSize not
   // to the real one
   fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;

   if (fEntryMax <= 0) fEntryMax = tree->GetEntries();
   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   //check if owner has a TEventList set. If yes we optimize for this special case
   //reading only the baskets containing entries in the list
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer,
   // then try to fill the cache from the list of selected branches,
   // otherwise normal read from file. Returns -1 in case of read
   // failure, 0 in case not in cache and 1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
         fNReadOk++;
      else if (res == 0)
         fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<commit_msg>avoid division by zero in entry number estimation<commit_after>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.11 2006/10/19 19:35:52 pcanal Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;}
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   // Fill the cache buffer with the branches in the cache.

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // Estimate number of entries that can fit in the cache compare it
   // to the original value of fBufferSize not to the real one
   if (fZipBytes==0) {
      fEntryNext = entry + tree->GetEntries();;
   } else {
      fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;
   }
   if (fEntryMax <= 0) fEntryMax = tree->GetEntries();
   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   // Check if owner has a TEventList set. If yes we optimize for this
   // Special case reading only the baskets containing entries in the
   // list.
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer.
   // Otherwise try to fill the cache from the list of selected branches,
   // and recheck if pos is now in the list.
   // Returns
   //    -1 in case of read failure,
   //     0 in case not in cache,
   //     1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
         fNReadOk++;
      else if (res == 0)
         fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<|endoftext|>


<commit_before>/* conduitConfigDialog.cc                KPilot
**
** Copyright (C) 2001 by Dan Pilone
**
** This file defines a .ui-based configuration dialog for conduits.
*/

/*
** 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 in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
** MA 02139, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

static const char *conduitconfigdialog_id =
	"$Id$";

#include "options.h"

#include <qlistview.h>
#include <qlabel.h>
#include <qtooltip.h>
#include <qfile.h>
#include <qpushbutton.h>

#include <kservice.h>
#include <kservicetype.h>
#include <kuserprofile.h>
#include <kprocess.h>
#include <kmessagebox.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <klibloader.h>

#include "plugin.h"
#include "kpilotConfig.h"

#include "conduitConfigDialog_base.h"
#include "conduitConfigDialog.moc"

#define CONDUIT_NAME    (0)
#define CONDUIT_COMMENT (1)
#define CONDUIT_DESKTOP (2)
#define CONDUIT_LIBRARY (3)

class ConduitTip : public QToolTip
{
public:
	ConduitTip(QListView *parent);
	virtual ~ConduitTip();

protected:
	virtual void maybeTip(const QPoint &);

	QListView *fListView;
} ;

ConduitTip::ConduitTip(QListView *p) :
	QToolTip(p->viewport(),0L),
	fListView(p)
{
	FUNCTIONSETUP;
}

ConduitTip::~ConduitTip()
{
	FUNCTIONSETUP;
}

/* virtual */ void ConduitTip::maybeTip(const QPoint &p)
{
	FUNCTIONSETUP;

	QListViewItem *l = fListView->itemAt(p);

	if (!l) return;

	// ConduitListItem *q = static_cast<ConduitListItem *>(l);

#ifdef DEBUG
	DEBUGKPILOT << fname
		<< ": Tip over "
		<< l->text(CONDUIT_NAME)
		<< " with text "
		<< l->text(CONDUIT_COMMENT)
		<< endl;
#endif

	QString s = l->text(CONDUIT_COMMENT);

	if (s.isEmpty()) return;
	if (s.find("<qt>",0,false) == -1)
	{
		s.prepend("<qt>");
		s.append("</qt>");
	}

	tip(fListView->itemRect(l),s);
}

ConduitConfigDialog::ConduitConfigDialog(QWidget * _w, const char *n,
	bool m) : UIDialog(_w, n, m)
{
	FUNCTIONSETUP;

	fConfigWidget = new ConduitConfigWidget(widget());

	fillLists();

	fConfigWidget->active->adjustSize();
	fConfigWidget->available->adjustSize();

	int w = QMAX(fConfigWidget->active->width(),
		fConfigWidget->available->width());

	fConfigWidget->available->resize(w,fConfigWidget->available->height());
	fConfigWidget->active->resize(w,fConfigWidget->active->height());
	fConfigWidget->available->setColumnWidth(0,w);
	fConfigWidget->active->setColumnWidth(0,w);
	fConfigWidget->available->setColumnWidthMode(0,QListView::Manual);
	fConfigWidget->active->setColumnWidthMode(0,QListView::Manual);

	QObject::connect(fConfigWidget->active,
		SIGNAL(selectionChanged(QListViewItem *)),
		this,SLOT(selected(QListViewItem *)));
	QObject::connect(fConfigWidget->available,
		SIGNAL(selectionChanged(QListViewItem *)),
		this,SLOT(selected(QListViewItem *)));
	QObject::connect(fConfigWidget->active,
		SIGNAL(doubleClicked(QListViewItem *)),
		this,SLOT(configureConduit()));

	QObject::connect(fConfigWidget->enableButton,
		SIGNAL(clicked()),
		this,SLOT(enableConduit()));
	QObject::connect(fConfigWidget->disableButton,
		SIGNAL(clicked()),
		this,SLOT(disableConduit()));
	QObject::connect(fConfigWidget->configButton,
		SIGNAL(clicked()),
		this,SLOT(configureConduit()));

	fConfigWidget->adjustSize();

	(void) new ConduitTip(fConfigWidget->active);
	(void) new ConduitTip(fConfigWidget->available);

	selected(0L);

	(void) conduitconfigdialog_id;
}

ConduitConfigDialog::~ConduitConfigDialog()
{
	FUNCTIONSETUP;
}

void ConduitConfigDialog::fillLists()
{
	FUNCTIONSETUP;

	QStringList potentiallyInstalled =
		KPilotConfig::getConfig().setConduitGroup().
		getInstalledConduits();
	KServiceTypeProfile::OfferList offers =
		KServiceTypeProfile::offers("KPilotConduit");

	// Now actually fill the two list boxes, just make
	// sure that nothing gets listed in both.
	//
	//
	QValueListIterator < KServiceOffer > availList(offers.begin());
	while (availList != offers.end())
	{
		KSharedPtr < KService > o = (*availList).service();

#ifdef DEBUG
		DEBUGKPILOT << fname << ": "
			<< o->desktopEntryName()
			<< " = " << o->name() << endl;
#endif

		QListViewItem *p = 0L;

		if (!o->exec().isEmpty())
		{
			kdWarning() << k_funcinfo
				<< ": Old-style conduit found "
				<< o->name()
				<< endl;
		}

		if (potentiallyInstalled.contains(o->desktopEntryName()) == 0)
		{
			p = new QListViewItem(fConfigWidget->available,
				o->name(),
				o->comment(),
				o->desktopEntryName(),
				o->library());
		}
		else
		{
			p = new QListViewItem(fConfigWidget->active,
				o->name(),
				o->comment(),
				o->desktopEntryName(),
				o->library());
		}

		++availList;
	}
}

void ConduitConfigDialog::selected(QListViewItem *p)
{
	FUNCTIONSETUP;

	if (!p)
	{
		fConfigWidget->configButton->setEnabled(false);
		fConfigWidget->enableButton->setEnabled(false);
		fConfigWidget->disableButton->setEnabled(false);
		return;
	}

	if (p->listView() == fConfigWidget->active)
	{
		fConfigWidget->configButton->setEnabled(true);
		fConfigWidget->enableButton->setEnabled(false);
		fConfigWidget->disableButton->setEnabled(true);
		fConfigWidget->available->clearSelection();
	}
	else
	{
		fConfigWidget->configButton->setEnabled(false);
		fConfigWidget->enableButton->setEnabled(true);
		fConfigWidget->disableButton->setEnabled(false);
		fConfigWidget->active->clearSelection();
	}
}

void ConduitConfigDialog::enableConduit()
{
	FUNCTIONSETUP;

	QListViewItem *l = fConfigWidget->available->currentItem();
	if (!l) return;

	fConfigWidget->available->takeItem(l);
	fConfigWidget->active->clearSelection();
	fConfigWidget->active->insertItem(l);
	fConfigWidget->active->setSelected(l,true);
	selected(l);
}

void ConduitConfigDialog::disableConduit()
{
	FUNCTIONSETUP;

	QListViewItem *l = fConfigWidget->active->currentItem();
	if (!l) return;

	fConfigWidget->active->takeItem(l);
	fConfigWidget->available->clearSelection();
	fConfigWidget->available->insertItem(l);
	fConfigWidget->available->setSelected(l,true);
	selected(l);
	fConfigWidget->available->setFocus();
}

void ConduitConfigDialog::configureConduit()
{
	FUNCTIONSETUP;

	QListViewItem *p = fConfigWidget->active->currentItem();

	if (!p)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": Executed NULL conduit?"
			<< endl;
#endif
		return;
	}

#ifdef DEBUG
	DEBUGKPILOT << fname
		<< ": Executing conduit "
		<< p->text(CONDUIT_NAME)
		<< endl;
#endif

	if (p->text(CONDUIT_LIBRARY).isEmpty())
	{
		warnNoExec(p);
		return;
	}

	const char *library = p->text(CONDUIT_LIBRARY);

	KLibFactory *f = KLibLoader::self()->
		factory(library);
	if (!f)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": No conduit library "
			<< library
			<< " found."
			<< endl;
#endif
		warnNoLibrary(p);
		return;
	}

	QStringList a;
	a.append("modal");

	QObject *o = f->create(this, 0L, "ConduitConfig",a);

	if (!o)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": Can't create object."
			<< endl;
#endif

		KLibLoader::self()->unloadLibrary(
			library);
		warnNoLibrary(p);
		return;
	}

	ConduitConfig *d = dynamic_cast<ConduitConfig *>(o);

	if (!d)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": Can't cast to dialog."
			<< endl;
#endif

		delete o;
		KLibLoader::self()->unloadLibrary(
			library);
		warnNoLibrary(p);
		return;
	}

	d->setConfig(&KPilotConfig::getConfig());
	d->readSettings();
	d->exec();

	delete d;
	KLibLoader::self()->unloadLibrary(
		library);
}

void ConduitConfigDialog::warnNoExec(const QListViewItem * p)
{
	FUNCTIONSETUP;

	QString msg = i18n("<qt>No library could be "
		"found for the conduit %1. This means that the "
		"conduit was not installed properly.</qt>")
		.arg(p->text(CONDUIT_NAME));

#ifdef DEBUG
	DEBUGKPILOT << fname << ": " << msg << endl;
#endif

	KMessageBox::error(this, msg, i18n("Conduit Error"));
}

void ConduitConfigDialog::warnNoLibrary(const QListViewItem *p)
{
	FUNCTIONSETUP;

	QString msg = i18n("<qt>There was a problem loading the library "
		"for the conduit %1. This means that the "
		"conduit was not installed properly.</qt>")
		.arg(p->text(CONDUIT_NAME));

	KMessageBox::error(this, msg, i18n("Conduit Error"));
}

/* virtual */ void ConduitConfigDialog::commitChanges()
{
	FUNCTIONSETUP;

	QStringList activeConduits;
	const QListViewItem *p = fConfigWidget->active->firstChild();
	KPilotConfigSettings & config = KPilotConfig::getConfig();

	while (p)
	{
		activeConduits.append(p->text(CONDUIT_DESKTOP));
		p = p->nextSibling();
	}
	config.setConduitGroup().setInstalledConduits(activeConduits);
	config.sync();
}

// $Log$
// Revision 1.9  2002/04/20 13:03:31  binner
// CVS_SILENT Capitalisation fixes.
//
// Revision 1.8  2002/04/16 18:18:13  adridg
// Minor debugging fixups by David B
//
// Revision 1.7  2002/01/26 15:00:11  adridg
// Dblclick to configure
//
// Revision 1.6  2002/01/02 11:42:19  bero
// Fix build.
//
// Revision 1.5  2001/12/31 09:26:15  adridg
// Removed support for old-style Exec= conduits
//
// Revision 1.4  2001/11/18 16:59:55  adridg
// New icons, DCOP changes
//
// Revision 1.3  2001/10/19 14:03:04  adridg
// Qt3 include fixes
//
// Revision 1.2  2001/10/08 22:20:18  adridg
// Changeover to libkpilot, prepare for lib-based conduits
//
// Revision 1.1  2001/10/04 16:53:57  adridg
// New files for newstyle config
//
<commit_msg>Start of work to move conduitConfig to list of QCheckBoxes<commit_after>/* conduitConfigDialog.cc                KPilot
**
** Copyright (C) 2001 by Dan Pilone
**
** This file defines a .ui-based configuration dialog for conduits.
*/

/*
** 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 in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
** MA 02139, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

static const char *conduitconfigdialog_id =
	"$Id$";

#include "options.h"

#include <qlistview.h>
#include <qlabel.h>
#include <qtooltip.h>
#include <qfile.h>
#include <qpushbutton.h>

#include <kservice.h>
#include <kservicetype.h>
#include <kuserprofile.h>
#include <kprocess.h>
#include <kmessagebox.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <klibloader.h>

#include "plugin.h"
#include "kpilotConfig.h"

#include "conduitConfigDialog_base.h"
#include "conduitConfigDialog.moc"

#define CONDUIT_NAME    (0)
#define CONDUIT_COMMENT (1)
#define CONDUIT_DESKTOP (2)
#define CONDUIT_LIBRARY (3)

class ConduitTip : public QToolTip
{
public:
	ConduitTip(QListView *parent);
	virtual ~ConduitTip();

protected:
	virtual void maybeTip(const QPoint &);

	QListView *fListView;
} ;

ConduitTip::ConduitTip(QListView *p) :
	QToolTip(p->viewport(),0L),
	fListView(p)
{
	FUNCTIONSETUP;
}

ConduitTip::~ConduitTip()
{
	FUNCTIONSETUP;
}

/* virtual */ void ConduitTip::maybeTip(const QPoint &p)
{
	FUNCTIONSETUP;

	QListViewItem *l = fListView->itemAt(p);

	if (!l) return;

	// ConduitListItem *q = static_cast<ConduitListItem *>(l);

#ifdef DEBUG
	DEBUGKPILOT << fname
		<< ": Tip over "
		<< l->text(CONDUIT_NAME)
		<< " with text "
		<< l->text(CONDUIT_COMMENT)
		<< endl;
#endif

	QString s = l->text(CONDUIT_COMMENT);

	if (s.isEmpty()) return;
	if (s.find("<qt>",0,false) == -1)
	{
		s.prepend("<qt>");
		s.append("</qt>");
	}

	tip(fListView->itemRect(l),s);
}

#if 0
/**
*** As-yet unused class for a list of QCheckBoxes, to replace
*** the unwieldy two-listbox layout we have now. This code
*** pretty much copies things from KDebugDialog.
***
*** We'll be inserting conduitDescription objects into the list,
*** which subsume the hacked QListViewItems we use now.
**/

/*
** KCheckBoxList
*/

#include <qscrollview.h>
#include <qptrlist.h>
#include <qvbox.h>
#include <qcheckbox.h>

class KCheckBoxList : public QScrollView
{
public:
	KCheckBoxList(QWidget *parent=0L);
	virtual ~KCheckBoxList();

	void addBoxes(const QStringList &);
	bool addBox(QCheckBox *p)
		{ if (p->parent()==boxParent())
			{ m_boxes.append(p); return true; }
		  else return false; } ;
	QPtrList<QCheckBox> checkedBoxes() const;
	const QPtrList<QCheckBox> allBoxes() const { return m_boxes; } ;

	void selectAllBoxes(bool);

	QWidget *boxParent() const { return m_box; } ;

protected:
	QVBox *m_box;
	QPtrList<QCheckBox> m_boxes;
} ;

KCheckBoxList::KCheckBoxList(QWidget *parent) :
	QScrollView(parent)
{
	setResizePolicy(QScrollView::AutoOneFit);
	m_box = new QVBox( viewport() );
	addChild(m_box);
}

KCheckBoxList::~KCheckBoxList()
{
	// All of the QCheckBoxes are my children,
	// they die with the widget.
}

void KCheckBoxList::addBoxes(const QStringList &l)
{
	QStringList::ConstIterator it = l.begin();
	for ( ; it != l.end(); ++it)
	{
		QCheckBox *cb = new QCheckBox(*it,m_box);
		m_boxes.append(cb);
	}
}

void KCheckBoxList::selectAllBoxes(bool b)
{
	QCheckBox *p;

	for (p=m_boxes.first(); p; p=m_boxes.next())
	{
		p->setChecked(b);
	}
}

QPtrList<QCheckBox> KCheckBoxList::checkedBoxes() const
{
	QPtrList<QCheckBox> l;
	QPtrListIterator<QCheckBox> it(m_boxes);
	QCheckBox *p;

	for ( ; (p = it.current()) ; ++it)
	{
		if (p->isChecked()) l.append(p);
	}

	return l;
}

class ConduitDescription : public QCheckBox
{
public:
	ConduitDescription(KCheckBoxList *owner,
		const QString &name,
		const QString &comment,
		const QString &desktop,
		const QString &library);
	virtual ~ConduitDescription();

	QString conduit() const { return text(); } ;
	QString comment() const { return fComment; } ;
	QString desktop() const { return fDesktop; } ;
	QString library() const { return fLibrary; } ;

protected:
	QString fComment,fDesktop,fLibrary;
} ;

ConduitDescription::ConduitDescription(KCheckBoxList *owner,
	const QString &name,
	const QString &comment,
	const QString &desktop,
	const QString &library) :
	QCheckBox(name,owner->boxParent()),
	fComment(comment),
	fDesktop(desktop),
	fLibrary(library)
{
	owner->addBox(this);
}

ConduitDescription::~ConduitDescription()
{
}
#endif

ConduitConfigDialog::ConduitConfigDialog(QWidget * _w, const char *n,
	bool m) : UIDialog(_w, n, m)
{
	FUNCTIONSETUP;

	fConfigWidget = new ConduitConfigWidget(widget());

	fillLists();

	fConfigWidget->active->adjustSize();
	fConfigWidget->available->adjustSize();

	int w = QMAX(fConfigWidget->active->width(),
		fConfigWidget->available->width());

	fConfigWidget->available->resize(w,fConfigWidget->available->height());
	fConfigWidget->active->resize(w,fConfigWidget->active->height());
	fConfigWidget->available->setColumnWidth(0,w);
	fConfigWidget->active->setColumnWidth(0,w);
	fConfigWidget->available->setColumnWidthMode(0,QListView::Manual);
	fConfigWidget->active->setColumnWidthMode(0,QListView::Manual);

	QObject::connect(fConfigWidget->active,
		SIGNAL(selectionChanged(QListViewItem *)),
		this,SLOT(selected(QListViewItem *)));
	QObject::connect(fConfigWidget->available,
		SIGNAL(selectionChanged(QListViewItem *)),
		this,SLOT(selected(QListViewItem *)));
	QObject::connect(fConfigWidget->active,
		SIGNAL(doubleClicked(QListViewItem *)),
		this,SLOT(configureConduit()));

	QObject::connect(fConfigWidget->enableButton,
		SIGNAL(clicked()),
		this,SLOT(enableConduit()));
	QObject::connect(fConfigWidget->disableButton,
		SIGNAL(clicked()),
		this,SLOT(disableConduit()));
	QObject::connect(fConfigWidget->configButton,
		SIGNAL(clicked()),
		this,SLOT(configureConduit()));

	fConfigWidget->adjustSize();

	(void) new ConduitTip(fConfigWidget->active);
	(void) new ConduitTip(fConfigWidget->available);

	selected(0L);

	(void) conduitconfigdialog_id;
}

ConduitConfigDialog::~ConduitConfigDialog()
{
	FUNCTIONSETUP;
}

void ConduitConfigDialog::fillLists()
{
	FUNCTIONSETUP;

	QStringList potentiallyInstalled =
		KPilotConfig::getConfig().setConduitGroup().
		getInstalledConduits();
	KServiceTypeProfile::OfferList offers =
		KServiceTypeProfile::offers("KPilotConduit");

	// Now actually fill the two list boxes, just make
	// sure that nothing gets listed in both.
	//
	//
	QValueListIterator < KServiceOffer > availList(offers.begin());
	while (availList != offers.end())
	{
		KSharedPtr < KService > o = (*availList).service();

#ifdef DEBUG
		DEBUGKPILOT << fname << ": "
			<< o->desktopEntryName()
			<< " = " << o->name() << endl;
#endif

		QListViewItem *p = 0L;

		if (!o->exec().isEmpty())
		{
			kdWarning() << k_funcinfo
				<< ": Old-style conduit found "
				<< o->name()
				<< endl;
		}

		if (potentiallyInstalled.contains(o->desktopEntryName()) == 0)
		{
			p = new QListViewItem(fConfigWidget->available,
				o->name(),
				o->comment(),
				o->desktopEntryName(),
				o->library());
		}
		else
		{
			p = new QListViewItem(fConfigWidget->active,
				o->name(),
				o->comment(),
				o->desktopEntryName(),
				o->library());
		}

		++availList;
	}
}

void ConduitConfigDialog::selected(QListViewItem *p)
{
	FUNCTIONSETUP;

	if (!p)
	{
		fConfigWidget->configButton->setEnabled(false);
		fConfigWidget->enableButton->setEnabled(false);
		fConfigWidget->disableButton->setEnabled(false);
		return;
	}

	if (p->listView() == fConfigWidget->active)
	{
		fConfigWidget->configButton->setEnabled(true);
		fConfigWidget->enableButton->setEnabled(false);
		fConfigWidget->disableButton->setEnabled(true);
		fConfigWidget->available->clearSelection();
	}
	else
	{
		fConfigWidget->configButton->setEnabled(false);
		fConfigWidget->enableButton->setEnabled(true);
		fConfigWidget->disableButton->setEnabled(false);
		fConfigWidget->active->clearSelection();
	}
}

void ConduitConfigDialog::enableConduit()
{
	FUNCTIONSETUP;

	QListViewItem *l = fConfigWidget->available->currentItem();
	if (!l) return;

	fConfigWidget->available->takeItem(l);
	fConfigWidget->active->clearSelection();
	fConfigWidget->active->insertItem(l);
	fConfigWidget->active->setSelected(l,true);
	selected(l);
}

void ConduitConfigDialog::disableConduit()
{
	FUNCTIONSETUP;

	QListViewItem *l = fConfigWidget->active->currentItem();
	if (!l) return;

	fConfigWidget->active->takeItem(l);
	fConfigWidget->available->clearSelection();
	fConfigWidget->available->insertItem(l);
	fConfigWidget->available->setSelected(l,true);
	selected(l);
	fConfigWidget->available->setFocus();
}

void ConduitConfigDialog::configureConduit()
{
	FUNCTIONSETUP;

	QListViewItem *p = fConfigWidget->active->currentItem();

	if (!p)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": Executed NULL conduit?"
			<< endl;
#endif
		return;
	}

#ifdef DEBUG
	DEBUGKPILOT << fname
		<< ": Executing conduit "
		<< p->text(CONDUIT_NAME)
		<< endl;
#endif

	if (p->text(CONDUIT_LIBRARY).isEmpty())
	{
		warnNoExec(p);
		return;
	}

	const char *library = p->text(CONDUIT_LIBRARY);

	KLibFactory *f = KLibLoader::self()->
		factory(library);
	if (!f)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": No conduit library "
			<< library
			<< " found."
			<< endl;
#endif
		warnNoLibrary(p);
		return;
	}

	QStringList a;
	a.append("modal");

	QObject *o = f->create(this, 0L, "ConduitConfig",a);

	if (!o)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": Can't create object."
			<< endl;
#endif

		KLibLoader::self()->unloadLibrary(
			library);
		warnNoLibrary(p);
		return;
	}

	ConduitConfig *d = dynamic_cast<ConduitConfig *>(o);

	if (!d)
	{
#ifdef DEBUG
		DEBUGKPILOT << fname
			<< ": Can't cast to dialog."
			<< endl;
#endif

		delete o;
		KLibLoader::self()->unloadLibrary(
			library);
		warnNoLibrary(p);
		return;
	}

	d->setConfig(&KPilotConfig::getConfig());
	d->readSettings();
	d->exec();

	delete d;
	KLibLoader::self()->unloadLibrary(
		library);
}

void ConduitConfigDialog::warnNoExec(const QListViewItem * p)
{
	FUNCTIONSETUP;

	QString msg = i18n("<qt>No library could be "
		"found for the conduit %1. This means that the "
		"conduit was not installed properly.</qt>")
		.arg(p->text(CONDUIT_NAME));

#ifdef DEBUG
	DEBUGKPILOT << fname << ": " << msg << endl;
#endif

	KMessageBox::error(this, msg, i18n("Conduit Error"));
}

void ConduitConfigDialog::warnNoLibrary(const QListViewItem *p)
{
	FUNCTIONSETUP;

	QString msg = i18n("<qt>There was a problem loading the library "
		"for the conduit %1. This means that the "
		"conduit was not installed properly.</qt>")
		.arg(p->text(CONDUIT_NAME));

	KMessageBox::error(this, msg, i18n("Conduit Error"));
}

/* virtual */ void ConduitConfigDialog::commitChanges()
{
	FUNCTIONSETUP;

	QStringList activeConduits;
	const QListViewItem *p = fConfigWidget->active->firstChild();
	KPilotConfigSettings & config = KPilotConfig::getConfig();

	while (p)
	{
		activeConduits.append(p->text(CONDUIT_DESKTOP));
		p = p->nextSibling();
	}
	config.setConduitGroup().setInstalledConduits(activeConduits);
	config.sync();
}

// $Log$
// Revision 1.10  2002/12/31 13:22:07  mueller
// CVS_SILENT fixincludes
//
// Revision 1.9  2002/04/20 13:03:31  binner
// CVS_SILENT Capitalisation fixes.
//
// Revision 1.8  2002/04/16 18:18:13  adridg
// Minor debugging fixups by David B
//
// Revision 1.7  2002/01/26 15:00:11  adridg
// Dblclick to configure
//
// Revision 1.6  2002/01/02 11:42:19  bero
// Fix build.
//
// Revision 1.5  2001/12/31 09:26:15  adridg
// Removed support for old-style Exec= conduits
//
// Revision 1.4  2001/11/18 16:59:55  adridg
// New icons, DCOP changes
//
// Revision 1.3  2001/10/19 14:03:04  adridg
// Qt3 include fixes
//
// Revision 1.2  2001/10/08 22:20:18  adridg
// Changeover to libkpilot, prepare for lib-based conduits
//
// Revision 1.1  2001/10/04 16:53:57  adridg
// New files for newstyle config
//
<|endoftext|>


<commit_before>/**
*
*  @file mmUtils.cpp
*  @brief MotionMachine source file for Utils.
*  @author Mickael Tits
*  @copyright Numediart Institute, UMONS (c) 2014-2015
*
*/

#include "mmUtils.h"

#ifndef _WIN32
#include "unistd.h"
#endif

using namespace std;

//string MoMa::getExeFilePath( void ) {
//
//    return "";
//
//    // taken from ofFileUtils
//    /*#if defined(_WIN32)
//    vector<char> executablePath(MAX_PATH);
//    DWORD result = ::GetModuleFileNameA(NULL, &executablePath[0], static_cast<DWORD>(executablePath.size()));
//    if(result == 0) {
//    cout << "getAppPath(): couldn't get path, GetModuleFileNameA failed";
//    }else{
//    return string(executablePath.begin(), executablePath.begin() + result);
//    }
//    #elif defined(__APPLE_CC__)
//    char path[FILENAME_MAX];
//    uint32_t size = sizeof(path);
//    if(_NSGetExecutablePath(path, &size) != 0){
//    cout << "getAppPath(): path buffer too small, need size " <<  size;
//    }
//    return path;
//    #else //Linux
//    char buff[FILENAME_MAX];
//    ssize_t size = readlink("/proc/self/exe", buff, sizeof(buff) - 1);
//    if (size == -1){
//    cout << "getAppPath(): readlink failed with error " << errno;
//    }
//    else{
//    buff[size] = '\0';
//    return buff;
//    }
//
//    #endif
//    return "";*/
//}

string MoMa::getAbsoluteAppPath( void ) {

#ifdef _WIN32
    wchar_t* cwd;
    wchar_t buff[MAX_PATH + 1];

    cwd = _wgetcwd( buff, MAX_PATH + 1 );
    wstring ws(cwd);
    //wcout << "wide string : " << ws << endl;
    string str(ws.begin(), ws.end());
    //cout << "string : " << str << endl;
    str = str + "/";

    //cout << "appPath : " << str << endl;
    //Uncomment if you have bugs with special ASCII characters
    //checkFilePath(str);

    //cout << "Corrected appPath : " << str << endl;

    return str;
#else
    char* cwd;
    char buff[PATH_MAX + 1];

    cwd = getcwd( (char*)buff, (size_t)(PATH_MAX + 1) );

    if( cwd != NULL ) {

        // printf( "My working directory is %s.\n", cwd );

        string str( cwd );
        str = str + "/../../../";

        return str;

    } else {

        string str = "";
        return str;
    }
#endif

    /*string filePath = getExeFilePath();
    size_t sep = filePath.find_last_of("\\/");
    string appDir = filePath.substr( 0, sep+1 );
    return appDir;*/
}

string MoMa::getAppPath( void ) {

#ifdef _WIN32
    return "";
#else
    return"../../../";
#endif
}

string MoMa::getLibPath( void ) {

    string appDir = getAppPath();
#ifdef NDEBUG
    cout << "Warning : you should not use getLibPath nor getAbsoluteLibPath in Release mode. If the bin folder is moved, the relative path to the libs will be incorrect." << endl;
#endif
#ifdef _WIN32
    return( appDir + "../../../../libs/MoMa/" );
#else
    return( appDir +  "../../../../../../../libs/MoMa/" );
#endif
}

string MoMa::getAbsoluteLibPath( void ) {

    string appDir = getAbsoluteAppPath();
#ifdef NDEBUG
    cout << "Warning : you should not use getLibPath nor getAbsoluteLibPath in Release mode. If the bin folder is moved, the relative path to the libs will be incorrect." << endl;
#endif
#ifdef _WIN32
    return( appDir + "../../../../libs/MoMa/" );
#else
    return( appDir +  "../../../../libs/MoMa/" );
#endif
}

string MoMa::getDataPath( void ) {

    string appDir = getAppPath();
    return( appDir + "data/" );
}

string MoMa::getAbsoluteDataPath( void ) {

    string appDir = getAbsoluteAppPath();
    return( appDir + "data/" );
}

//unsafe to use
/*string MoMa::getResPath( void ) {

#ifdef NDEBUG
    string appDir = getAppPath();
    return( appDir + "data/resources/" );
#else
    string libDir = getLibPath();
    return( libDir + "resources/" );
#endif
}*/

string MoMa::getAbsoluteResPath( void ) {

#ifdef NDEBUG
    string appDir = getAbsoluteAppPath();
    return( appDir + "data/resources/" );
#else
    string libDir = getAbsoluteLibPath();
    return( libDir + "resources/" );
#endif
}

void MoMa::correctPath( string &path, bool invert ) {

    string tmp;

    // Manage special characters (accents
    // for example) in file path (extended ASCII table)
    if(!invert) {

        for( int i=0; i<path.size(); ++i ) {

            if( path[i] != -61 ) {

                // Basic ASCII table
                tmp.push_back( path[i] );

            } else {

                // Manage buggy special characters (extended ASCII character) the
                // special character is divided in two characters : -61 and X (between
                // -1 and -127); to get a valid character the conversion is c = X+64

                ++i; // tmp[i] was -61
                tmp.push_back( path[i]+64 );
            }
        }
    }
    else {

        for( int i=0; i<path.size(); ++i ) {

            if( path[i] >= 0 ) {

                // Basic ASCII table
                tmp.push_back( path[i] );

            } else {

                // Negative ASCII character

                tmp.push_back(-61);
                tmp.push_back( path[i]-64 );
            }
        }
    }

    path.clear();
    path = tmp;
}

void MoMa::checkFilePath( string &path ) {

    ifstream fPath( path.c_str() );

    if(!fPath) {

        correctPath( path );
        fPath = ifstream( path.c_str() );

        if(!fPath) {

            correctPath( path, true );
            fPath = ifstream( path.c_str() );

            if(!fPath) {

                cout << "The following path does not exists or is not accessible : " << path << endl;
            }
        }
    }
}

string MoMa::getExtension(string filePath) {

    size_t dot = filePath.find_last_of(".");
    string extension = filePath.substr(dot + 1);
    transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
    return extension;
}

string MoMa::getName(string filePath) {

    size_t sep = filePath.find_last_of("\\/");
    size_t dot = filePath.find_last_of(".");
    return filePath.substr(sep + 1, dot - sep - 1);
}

string MoMa::getFolder(string filePath) {

    size_t sep = filePath.find_last_of("\\/");
    return filePath.substr(0,sep);
}
<commit_msg>minor correction in mmUtils<commit_after>/**
*
*  @file mmUtils.cpp
*  @brief MotionMachine source file for Utils.
*  @author Mickael Tits
*  @copyright Numediart Institute, UMONS (c) 2014-2015
*
*/

#include "mmUtils.h"

#ifndef _WIN32
#include "unistd.h"
#endif

using namespace std;

//string MoMa::getExeFilePath( void ) {
//
//    return "";
//
//    // taken from ofFileUtils
//    /*#if defined(_WIN32)
//    vector<char> executablePath(MAX_PATH);
//    DWORD result = ::GetModuleFileNameA(NULL, &executablePath[0], static_cast<DWORD>(executablePath.size()));
//    if(result == 0) {
//    cout << "getAppPath(): couldn't get path, GetModuleFileNameA failed";
//    }else{
//    return string(executablePath.begin(), executablePath.begin() + result);
//    }
//    #elif defined(__APPLE_CC__)
//    char path[FILENAME_MAX];
//    uint32_t size = sizeof(path);
//    if(_NSGetExecutablePath(path, &size) != 0){
//    cout << "getAppPath(): path buffer too small, need size " <<  size;
//    }
//    return path;
//    #else //Linux
//    char buff[FILENAME_MAX];
//    ssize_t size = readlink("/proc/self/exe", buff, sizeof(buff) - 1);
//    if (size == -1){
//    cout << "getAppPath(): readlink failed with error " << errno;
//    }
//    else{
//    buff[size] = '\0';
//    return buff;
//    }
//
//    #endif
//    return "";*/
//}

string MoMa::getAbsoluteAppPath( void ) {

#ifdef _WIN32
    wchar_t* cwd;
    wchar_t buff[MAX_PATH + 1];

    cwd = _wgetcwd( buff, MAX_PATH + 1 );
    wstring ws(cwd);
    //wcout << "wide string : " << ws << endl;
    string str(ws.begin(), ws.end());
    //cout << "string : " << str << endl;
    str = str + "/";

    //cout << "appPath : " << str << endl;
    //Uncomment if you have bugs with special ASCII characters
    //checkFilePath(str);

    //cout << "Corrected appPath : " << str << endl;

    return str;
#else
    char* cwd;
    char buff[PATH_MAX + 1];

    cwd = getcwd( (char*)buff, (size_t)(PATH_MAX + 1) );

    if( cwd != NULL ) {

        // printf( "My working directory is %s.\n", cwd );

        string str( cwd );
        str = str + "/../../../";

        return str;

    } else {

        string str = "";
        return str;
    }
#endif

    /*string filePath = getExeFilePath();
    size_t sep = filePath.find_last_of("\\/");
    string appDir = filePath.substr( 0, sep+1 );
    return appDir;*/
}

string MoMa::getAppPath( void ) {

#ifdef _WIN32
    return "";
#else
    return"../../../";
#endif
}

string MoMa::getLibPath( void ) {

    string appDir = getAppPath();
#ifdef NDEBUG
    cout << "Warning : you should not use getLibPath nor getAbsoluteLibPath in Release mode. If the bin folder is moved, the relative path to the libs will be incorrect." << endl;
#endif
#ifdef _WIN32
    return( appDir + "../../../../libs/MoMa/" );
#else
    return( appDir +  "../../../../../../../libs/MoMa/" );
#endif
}

string MoMa::getAbsoluteLibPath( void ) {

    string appDir = getAbsoluteAppPath();
#ifdef NDEBUG
    cout << "Warning : you should not use getLibPath nor getAbsoluteLibPath in Release mode. If the bin folder is moved, the relative path to the libs will be incorrect." << endl;
#endif
#ifdef _WIN32
    return( appDir + "../../../../libs/MoMa/" );
#else
    return( appDir +  "../../../../libs/MoMa/" );
#endif
}

string MoMa::getDataPath( void ) {

    string appDir = getAppPath();
    return( appDir + "data/" );
}

string MoMa::getAbsoluteDataPath( void ) {

    string appDir = getAbsoluteAppPath();
    return( appDir + "data/" );
}

//unsafe to use
/*string MoMa::getResPath( void ) {

#ifdef NDEBUG
    string appDir = getAppPath();
    return( appDir + "data/resources/" );
#else
    string libDir = getLibPath();
    return( libDir + "resources/" );
#endif
}*/

string MoMa::getAbsoluteResPath( void ) {

#ifdef NDEBUG
    string appDir = getAbsoluteAppPath();
    return( appDir + "data/resources/" );
#else
    string libDir = getAbsoluteLibPath();
    return( libDir + "resources/" );
#endif
}

void MoMa::correctPath( string &path, bool invert ) {

    string tmp;

    // Manage special characters (accents
    // for example) in file path (extended ASCII table)
    if(!invert) {

        for( int i=0; i<path.size(); ++i ) {

            if( path[i] != -61 ) {

                // Basic ASCII table
                tmp.push_back( path[i] );

            } else {

                // Manage buggy special characters (extended ASCII character) the
                // special character is divided in two characters : -61 and X (between
                // -1 and -127); to get a valid character the conversion is c = X+64

                ++i; // tmp[i] was -61
                tmp.push_back( path[i]+64 );
            }
        }
    }
    else {

        for( int i=0; i<path.size(); ++i ) {

            if( path[i] >= 0 ) {

                // Basic ASCII table
                tmp.push_back( path[i] );

            } else {

                // Negative ASCII character

                tmp.push_back(-61);
                tmp.push_back( path[i]-64 );
            }
        }
    }

    path.clear();
    path = tmp;
}

void MoMa::checkFilePath( string &path ) {

    ifstream fPath( path.c_str() );

    if(!fPath) {

        correctPath( path );
        fPath = ifstream( path.c_str() );

        if(!fPath) {

            correctPath( path, true );
            fPath = ifstream( path.c_str() );

            if(!fPath) {

                cout << "The following path does not exists or is not accessible : " << path << endl;
            }
        }
    }
}

string MoMa::getExtension(string filePath) {

    size_t dot = filePath.find_last_of(".");
    string extension = filePath.substr(dot + 1);
    transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
    return extension;
}

string MoMa::getName(string filePath) {

    size_t sep = filePath.find_last_of("\\/");
    size_t dot = filePath.find_last_of(".");
    return filePath.substr(sep + 1, dot - sep - 1); //length of dot - sep - 1
}

string MoMa::getFolder(string filePath) {

    size_t sep = filePath.find_last_of("\\/");
    return filePath.substr(0,sep+1); //length of sep+1
}
<|endoftext|>


<commit_before>#include <singleton.hpp>
#include <vector>
#include <types.hpp>
#include <gameobject.hpp>

#ifndef ENGINE_HPP
#define ENGINE_HPP

namespace fabric {
	// The class holding all Engine stuff
	// There will always only be one therfor the Singleton inheritence
	class Engine : public fabric::Singleton<Engine>
	{
	public:
		// Main Eventloop
		// Calls it self till programm exits
		int eventLoop();

		Engine() {
			vLoadedGameObjects = new vector<GameObject*>;
		}

		~Engine() {
			delete vLoadedGameObjects;
			vLoadedGameObjects = 0;
		}

	private:

		vector<GameObject*>* vLoadedGameObjects;

		// Called from the eventloop when the programms exits
		int exitRoutin();

	};

}

#endif // !ENGINE_HPP
<commit_msg>Adde SDL related variables<commit_after>#include <singleton.hpp>
#include <vector>
#include <types.hpp>
#include <gameobject.hpp>
#include "../SDL/include/SDL.h"

#ifndef ENGINE_HPP
#define ENGINE_HPP

namespace fabric {
	// The class holding all Engine stuff
	// There will always only be one therfor the Singleton inheritence
	class Engine : public fabric::Singleton<Engine>
	{
	public:

		vector<GameObject*>* vLoadedGameObjects;

		// Main Eventloop
		// Calls it self till programm exits
		int startRoutin();

		Engine() {
			vLoadedGameObjects = new vector<GameObject*>;
		}

		~Engine() {
			delete vLoadedGameObjects;
			vLoadedGameObjects = 0;
		}

	private:

		SDL_Window* m_pWindow;
		SDL_Surface* m_pScreenSurface;
		SDL_Event* m_event;

		// Called from the eventloop when the programms exits
		int exitRoutin();
		int eventLoop();

	};

}

#endif // !ENGINE_HPP
<|endoftext|>


<commit_before>/// @file AesopPlanner.cpp
/// @brief Implementation of Planner class as defined in Aesop.h

#include "Aesop.h"

#include <functional>
#include <algorithm>
#include <vector>

namespace ae {
   /// @class Planner
   ///
   /// A Planner object actually performs plan queries on the world state.
   /// It represents an entire planning state, with its own start and end
   /// states and plan-specific data.
   /// This will include, among other things, a set of vetoed Actions (for
   /// example, Actions that we tried but failed in practis, and we now
   /// want to exclude from our planning process temporarily).

   Planner::Planner(const WorldState *start, const WorldState *goal, const ActionSet *set)
   {
      setStart(start);
      setGoal(goal);
      setActions(set);
      mPlanning = false;
      mId = 0;
   }

   Planner::Planner()
   {
      Planner(NULL, NULL, NULL);
   }

   Planner::~Planner()
   {
   }

   void Planner::setStart(const WorldState *start)
   {
      mStart = start;
   }

   void Planner::setGoal(const WorldState *goal)
   {
      mGoal = goal;
   }

   void Planner::setActions(const ActionSet *set)
   {
      mActions = set;
   }

   bool Planner::isPlanning() const
   {
      return mPlanning;
   }

   const Plan& Planner::getPlan() const
   {
      return mPlan;
   }

   /// This method is actually just a wrapper for a series of calls to the
   /// sliced planning methods.
   bool Planner::plan(AesopLogger *log)
   {
      // Try to start planning.
      if(!initSlicedPlan(log))
         return false;

      while(isPlanning())
      {
         // Increment plan and capture failure.
         if(!updateSlicedPlan(log))
            return false;
         // If planning has halted, we must have been successful.
         if(!isPlanning())
         {
            finaliseSlicedPlan(log);
            return true;
         }
      }

      // No plan found.
      return false;
   }

   bool Planner::initSlicedPlan(AesopLogger *log)
   {
      // Validate pointers.
      if(!mStart || !mGoal || !mActions)
         return false;

      // Reset intermediate data.
      mPlanning = true;
      mOpenList.clear();
      mClosedList.clear();
      mId = 0;

      // Push initial state onto the open list.
      mOpenList.push_back(IntermediateState(mId)); mId++;
      mOpenList.back().state = *mGoal;

      return true;
   }

   void Planner::finaliseSlicedPlan(AesopLogger *log)
   {
      // Work backwards up the closed list to get the final plan.
      mPlan.clear();
      unsigned int i = mClosedList.size() - 1;
      while(i)
      {
         // Extract the Action performed at this step.
         mPlan.push_back(mClosedList[i].ac);
         // Iterate.
         i = mClosedList[i].prev;
      }
      // Purge intermediate results.
      mOpenList.clear();
      mClosedList.clear();
      mPlanning = false;
   }

   bool Planner::updateSlicedPlan(AesopLogger *log)
   {
      // Main loop of A* search.
      if(!mOpenList.empty())
      {
         // Remove best IntermediateState from open list.
         pop_heap(mOpenList.begin(), mOpenList.end(), std::greater<IntermediateState>());
         IntermediateState s = mOpenList.back();
         mOpenList.pop_back();

         if(log) log->logEvent("Moving state %d from open to closed.", s.ID);

         // Add to closed list.
         mClosedList.push_back(s);

         // Check for completeness.
         if(s.state == *mStart)
         {
            mPlanning = false;
            return true;
         }

         // Find all actions we can use that may result in the current state.
         ActionSet::const_iterator it;
         for(it = mActions->begin(); it != mActions->end(); it++)
         {
            if(*it && s.state.actionPostMatch(*it))
            {
               IntermediateState n(mId); mId++;
               // Copy the current state, then apply the Action to it in
               // reverse to get the previous state.
               n.state = s.state;
               n.state.applyActionReverse(*it);

               closedlist::const_iterator cli;
               // Check to see if the world state is in the closed list.
               bool found = false;
               for(cli = mClosedList.begin(); cli != mClosedList.end(); cli++)
               {
                  if(n.state == cli->state)
                  {
                     found = true;
                     break;
                  }
               }
               if(found)
                  continue;

               // H (heuristic) cost is the estimated number of Actions to get
               // from new state to start.
               n.H = (float)WorldState::comp(n.state, *mStart);
               // G cost is the total weight of all Actions we've taken to get
               // to this state. By default, the cost of an Action is 1.
               n.G = s.G + (*it)->getCost();
               // Save this to avoid recalculating every time.
               n.F = n.G + n.H;
               // Remember Action we used to to this state.
               n.ac = *it;
               // Predecessor is the last state to be added to the closed list.
               n.prev = mClosedList.size() - 1;

               openlist::iterator oli;
               // Check to see if the world state is already in the open list.
               for(oli = mOpenList.begin(); oli != mOpenList.end(); oli++)
               {
                  if(n.state == oli->state && n < *oli)
                  {
                     // We've found a more efficient way of getting here.
                     *oli = n;
                     // Reorder the heap.
                     make_heap(mOpenList.begin(), mOpenList.end(),
                        std::greater<IntermediateState>());

                     if(log) log->logEvent("Updating state %d to F=%f",
                        oli->ID, oli->G + oli->H);
                     break;
                  }
               }
               // No match found in open list.
               if(oli == mOpenList.end())
               {
                  // Add the new intermediate state to the open list.
                  mOpenList.push_back(n);
                  // Heapify open list.
                  push_heap(mOpenList.begin(), mOpenList.end(), std::greater<IntermediateState>());

                  if(log) log->logEvent("Pushing state %d via action \"%s\" onto open list with score F=%f.",
                     n.ID, (*it)->getName().c_str(), n.G + n.H);
               }
            }
         }
      }
      else
         return false;

      return true;
   }
};
<commit_msg>Added more log events.<commit_after>/// @file AesopPlanner.cpp
/// @brief Implementation of Planner class as defined in Aesop.h

#include "Aesop.h"

#include <functional>
#include <algorithm>
#include <vector>

namespace ae {
   /// @class Planner
   ///
   /// A Planner object actually performs plan queries on the world state.
   /// It represents an entire planning state, with its own start and end
   /// states and plan-specific data.
   /// This will include, among other things, a set of vetoed Actions (for
   /// example, Actions that we tried but failed in practis, and we now
   /// want to exclude from our planning process temporarily).

   Planner::Planner(const WorldState *start, const WorldState *goal, const ActionSet *set)
   {
      setStart(start);
      setGoal(goal);
      setActions(set);
      mPlanning = false;
      mId = 0;
   }

   Planner::Planner()
   {
      Planner(NULL, NULL, NULL);
   }

   Planner::~Planner()
   {
   }

   void Planner::setStart(const WorldState *start)
   {
      mStart = start;
   }

   void Planner::setGoal(const WorldState *goal)
   {
      mGoal = goal;
   }

   void Planner::setActions(const ActionSet *set)
   {
      mActions = set;
   }

   bool Planner::isPlanning() const
   {
      return mPlanning;
   }

   const Plan& Planner::getPlan() const
   {
      return mPlan;
   }

   /// This method is actually just a wrapper for a series of calls to the
   /// sliced planning methods.
   bool Planner::plan(AesopLogger *log)
   {
      // Try to start planning.
      if(!initSlicedPlan(log))
         return false;

      while(isPlanning())
      {
         // Increment plan and capture failure.
         if(!updateSlicedPlan(log))
            return false;
         // If planning has halted, we must have been successful.
         if(!isPlanning())
         {
            finaliseSlicedPlan(log);
            return true;
         }
      }

      // No plan found.
      return false;
   }

   bool Planner::initSlicedPlan(AesopLogger *log)
   {
      // Validate pointers.
      if(!mStart || !mGoal || !mActions)
      {
         if(log) log->logEvent("Planning failed due to unset start, goal or action set!");
         return false;
      }

      if(log) log->logEvent("Starting new plan.");

      // Reset intermediate data.
      mPlanning = true;
      mOpenList.clear();
      mClosedList.clear();
      mId = 0;

      if(log) log->logEvent("Pushing starting state onto open list.");

      // Push initial state onto the open list.
      mOpenList.push_back(IntermediateState(mId)); mId++;
      mOpenList.back().state = *mGoal;

      return true;
   }

   void Planner::finaliseSlicedPlan(AesopLogger *log)
   {
      if(log) log->logEvent("Finalising plan!");
      // Work backwards up the closed list to get the final plan.
      mPlan.clear();
      unsigned int i = mClosedList.size() - 1;
      while(i)
      {
         // Extract the Action performed at this step.
         mPlan.push_back(mClosedList[i].ac);
         // Iterate.
         i = mClosedList[i].prev;
      }
      // Purge intermediate results.
      mOpenList.clear();
      mClosedList.clear();
      mPlanning = false;
   }

   bool Planner::updateSlicedPlan(AesopLogger *log)
   {
      // Main loop of A* search.
      if(!mOpenList.empty())
      {
         // Remove best IntermediateState from open list.
         pop_heap(mOpenList.begin(), mOpenList.end(), std::greater<IntermediateState>());
         IntermediateState s = mOpenList.back();
         mOpenList.pop_back();

         if(log) log->logEvent("Moving state %d from open to closed.", s.ID);

         // Add to closed list.
         mClosedList.push_back(s);

         // Check for completeness.
         if(s.state == *mStart)
         {
            mPlanning = false;
            return true;
         }

         // Find all actions we can use that may result in the current state.
         ActionSet::const_iterator it;
         for(it = mActions->begin(); it != mActions->end(); it++)
         {
            if(*it && s.state.actionPostMatch(*it))
            {
               IntermediateState n(mId); mId++;
               // Copy the current state, then apply the Action to it in
               // reverse to get the previous state.
               n.state = s.state;
               n.state.applyActionReverse(*it);

               closedlist::const_iterator cli;
               // Check to see if the world state is in the closed list.
               bool found = false;
               for(cli = mClosedList.begin(); cli != mClosedList.end(); cli++)
               {
                  if(n.state == cli->state)
                  {
                     found = true;
                     break;
                  }
               }
               if(found)
                  continue;

               // H (heuristic) cost is the estimated number of Actions to get
               // from new state to start.
               n.H = (float)WorldState::comp(n.state, *mStart);
               // G cost is the total weight of all Actions we've taken to get
               // to this state. By default, the cost of an Action is 1.
               n.G = s.G + (*it)->getCost();
               // Save this to avoid recalculating every time.
               n.F = n.G + n.H;
               // Remember Action we used to to this state.
               n.ac = *it;
               // Predecessor is the last state to be added to the closed list.
               n.prev = mClosedList.size() - 1;

               openlist::iterator oli;
               // Check to see if the world state is already in the open list.
               for(oli = mOpenList.begin(); oli != mOpenList.end(); oli++)
               {
                  if(n.state == oli->state && n < *oli)
                  {
                     // We've found a more efficient way of getting here.
                     *oli = n;
                     // Reorder the heap.
                     make_heap(mOpenList.begin(), mOpenList.end(),
                        std::greater<IntermediateState>());

                     if(log) log->logEvent("Updating state %d to F=%f",
                        oli->ID, oli->G + oli->H);
                     break;
                  }
               }
               // No match found in open list.
               if(oli == mOpenList.end())
               {
                  // Add the new intermediate state to the open list.
                  mOpenList.push_back(n);
                  // Heapify open list.
                  push_heap(mOpenList.begin(), mOpenList.end(), std::greater<IntermediateState>());

                  if(log) log->logEvent("Pushing state %d via action \"%s\" onto open list with score F=%f.",
                     n.ID, (*it)->getName().c_str(), n.G + n.H);
               }
            }
         }
      }
      else
         return false;

      return true;
   }
};
<|endoftext|>


<commit_before>#include <boost/format.hpp>
#include <cinttypes>
#include <regex>

#include "dccbot.h"
#include "dccreceivetask.h"
#include "ircmessage.h"

xdccd::DCCAnnounce::DCCAnnounce(
        const std::string &bot,
        const std::string &filename,
        const std::string &size,
        const std::string &slot,
        const std::string &download_count)
    : hash(bot+slot), bot(bot), filename(filename), size(size), slot(slot), download_count(download_count)
{}

bool xdccd::DCCAnnounce::compare(const std::string &other) const
{
    return boost::algorithm::icontains(filename, other);
}

xdccd::DCCBot::DCCBot(bot_id_t id, ThreadpoolPtr threadpool, const std::string &host, const std::string &port, const std::string &nick, const std::vector<std::string> &channels, bool use_ssl)
    : id(id), last_file_id(0), nickname(nick), connection(host, port, ([this](const std::string &msg) { this->read_handler(msg); }), use_ssl),
    threadpool(threadpool), channels_to_join(channels)
{
    std::string result = boost::algorithm::join(channels, ", ");
    std::cout << "Started bot for '" << host << ":" << port << "', called '" << nick  << "', joining: " << result << std::endl;
    connection.write((boost::format("NICK %s") % nick).str());
    connection.write((boost::format("USER %s * * %s") % nick % nick).str());
}

xdccd::DCCBot::~DCCBot()
{
    std::cout << "Deleting bot '" << nickname << "'!" << std::endl;
}

void xdccd::DCCBot::read_handler(const std::string &message)
{
    xdccd::IRCMessage msg(message);

    if (msg.command == "PING")
    {
        connection.write("PONG " + msg.params[0]);
        return;
    }

    // 001 is the server's welcome message
    if (msg.command == "001")
    {
        on_connected();
        return;
    }

    // 366 is the end of a channel's name list
    if (msg.command == "366")
    {
        on_join(msg.params[1]);
        return;
    }

    if (msg.command == "PART" && msg.params[0] == nickname)
    {
        on_part(msg.params[1]);
        return;
    }

    if (msg.command == "PRIVMSG")
    {
        if (msg.ctcp)
        {
            on_ctcp(msg);
            return;
        }

        on_privmsg(msg);
    }
}

void xdccd::DCCBot::on_ctcp(const xdccd::IRCMessage &msg)
{
    std::cout << "CTCP-Message: " << msg.ctcp_command << " says: '" << msg.params[1] << "'" << std::endl;

    if (msg.ctcp_command == "DCC")
    {
        if (msg.ctcp_params[0] == "SEND")
        {
            bool active = true;
            std::string filename = msg.ctcp_params[1];
            std::string ip = msg.ctcp_params[2];
            std::string port = msg.ctcp_params[3];
            std::string size = msg.ctcp_params[4];

            // Check if we got an IPv6 or v4 address
            boost::asio::ip::address addr;
            if (ip.find(':') != std::string::npos)
            {
                boost::asio::ip::address_v6 tmp(boost::asio::ip::address_v6::from_string(ip));
                addr = boost::asio::ip::address(tmp);
            }
            else
            {
                unsigned long int_ip = std::stol(ip);
                boost::asio::ip::address_v4 tmp(int_ip);
                addr = boost::asio::ip::address(tmp);
            }

            // Other side wants to initiate passive DCC
            if (port == "0")
            {
                active = false;

                // We have to send a DCC SEND request back, containing our IP address
                // DCC SEND <filename> <ip> <port> <filesize> <token>
                connection.write((boost::format("PRIVMSG %s :" "\x01" "DCC SEND %s %s %s %s\x01")
                            % msg.nickname
                            % filename
                            % connection.get_local_ip()
                            % "12345"
                            % size).str());
            }

            std::cout << "DCC SEND request, offering file " << filename << " on ip " << addr.to_string() << ":" << port << std::endl;

            std::lock_guard<std::mutex> lock(files_lock);
            std::shared_ptr<DCCFile> file_ptr = nullptr;

            // Check if we are expecting the incoming file
            for(auto file : files)
                if (file->bot == msg.nickname && file->filename == filename && file->state == xdccd::FileState::AWAITING_CONNECTION)
                    file_ptr = file;

            // If not, add it anyway and wait for user interaction
            if (file_ptr == nullptr)
            {
                file_ptr = std::make_shared<DCCFile>(last_file_id++, msg.nickname, addr.to_string(), port, filename, std::strtoumax(size.c_str(), nullptr, 10));
                file_ptr->state = xdccd::FileState::AWAITING_RESPONSE;
                files.push_back(file_ptr);
            }

            threadpool->run_task(DCCReceiveTask(file_ptr, active));
        }
    }
}

void xdccd::DCCBot::run()
{
    connection.run();
}

void xdccd::DCCBot::stop()
{
    std::cout << "Disconnecting bot '" << nickname << "'!" << std::endl;
    connection.close();
}

void xdccd::DCCBot::on_connected()
{
    std::cout << "Connected!" << std::endl;

    for (auto channel_name : channels_to_join)
        connection.write("JOIN " + channel_name);

    channels_to_join.clear();
}

void xdccd::DCCBot::on_join(const std::string &channel)
{
    std::cout << "Joined channel " << channel << std::endl;
    channels.push_back(channel);
}

void xdccd::DCCBot::on_part(const std::string &channel)
{
    std::remove_if(channels.begin(), channels.end(), [channel](const std::string &name) { return name == channel; });
}

void xdccd::DCCBot::on_privmsg(const xdccd::IRCMessage &msg)
{
    static std::regex announce("#(\\d{1,3})\\s+(\\d+)x\\s+\\[\\s?(\\d+(?:\\.\\d+)?M|G)\\] (.*)", std::regex_constants::ECMAScript);

    std::smatch m;
    if (!std::regex_match(msg.params[1], m, announce))
        return;

    if (!m.empty() && m.size() == 5)
    {
        std::vector<std::string> result;
        for (std::size_t i = 1; i < m.size(); ++i)
            result.push_back(m[i].str());

        add_announce(msg.nickname, result[3], result[2], result[0], result[1]);
    }
}

void xdccd::DCCBot::request_file(const std::string &nick, const std::string &slot)
{
    connection.write((boost::format("PRIVMSG %s :xdcc send #%s") % nick % slot).str());

}

const std::vector<std::string> &xdccd::DCCBot::get_channels() const
{
    return channels;
}

const std::string &xdccd::DCCBot::get_nickname() const
{
    return nickname;
}

const std::string &xdccd::DCCBot::get_host() const
{
    return connection.get_host();
}

const std::string &xdccd::DCCBot::get_port() const
{
    return connection.get_port();
}

void xdccd::DCCBot::add_announce(const std::string &bot, const std::string &filename, const std::string &size, const std::string &slot, const std::string &download_count)
{
    DCCAnnouncePtr announce = std::make_shared<DCCAnnounce>(bot, filename, size, slot, download_count);
    announces[announce->hash] = announce;

    /*std::cout << "[Bot Announce] Bot: " << bot
        << ", File: " << filename
        << ", Size: " << size
        << " in slot #" << slot
        << ", downloaded " << download_count
        << " times (size: " << sizeof(*announce)
        << "b, total size ~ " << sizeof(*announce) * announces.size() + sizeof(announces)
        << "b, announces: " << announces.size()
        << ")" << std::endl;
        */
}

xdccd::DCCAnnouncePtr xdccd::DCCBot::get_announce(const std::string &hash) const
{
    auto it = announces.find(hash);

    if (it == announces.end())
        return nullptr;

    return it->second;
}

void xdccd::DCCBot::find_announces(const std::string &query, std::vector<DCCAnnouncePtr> &result) const
{
    for (auto announce : announces)
    {
        if (announce.second->compare(query))
            result.push_back(announce.second);
    }
}

const std::vector<xdccd::DCCFilePtr> &xdccd::DCCBot::get_files() const
{
    return files;
}

const std::map<std::string, xdccd::DCCAnnouncePtr> &xdccd::DCCBot::get_announces() const
{
    return announces;
}

xdccd::bot_id_t xdccd::DCCBot::get_id() const
{
    return id;
}
<commit_msg>Preadd files when requesting a download we know<commit_after>#include <boost/format.hpp>
#include <cinttypes>
#include <regex>

#include "dccbot.h"
#include "dccreceivetask.h"
#include "ircmessage.h"

xdccd::DCCAnnounce::DCCAnnounce(
        const std::string &bot,
        const std::string &filename,
        const std::string &size,
        const std::string &slot,
        const std::string &download_count)
    : hash(bot+slot), bot(bot), filename(filename), size(size), slot(slot), download_count(download_count)
{}

bool xdccd::DCCAnnounce::compare(const std::string &other) const
{
    return boost::algorithm::icontains(filename, other);
}

xdccd::DCCBot::DCCBot(bot_id_t id, ThreadpoolPtr threadpool, const std::string &host, const std::string &port, const std::string &nick, const std::vector<std::string> &channels, bool use_ssl)
    : id(id), last_file_id(0), nickname(nick), connection(host, port, ([this](const std::string &msg) { this->read_handler(msg); }), use_ssl),
    threadpool(threadpool), channels_to_join(channels)
{
    std::string result = boost::algorithm::join(channels, ", ");
    std::cout << "Started bot for '" << host << ":" << port << "', called '" << nick  << "', joining: " << result << std::endl;
    connection.write((boost::format("NICK %s") % nick).str());
    connection.write((boost::format("USER %s * * %s") % nick % nick).str());
}

xdccd::DCCBot::~DCCBot()
{
    std::cout << "Deleting bot '" << nickname << "'!" << std::endl;
}

void xdccd::DCCBot::read_handler(const std::string &message)
{
    xdccd::IRCMessage msg(message);

    if (msg.command == "PING")
    {
        connection.write("PONG " + msg.params[0]);
        return;
    }

    // 001 is the server's welcome message
    if (msg.command == "001")
    {
        on_connected();
        return;
    }

    // 366 is the end of a channel's name list
    if (msg.command == "366")
    {
        on_join(msg.params[1]);
        return;
    }

    if (msg.command == "PART" && msg.params[0] == nickname)
    {
        on_part(msg.params[1]);
        return;
    }

    if (msg.command == "PRIVMSG")
    {
        if (msg.ctcp)
        {
            on_ctcp(msg);
            return;
        }

        on_privmsg(msg);
    }
}

void xdccd::DCCBot::on_ctcp(const xdccd::IRCMessage &msg)
{
    std::cout << "CTCP-Message: " << msg.ctcp_command << " says: '" << msg.params[1] << "'" << std::endl;

    if (msg.ctcp_command == "DCC")
    {
        if (msg.ctcp_params[0] == "SEND")
        {
            bool active = true;
            std::string filename = msg.ctcp_params[1];
            std::string ip = msg.ctcp_params[2];
            std::string port = msg.ctcp_params[3];
            std::string size = msg.ctcp_params[4];

            // Check if we got an IPv6 or v4 address
            boost::asio::ip::address addr;
            if (ip.find(':') != std::string::npos)
            {
                boost::asio::ip::address_v6 tmp(boost::asio::ip::address_v6::from_string(ip));
                addr = boost::asio::ip::address(tmp);
            }
            else
            {
                unsigned long int_ip = std::stol(ip);
                boost::asio::ip::address_v4 tmp(int_ip);
                addr = boost::asio::ip::address(tmp);
            }

            // Other side wants to initiate passive DCC
            if (port == "0")
            {
                active = false;

                // We have to send a DCC SEND request back, containing our IP address
                // DCC SEND <filename> <ip> <port> <filesize> <token>
                connection.write((boost::format("PRIVMSG %s :" "\x01" "DCC SEND %s %s %s %s\x01")
                            % msg.nickname
                            % filename
                            % connection.get_local_ip()
                            % "12345"
                            % size).str());
            }

            std::cout << "DCC SEND request, offering file " << filename << " on ip " << addr.to_string() << ":" << port << std::endl;

            std::lock_guard<std::mutex> lock(files_lock);
            std::shared_ptr<DCCFile> file_ptr = nullptr;

            // Check if we are expecting the incoming file
            for(auto file : files)
                if (file->bot == msg.nickname && file->filename == filename && file->state == xdccd::FileState::AWAITING_CONNECTION)
                {
                    file_ptr = file;
                    file_ptr->ip = addr.to_string();
                    file_ptr->port = port;
                    file_ptr->size = std::strtoumax(size.c_str(), nullptr, 10);
                    break;
                }

            // If not, add it anyway and wait for user interaction
            if (file_ptr == nullptr)
            {
                file_ptr = std::make_shared<DCCFile>(last_file_id++, msg.nickname, addr.to_string(), port, filename, std::strtoumax(size.c_str(), nullptr, 10));
                file_ptr->state = xdccd::FileState::AWAITING_RESPONSE;
                files.push_back(file_ptr);
            }

            threadpool->run_task(DCCReceiveTask(file_ptr, active));
        }
    }
}

void xdccd::DCCBot::run()
{
    connection.run();
}

void xdccd::DCCBot::stop()
{
    std::cout << "Disconnecting bot '" << nickname << "'!" << std::endl;
    connection.close();
}

void xdccd::DCCBot::on_connected()
{
    std::cout << "Connected!" << std::endl;

    for (auto channel_name : channels_to_join)
        connection.write("JOIN " + channel_name);

    channels_to_join.clear();
}

void xdccd::DCCBot::on_join(const std::string &channel)
{
    std::cout << "Joined channel " << channel << std::endl;
    channels.push_back(channel);
}

void xdccd::DCCBot::on_part(const std::string &channel)
{
    std::remove_if(channels.begin(), channels.end(), [channel](const std::string &name) { return name == channel; });
}

void xdccd::DCCBot::on_privmsg(const xdccd::IRCMessage &msg)
{
    static std::regex announce("#(\\d{1,3})\\s+(\\d+)x\\s+\\[\\s?(\\d+(?:\\.\\d+)?M|G)\\] (.*)", std::regex_constants::ECMAScript);

    std::smatch m;
    if (!std::regex_match(msg.params[1], m, announce))
        return;

    if (!m.empty() && m.size() == 5)
    {
        std::vector<std::string> result;
        for (std::size_t i = 1; i < m.size(); ++i)
            result.push_back(m[i].str());

        add_announce(msg.nickname, result[3], result[2], result[0], result[1]);
    }
}

void xdccd::DCCBot::request_file(const std::string &nick, const std::string &slot)
{
    connection.write((boost::format("PRIVMSG %s :xdcc send #%s") % nick % slot).str());

    // Check if we already discovered the file the user wants to download
    DCCAnnouncePtr announce = get_announce(nick + slot);

    if (!announce)
        return;

    // Yes, we have it, let's create the DCCFile for it now
    DCCFilePtr file_ptr = std::make_shared<DCCFile>(last_file_id++, nick, "", "", announce->filename, 0);
}

const std::vector<std::string> &xdccd::DCCBot::get_channels() const
{
    return channels;
}

const std::string &xdccd::DCCBot::get_nickname() const
{
    return nickname;
}

const std::string &xdccd::DCCBot::get_host() const
{
    return connection.get_host();
}

const std::string &xdccd::DCCBot::get_port() const
{
    return connection.get_port();
}

void xdccd::DCCBot::add_announce(const std::string &bot, const std::string &filename, const std::string &size, const std::string &slot, const std::string &download_count)
{
    DCCAnnouncePtr announce = std::make_shared<DCCAnnounce>(bot, filename, size, slot, download_count);
    announces[announce->hash] = announce;

    /*std::cout << "[Bot Announce] Bot: " << bot
        << ", File: " << filename
        << ", Size: " << size
        << " in slot #" << slot
        << ", downloaded " << download_count
        << " times (size: " << sizeof(*announce)
        << "b, total size ~ " << sizeof(*announce) * announces.size() + sizeof(announces)
        << "b, announces: " << announces.size()
        << ")" << std::endl;
        */
}

xdccd::DCCAnnouncePtr xdccd::DCCBot::get_announce(const std::string &hash) const
{
    auto it = announces.find(hash);

    if (it == announces.end())
        return nullptr;

    return it->second;
}

void xdccd::DCCBot::find_announces(const std::string &query, std::vector<DCCAnnouncePtr> &result) const
{
    for (auto announce : announces)
    {
        if (announce.second->compare(query))
            result.push_back(announce.second);
    }
}

const std::vector<xdccd::DCCFilePtr> &xdccd::DCCBot::get_files() const
{
    return files;
}

const std::map<std::string, xdccd::DCCAnnouncePtr> &xdccd::DCCBot::get_announces() const
{
    return announces;
}

xdccd::bot_id_t xdccd::DCCBot::get_id() const
{
    return id;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

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

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

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

*/

#ifndef TORRENT_UTP_SOCKET_MANAGER_HPP_INCLUDED
#define TORRENT_UTP_SOCKET_MANAGER_HPP_INCLUDED

#include <boost/shared_ptr.hpp>
#include <map>

namespace
{
	struct udp_socket;
	struct utp_stream;

	typedef void (*incoming_utp_fun)(void*, boost::shared_ptr<utp_stream> const&);

	struct utp_socket_manager
	{
		utp_socket_manager(udp_socket& s, incoming_utp_fun cb, void* userdata);

		// return false if this is not a uTP packet
		bool incoming_packet(char const* p, int size);

		void tick();

		// internal, used by utp_stream
		void remove_socket(boost::uint16_t id);

	private:
		udp_socket& m_sock;
		// replace with a hash-map
		typedef std::map<boost::uint16_t, utp_stream*> socket_map_t;
		socket_map_t m_utp_sockets;

		void add_socket(boost::uint16_t id, utp_stream* s);
	};
}

#endif

<commit_msg>Added libtorrent namespace in utp_socket_manager.hpp.<commit_after>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

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

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

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

*/

#ifndef TORRENT_UTP_SOCKET_MANAGER_HPP_INCLUDED
#define TORRENT_UTP_SOCKET_MANAGER_HPP_INCLUDED

#include <boost/shared_ptr.hpp>
#include <map>

namespace libtorrent
{
	struct udp_socket;
	struct utp_stream;

	typedef void (*incoming_utp_fun)(void*, boost::shared_ptr<utp_stream> const&);

	struct utp_socket_manager
	{
		utp_socket_manager(udp_socket& s, incoming_utp_fun cb, void* userdata);

		// return false if this is not a uTP packet
		bool incoming_packet(char const* p, int size);

		void tick();

		// internal, used by utp_stream
		void remove_socket(boost::uint16_t id);

	private:
		udp_socket& m_sock;
		// replace with a hash-map
		typedef std::map<boost::uint16_t, utp_stream*> socket_map_t;
		socket_map_t m_utp_sockets;

		void add_socket(boost::uint16_t id, utp_stream* s);
	};
}

#endif

<|endoftext|>