<commit_before>/* $Id: Node.C,v 1.14 1999-08-27 15:21:59 wilson Exp $ */
/* File sections:
 * Service: constructors, destructors
 * Chain: functions directly related to the building and analysis of chains
 * Solution: functions directly related to the solution of a (sub)problem
 * Utility: advanced member access such as searching and counting
 * List: maintenance of lists or arrays of objects
 */

#include "Node.h"

#include "DataLib/DataLib.h"

#include "truncate.h"

#include "Util/Statistics.h"

/****************************
 ********* Service **********
 ***************************/

DataCache Node::lambdaCache;
DataCache Node::heatCache;
DataCache Node::alphaCache;
DataCache Node::betaCache;
DataCache Node::gammaCache;
DataCache Node::wdrCache;

Node::Node(char *isoName)
{
  debug(4,"Making new Node: %s.",isoName);

  kza = 0;
  if (isoName != NULL)
    {
      char cpyName[8], sym[5];
      strcpy(cpyName,isoName);

      char *strPtr = strchr(cpyName,'-');

      int A = atoi(strPtr+1);
      *strPtr = '\0';

      sprintf(sym," %s ",cpyName);

      debug(5,"Set A= %d and searching for symbol '%s'",A,sym);

      int Z = (strstr(SYMBOLS,sym)-SYMBOLS)/3 + 1;

      kza = (Z*1000+A)*10;
    }
}

Node::Node(int nextKza, Node* passedPrev, double* passedSingle,
	   int passedRank, int passedState)
  : TreeInfo(passedPrev,passedRank,passedState),
    kza(nextKza)
{

  int gNum;

  switch(mode)
    {
    case MODE_FORWARD:
      single = new double[nGroups+1];
      memCheck(single,"Node::Node(...) constructor: single");
      for (gNum=0;gNum<=nGroups;gNum++)
	single[gNum] = passedSingle[gNum];
      P = single;
      break;
    case MODE_REVERSE:
      prev->P = passedSingle;
      break;
    }

}

/****************************
 ********** Chain ***********
 ***************************/

/* function to read nuclear data from arbitrary data source */
/* called by Chain::build() */
void Node::readData()
{
  dataLib->readData(kza,this);

  switch(mode)
    {
    case MODE_FORWARD:
      /* this is only true for forward mode */
      /* if a new node is created with TRUNCATE_STABLE state
       * strip its pure transmutation reactions immediately */
      if (state == TRUNCATE_STABLE)
	state = stripNonDecay();
      break;
    case MODE_REVERSE:
      if (single != NULL)
	D = single;
      else
	D = prev->P;
      break;
    }
}

double Node::getLambda(int setKza)
{
  if (lambdaCache.count(setKza))
    return lambdaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      lambdaCache[kza] = D[nGroups];
      return D[nGroups];
    }
  else
    return 0;
}

double Node::getHeat(int setKza)
{
  if (heatCache.count(setKza))
    return heatCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      heatCache[kza] = D[nGroups] * (E[0]+E[1]+E[2]);
      return D[nGroups] * (E[0]+E[1]+E[2]);
    }
  else
    return 0;
}

double Node::getAlpha(int setKza)
{
  if (alphaCache.count(setKza))
    return alphaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      alphaCache[kza] = D[nGroups] * E[0];
      return D[nGroups] * E[0];
    }
  else
    return 0;
}

double Node::getBeta(int setKza)
{
  if (betaCache.count(setKza))
    return betaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      betaCache[kza] = D[nGroups] * E[1];
      return D[nGroups] * E[1];
    }
  else
    return 0;
}

double Node::getGamma(int setKza)
{
  if (gammaCache.count(setKza))
    return gammaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      gammaCache[kza] = D[nGroups] * E[2];
      return D[nGroups] * E[2];
    }
  else
    return 0;
}

double Node::getWDR(int setKza)
{
  if (wdrCache.count(setKza))
    return wdrCache[setKza];
  else
    return 0;
}

void Node::loadWDR(char *fname)
{

  int tmpKza, A, Z, mode;
  char isoName[16], sym[5], *strPtr, isoFlag;
  double wdr;
  Node dataAccess;
  ifstream wdrFile(fname,ios::in);

  wdrCache.erase(wdrCache.begin(),wdrCache.end());

  wdrFile >> isoName >> wdr;

  if (isdigit(isoName[0]))
    mode = WDR_KZAMODE;
  else
    mode = WDR_SYMMODE;

  while (!wdrFile.eof())
    {
      if (mode == WDR_SYMMODE)
	{
	  for (strPtr=isoName;strPtr;strPtr++)
	    *strPtr = tolower(*strPtr);
	  strPtr = strchr(isoName,'-');
	  *strPtr = '\0';

	  sprintf(sym," %s ",isoName);

	  Z = (strstr(SYMBOLS,sym)-SYMBOLS)/3 + 1;
	  sscanf(strPtr+1,"%d%c",&A,&isoFlag);
	  tmpKza = (Z*1000+A)*10;
	  if (isalpha(isoFlag))
	    tmpKza += isoFlag - 'l';
	}
      else
	tmpKza = atio(isoName);

      wdrCache[tmpKza] = dataAccess.getLambda(tmpKza)/wdr;
      wdrFile >> isoName >> wdr;
    }

  wdrFile.close();

}

/* function to copy pointers to the chain data */
/* called by Chain::build() */
void Node::copyRates(double **rates, const int step, int *loopRank)
{

  if (D == NULL)
    {
      rates[rank+step] = NULL;
      rates[rank+3*step] = NULL;
    }
  else
    {
      rates[rank+step] = D;
      rates[rank+3*step] = rates[rank+step]+nGroups;
    }

  /* in reverse mode, we have to set the daughter's P rate
   * and not this parent's */
  int idx = rank;
  double *setP = P;
  if (mode == MODE_REVERSE && idx > 0)
    {
      idx = rank-1;
      setP = prev->P;
    }

  if (setP == NULL)
    {
      rates[idx] = NULL;
      rates[idx+2*step] = NULL;
    }
  else
    {
      rates[idx] = setP;
      rates[idx+2*step] = rates[idx]+nGroups;
    }

  /* find loop rank and assume that this node has no loop */
  int foundLoop = findLoop();
  loopRank[rank] = -1;

  /* find natural loop with current isotope */
  switch(mode)
    {
    case MODE_FORWARD:
      {
	/* if there is a natural loop */
	if (foundLoop>-1)
	  loopRank[rank] = rank - foundLoop;

	/* check for internal loop */
	if (rank > 0 && loopRank[rank-1] > -1
	    && (loopRank[rank] > loopRank[rank-1]+1 || loopRank[rank] == -1))
	  loopRank[rank] = loopRank[rank-1] + 1;

	break;
      }
    case MODE_REVERSE:
      {

	/* if there is a natural loop */
	if (foundLoop>-1)
	  {
	    loopRank[foundLoop] = rank - foundLoop;

	    /* check for internal loop */
	    if (loopRank[foundLoop] > loopRank[foundLoop+1]+1)
	      loopRank[foundLoop] = loopRank[foundLoop+1]+1;
	  }

	/* propagate that loop to other chain members */
	while (--foundLoop >= 0)
	  if (loopRank[foundLoop] == -1)
	    loopRank[foundLoop] = loopRank[foundLoop+1]+1;

	break;
      }
    }

}

/* re-initialize elements when the chain retracts */
void Node::delRates(double **rates, const int step, int *loopRank)
{
  int idx;

  rates[rank] = NULL;
  rates[rank+step] = NULL;
  rates[rank+2*step] = NULL;
  rates[rank+3*step] = NULL;
  switch(mode)
    {
    case MODE_FORWARD:
      /* simply reset this value */
      loopRank[rank] = -1;
      break;
    case MODE_REVERSE:
      /* reset this value */
      loopRank[rank] = -1;
      idx = rank;
      while (--idx >= 0)
	if (loopRank[idx]+idx >= rank)
	  loopRank[idx] = -1;
      break;
    }
}

/* function to determine state of tree building process.

 * This function is called twice from Chain::build(...).  The first
 * time is only for new isotopes which, by logic, must be in state
 * CONTINUE or TRUNCATE_STABLE.  This is when the argument is used.
 * The subsequent call is used to determine the action of the
 * Chain::build(...) function.  The arguments defaults to 0 and the
 * state upon entering the function could be one of many.
 */

/* called by Chain::build() */
int Node::stateEngine(int stateBits)
{

  /* if we are doing an initial truncation state analysis */
  if (stateBits>-1)
    {
      switch(state)
	{
	case CONTINUE:
	  if (stateBits == IGNORE)
	    state = IGNORE;
	  else if (stateBits >= TRUNCATE_STABLE && mode == MODE_FORWARD)
	    state = stripNonDecay();
	  else if (nPaths == 0 || stateBits >= TRUNCATE)
	    state = TRUNCATE;
	  break;
	case TRUNCATE_STABLE:
	  if (stateBits == IGNORE)
	    state = IGNORE;
	  else
	    /* NOTE: this test is easier than case CONTINUE since:
	     * 1) stripNonDecay() is run during readData()
	     * 2) since this is a next of something in a form
	     *    of TRUNCATE state, this must also be in a form of
	     *    TRUNCATE state
	     * 3) there is no change of state if it is radioactive.
	     */
	    if (nPaths == 0 || stateBits > TRUNCATE)
	      state = TRUNCATE;
	  break;
	}
    }
  else
    /* chain building action analysis */
    switch(state)
      {
      case IGNORE:
	/* When we are ignoring the last next, we must change the
	 * prev's state back to truncate so that its chain will not be
	 * lost. */
	if (prev != NULL && prev->state == SOLVED)
	  prev->state = TRUNCATE;
	break;
      case TRUNCATE:
	/* During the initial call to the state engine for a new isotope
	 * the state can be set to TRUNCATE.  The state engine then starts
	 * with this state when determining the action for Chain::build(...).
	 * The appropriate action is to solve the chain.
	 */
	state = SOLVE;
	break;
      case SOLVE:
	/* This state is set when a chain is truncated.
	 *
	 * The appropriate action here is to initiate a retraction of the chain.
	 */
	state = SOLVED;
	/* if we just solved the root, set the terminal state */
	if (rank == 0)
	  state = FINISHED_ROOT;
	break;
      case SOLVED:
	/* if we just solved the root, set the terminal state */
	if (rank == 0)
	  state = FINISHED_ROOT;
	break;
      }

  return state;

}

/* function to add correct next product to chain */
/* called by Chain::build() */
Node* Node::addNext(int &setRank)
{

  Node *ptr = this;

  /* If there are more children, add them.  */
  if (pathNum < nPaths)
    {
      next = new Node(relations[pathNum],this,paths[pathNum],rank+1,state);
      memCheck(next,"Node::addNext(): next");
    }
  else
    /* NOTE: this function should never be called in a state where
     * above is not true.  */
    error(9000,"Programming error: trying to add too many relations in chain.");

  /* If this was the last next */
  if (++pathNum == nPaths)
    {
      /* This node will be solved and tallied with its last next */
      state = SOLVED;

      /* look back up chain for successive isotopes which are also on
       * their last next */
      while (ptr->prev != NULL && ptr->prev->state == SOLVED)
	ptr = ptr->prev;

      /* setRank indicates that all nodes after this one (ptr) should be
       * tallied at the next solution */
      setRank = ptr->rank;
    }
  else
    /* if not the last next, only the last/newest node should be
     * tallied */
    setRank = next->rank;

  /* return the newly created next node */
  return next;
}

/* delete everything below the current node */
void Node::prune()
{
  delete next;
  next = NULL;
};

/* Retract the chain by returning the prev
 * - usually followed by a call to prune() */
Node* Node::retract()
{
  return prev;
}

/* function to search up a chain for a loop */
int Node::findLoop()
{
  Node* nodePtr = prev;

  while (nodePtr != NULL)
    {
      if (nodePtr->kza == kza)
	return nodePtr->rank;
      nodePtr = nodePtr->prev;
    }

  return -1;
}

/* search down a chain for a certain rank */
int Node::getRankKza(int findRank)
{
  Node* ptr = this;

  while (findRank>ptr->rank && ptr->next != NULL)
    ptr = ptr->next;

  if (findRank == ptr->rank)
    return ptr->kza;
  else
    return -1;
}

<commit_msg>Bug: int atio(char*) does not exist, try int atoi(char*).<commit_after>/* $Id: Node.C,v 1.15 1999-08-27 15:26:20 wilson Exp $ */
/* File sections:
 * Service: constructors, destructors
 * Chain: functions directly related to the building and analysis of chains
 * Solution: functions directly related to the solution of a (sub)problem
 * Utility: advanced member access such as searching and counting
 * List: maintenance of lists or arrays of objects
 */

#include "Node.h"

#include "DataLib/DataLib.h"

#include "truncate.h"

#include "Util/Statistics.h"

/****************************
 ********* Service **********
 ***************************/

DataCache Node::lambdaCache;
DataCache Node::heatCache;
DataCache Node::alphaCache;
DataCache Node::betaCache;
DataCache Node::gammaCache;
DataCache Node::wdrCache;

Node::Node(char *isoName)
{
  debug(4,"Making new Node: %s.",isoName);

  kza = 0;
  if (isoName != NULL)
    {
      char cpyName[8], sym[5];
      strcpy(cpyName,isoName);

      char *strPtr = strchr(cpyName,'-');

      int A = atoi(strPtr+1);
      *strPtr = '\0';

      sprintf(sym," %s ",cpyName);

      debug(5,"Set A= %d and searching for symbol '%s'",A,sym);

      int Z = (strstr(SYMBOLS,sym)-SYMBOLS)/3 + 1;

      kza = (Z*1000+A)*10;
    }
}

Node::Node(int nextKza, Node* passedPrev, double* passedSingle,
	   int passedRank, int passedState)
  : TreeInfo(passedPrev,passedRank,passedState),
    kza(nextKza)
{

  int gNum;

  switch(mode)
    {
    case MODE_FORWARD:
      single = new double[nGroups+1];
      memCheck(single,"Node::Node(...) constructor: single");
      for (gNum=0;gNum<=nGroups;gNum++)
	single[gNum] = passedSingle[gNum];
      P = single;
      break;
    case MODE_REVERSE:
      prev->P = passedSingle;
      break;
    }

}

/****************************
 ********** Chain ***********
 ***************************/

/* function to read nuclear data from arbitrary data source */
/* called by Chain::build() */
void Node::readData()
{
  dataLib->readData(kza,this);

  switch(mode)
    {
    case MODE_FORWARD:
      /* this is only true for forward mode */
      /* if a new node is created with TRUNCATE_STABLE state
       * strip its pure transmutation reactions immediately */
      if (state == TRUNCATE_STABLE)
	state = stripNonDecay();
      break;
    case MODE_REVERSE:
      if (single != NULL)
	D = single;
      else
	D = prev->P;
      break;
    }
}

double Node::getLambda(int setKza)
{
  if (lambdaCache.count(setKza))
    return lambdaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      lambdaCache[kza] = D[nGroups];
      return D[nGroups];
    }
  else
    return 0;
}

double Node::getHeat(int setKza)
{
  if (heatCache.count(setKza))
    return heatCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      heatCache[kza] = D[nGroups] * (E[0]+E[1]+E[2]);
      return D[nGroups] * (E[0]+E[1]+E[2]);
    }
  else
    return 0;
}

double Node::getAlpha(int setKza)
{
  if (alphaCache.count(setKza))
    return alphaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      alphaCache[kza] = D[nGroups] * E[0];
      return D[nGroups] * E[0];
    }
  else
    return 0;
}

double Node::getBeta(int setKza)
{
  if (betaCache.count(setKza))
    return betaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      betaCache[kza] = D[nGroups] * E[1];
      return D[nGroups] * E[1];
    }
  else
    return 0;
}

double Node::getGamma(int setKza)
{
  if (gammaCache.count(setKza))
    return gammaCache[setKza];

  kza = setKza;
  readData();

  if (nPaths>0 && D[nGroups]>0)
    {
      gammaCache[kza] = D[nGroups] * E[2];
      return D[nGroups] * E[2];
    }
  else
    return 0;
}

double Node::getWDR(int setKza)
{
  if (wdrCache.count(setKza))
    return wdrCache[setKza];
  else
    return 0;
}

void Node::loadWDR(char *fname)
{

  int tmpKza, A, Z, mode;
  char isoName[16], sym[5], *strPtr, isoFlag;
  double wdr;
  Node dataAccess;
  ifstream wdrFile(fname,ios::in);

  wdrCache.erase(wdrCache.begin(),wdrCache.end());

  wdrFile >> isoName >> wdr;

  if (isdigit(isoName[0]))
    mode = WDR_KZAMODE;
  else
    mode = WDR_SYMMODE;

  while (!wdrFile.eof())
    {
      if (mode == WDR_SYMMODE)
	{
	  for (strPtr=isoName;strPtr;strPtr++)
	    *strPtr = tolower(*strPtr);
	  strPtr = strchr(isoName,'-');
	  *strPtr = '\0';

	  sprintf(sym," %s ",isoName);

	  Z = (strstr(SYMBOLS,sym)-SYMBOLS)/3 + 1;
	  sscanf(strPtr+1,"%d%c",&A,&isoFlag);
	  tmpKza = (Z*1000+A)*10;
	  if (isalpha(isoFlag))
	    tmpKza += isoFlag - 'l';
	}
      else
	tmpKza = atoi(isoName);

      wdrCache[tmpKza] = dataAccess.getLambda(tmpKza)/wdr;
      wdrFile >> isoName >> wdr;
    }

  wdrFile.close();

}

/* function to copy pointers to the chain data */
/* called by Chain::build() */
void Node::copyRates(double **rates, const int step, int *loopRank)
{

  if (D == NULL)
    {
      rates[rank+step] = NULL;
      rates[rank+3*step] = NULL;
    }
  else
    {
      rates[rank+step] = D;
      rates[rank+3*step] = rates[rank+step]+nGroups;
    }

  /* in reverse mode, we have to set the daughter's P rate
   * and not this parent's */
  int idx = rank;
  double *setP = P;
  if (mode == MODE_REVERSE && idx > 0)
    {
      idx = rank-1;
      setP = prev->P;
    }

  if (setP == NULL)
    {
      rates[idx] = NULL;
      rates[idx+2*step] = NULL;
    }
  else
    {
      rates[idx] = setP;
      rates[idx+2*step] = rates[idx]+nGroups;
    }

  /* find loop rank and assume that this node has no loop */
  int foundLoop = findLoop();
  loopRank[rank] = -1;

  /* find natural loop with current isotope */
  switch(mode)
    {
    case MODE_FORWARD:
      {
	/* if there is a natural loop */
	if (foundLoop>-1)
	  loopRank[rank] = rank - foundLoop;

	/* check for internal loop */
	if (rank > 0 && loopRank[rank-1] > -1
	    && (loopRank[rank] > loopRank[rank-1]+1 || loopRank[rank] == -1))
	  loopRank[rank] = loopRank[rank-1] + 1;

	break;
      }
    case MODE_REVERSE:
      {

	/* if there is a natural loop */
	if (foundLoop>-1)
	  {
	    loopRank[foundLoop] = rank - foundLoop;

	    /* check for internal loop */
	    if (loopRank[foundLoop] > loopRank[foundLoop+1]+1)
	      loopRank[foundLoop] = loopRank[foundLoop+1]+1;
	  }

	/* propagate that loop to other chain members */
	while (--foundLoop >= 0)
	  if (loopRank[foundLoop] == -1)
	    loopRank[foundLoop] = loopRank[foundLoop+1]+1;

	break;
      }
    }

}

/* re-initialize elements when the chain retracts */
void Node::delRates(double **rates, const int step, int *loopRank)
{
  int idx;

  rates[rank] = NULL;
  rates[rank+step] = NULL;
  rates[rank+2*step] = NULL;
  rates[rank+3*step] = NULL;
  switch(mode)
    {
    case MODE_FORWARD:
      /* simply reset this value */
      loopRank[rank] = -1;
      break;
    case MODE_REVERSE:
      /* reset this value */
      loopRank[rank] = -1;
      idx = rank;
      while (--idx >= 0)
	if (loopRank[idx]+idx >= rank)
	  loopRank[idx] = -1;
      break;
    }
}

/* function to determine state of tree building process.

 * This function is called twice from Chain::build(...).  The first
 * time is only for new isotopes which, by logic, must be in state
 * CONTINUE or TRUNCATE_STABLE.  This is when the argument is used.
 * The subsequent call is used to determine the action of the
 * Chain::build(...) function.  The arguments defaults to 0 and the
 * state upon entering the function could be one of many.
 */

/* called by Chain::build() */
int Node::stateEngine(int stateBits)
{

  /* if we are doing an initial truncation state analysis */
  if (stateBits>-1)
    {
      switch(state)
	{
	case CONTINUE:
	  if (stateBits == IGNORE)
	    state = IGNORE;
	  else if (stateBits >= TRUNCATE_STABLE && mode == MODE_FORWARD)
	    state = stripNonDecay();
	  else if (nPaths == 0 || stateBits >= TRUNCATE)
	    state = TRUNCATE;
	  break;
	case TRUNCATE_STABLE:
	  if (stateBits == IGNORE)
	    state = IGNORE;
	  else
	    /* NOTE: this test is easier than case CONTINUE since:
	     * 1) stripNonDecay() is run during readData()
	     * 2) since this is a next of something in a form
	     *    of TRUNCATE state, this must also be in a form of
	     *    TRUNCATE state
	     * 3) there is no change of state if it is radioactive.
	     */
	    if (nPaths == 0 || stateBits > TRUNCATE)
	      state = TRUNCATE;
	  break;
	}
    }
  else
    /* chain building action analysis */
    switch(state)
      {
      case IGNORE:
	/* When we are ignoring the last next, we must change the
	 * prev's state back to truncate so that its chain will not be
	 * lost. */
	if (prev != NULL && prev->state == SOLVED)
	  prev->state = TRUNCATE;
	break;
      case TRUNCATE:
	/* During the initial call to the state engine for a new isotope
	 * the state can be set to TRUNCATE.  The state engine then starts
	 * with this state when determining the action for Chain::build(...).
	 * The appropriate action is to solve the chain.
	 */
	state = SOLVE;
	break;
      case SOLVE:
	/* This state is set when a chain is truncated.
	 *
	 * The appropriate action here is to initiate a retraction of the chain.
	 */
	state = SOLVED;
	/* if we just solved the root, set the terminal state */
	if (rank == 0)
	  state = FINISHED_ROOT;
	break;
      case SOLVED:
	/* if we just solved the root, set the terminal state */
	if (rank == 0)
	  state = FINISHED_ROOT;
	break;
      }

  return state;

}

/* function to add correct next product to chain */
/* called by Chain::build() */
Node* Node::addNext(int &setRank)
{

  Node *ptr = this;

  /* If there are more children, add them.  */
  if (pathNum < nPaths)
    {
      next = new Node(relations[pathNum],this,paths[pathNum],rank+1,state);
      memCheck(next,"Node::addNext(): next");
    }
  else
    /* NOTE: this function should never be called in a state where
     * above is not true.  */
    error(9000,"Programming error: trying to add too many relations in chain.");

  /* If this was the last next */
  if (++pathNum == nPaths)
    {
      /* This node will be solved and tallied with its last next */
      state = SOLVED;

      /* look back up chain for successive isotopes which are also on
       * their last next */
      while (ptr->prev != NULL && ptr->prev->state == SOLVED)
	ptr = ptr->prev;

      /* setRank indicates that all nodes after this one (ptr) should be
       * tallied at the next solution */
      setRank = ptr->rank;
    }
  else
    /* if not the last next, only the last/newest node should be
     * tallied */
    setRank = next->rank;

  /* return the newly created next node */
  return next;
}

/* delete everything below the current node */
void Node::prune()
{
  delete next;
  next = NULL;
};

/* Retract the chain by returning the prev
 * - usually followed by a call to prune() */
Node* Node::retract()
{
  return prev;
}

/* function to search up a chain for a loop */
int Node::findLoop()
{
  Node* nodePtr = prev;

  while (nodePtr != NULL)
    {
      if (nodePtr->kza == kza)
	return nodePtr->rank;
      nodePtr = nodePtr->prev;
    }

  return -1;
}

/* search down a chain for a certain rank */
int Node::getRankKza(int findRank)
{
  Node* ptr = this;

  while (findRank>ptr->rank && ptr->next != NULL)
    ptr = ptr->next;

  if (findRank == ptr->rank)
    return ptr->kza;
  else
    return -1;
}

<|endoftext|>


<commit_before>// GPS Tracker project with Adafruit IO
// Author: Martin Spier

#include "Arduino_Tracker.h"

// Alarm pins
const int ledPin = LEAD_PIN;

// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = CHIP_SELECT;

// the logging file
File logfile;

// FONA instance & configuration
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);     // FONA software serial connection.
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);                 // FONA library connection.

uint8_t txFailures = 0;                                       // Count of how many publish failures have occured in a row.
uint8_t gpsFixFailures = 0;                                   // Count of how many GPS fix failures have occured in a row.
uint8_t gprsFailures = 0;                                     // Count of how many GPS fix failures have occured in a row.
uint8_t loopFailures = 0;                                     // Count of how many general failures have occured in a row.

float latitude, longitude, speed_kph, heading, altitude;
char currentTime[23];
uint16_t vbat;

// make a string for assembling the data to log:
char sendbuffer[96];

// Halt function called when an error occurs.  Will print an error and stop execution while
// doing a fast blink of the LED.  If the watchdog is enabled it will reset after 8 seconds.
void halt(const __FlashStringHelper *error) {
  Serial.println(error);
  Watchdog.enable(8000);
  Watchdog.reset();
  while (1) {
    digitalWrite(ledPin, LOW);
    delay(100);
    digitalWrite(ledPin, HIGH);
    delay(100);
  }
}

int8_t cellularConnect() {
  Watchdog.enable(8000);
  Watchdog.reset();

  // Getting out of sleep mode
  fonaSS.println("AT+CSCLK=0");

  // Wait for FONA to connect to cell network (up to 8 seconds, then watchdog reset).
  Serial.println(F("Checking for network..."));
  Watchdog.reset();
  while (fona.getNetworkStatus() != 1) {
    fonaSS.println("AT+CSCLK=0");
    delay(500);
  }

  // Disable GPRS
  Watchdog.reset();
  Serial.println(F("Disabling GPRS"));
  fona.enableGPRS(false);

  // Wait a little bit
  Watchdog.reset();
  delay(2000);

  // Start the GPRS data connection.
  Serial.println(F("Enabling GPRS"));
  Watchdog.disable();
  while (!fona.enableGPRS(true)) {
    Serial.println(F("Failed to turn GPRS on..."));
    gprsFailures++;

    // Reset everything if too many GPRS connect failures occured in a row.
    if (gprsFailures >= MAX_GPRS_FAILURES) {
      Serial.println(F("Failed to turn GPRS on, aborting..."));
      return -1;
    }
    Serial.println(F("Retrying GPRS in 10 seconds..."));

    delay(10000);  // wait 10 seconds
  }
  Serial.println(F("Connected to Cellular!"));

  return 0;
}

int8_t buildSendbuffer() {
  char *p = sendbuffer;

  // add date and time
  sprintf (p, "time=%s", currentTime);
  p += strlen(p);

  // concat latitude
  sprintf (p, "&lat=");
  p += strlen(p);
  dtostrf(latitude, 2, 6, p);
  p += strlen(p);

  // concat longitude
  sprintf (p, "&lon=");
  p += strlen(p);
  dtostrf(longitude, 3, 6, p);
  p += strlen(p);

  // add speed value
  sprintf (p, "&spd=");
  p += strlen(p);
  dtostrf(speed_kph, 2, 2, p);
  p += strlen(p);

  // concat altitude
  sprintf (p, "&alt=");
  p += strlen(p);
  dtostrf(altitude, 2, 2, p);
  p += strlen(p);

  // add vbat value
  sprintf (p, "&bat=%u", vbat);
  p += strlen(p);

  // null terminate
  p[0] = 0;

  Serial.println(sendbuffer);

  return 0;
}

int8_t httpLog() {
  uint16_t statuscode;
  int16_t length;
  char url[] = HTTP_POST_URL;

  if (!fona.HTTP_POST_start(url, F("text/plain"), (uint8_t *) sendbuffer, strlen(sendbuffer), &statuscode, (uint16_t *)&length)) {
    Serial.println("Failed!");
    return -1;
  }
  while (length > 0) {
    while (fona.available()) {
      char c = fona.read();

      #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
      loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
      UDR0 = c;
      #else
      Serial.write(c);
      #endif

      length--;
      if (!length) break;
    }
  }
  fona.HTTP_POST_end();

  return 0;
}

void sdLog() {
  // initialize the SD card
  Serial.println(F("Initializing SD card..."));

  // see if the card is present and can be initialized
  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present. Aborting."));
    // don't do anything else
    return;
  }

  Serial.println(F("SD card initialized."));

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  logfile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (logfile) {
    logfile.println(sendbuffer);
    logfile.close();
  } else { // if the file isn't open, pop up an error
    Serial.println(F("Error opening datalog.txt."));
  }

  return;
}

int8_t getGPSFix() {
  Serial.println(F("Trying to get a GPS fix... "));

  while (!fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude)) { // getGPS will return true for 3D fix
    Serial.println(F("Waiting for FONA GPS 3D fix..."));
    gpsFixFailures++;

    // Reset everything if too many GPS fix failures occured in a row.
    if (gpsFixFailures >= MAX_GPS_FIX_FAILURES) {
      Serial.println(F("Too many GPS fix failures, aborting..."));
      return -1;
    }
    Serial.println(F("Retrying GPS fix in 10 seconds..."));

    delay(10000);  // wait 10 seconds
  }
  Serial.println(F("FONA GPS 3D fix acquired!"));
  gpsFixFailures = 0;

  // Grab battery reading
  fona.getBattPercent(&vbat);

  // Grab time
  fona.getTime(currentTime, 23);

  return 0;
}

void setup() {

  // Initialize serial output.
  Serial.begin(115200);
  Serial.println(F("Adafruit IO & FONA808 Tracker"));

  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(chipSelect, OUTPUT);

  // Set alarm components
  pinMode(ledPin, OUTPUT);

  // Initialize the FONA module
  Serial.println(F("Initializing FONA....(may take 10 seconds)"));
  fonaSS.begin(4800);
  if (!fona.begin(fonaSS)) {
    halt(F("Couldn't find FONA"));
  }
  fonaSS.println("AT+CMEE=2");
  Serial.println(F("FONA is OK"));

  // Set GPRS network settings.
  fona.setGPRSNetworkSettings(F(FONA_APN));
  // fona.setGPRSNetworkSettings(F(FONA_APN), F(FONA_USERNAME), F(FONA_PASSWORD));

  if (!fona.enableNetworkTimeSync(true)) {
    Serial.println(F("Failed to enable network time sync."));
  }

  // Wait a little bit to make sure settings are in effect.
  delay(2000);
}

void loop() {
  // Use the watchdog to simplify retry logic and make things more robust.
  Watchdog.enable(8000);

  // Enable GPS
  Watchdog.reset();
  fona.enableGPS(true);

  // Wait a little bit to make sure GPS is enabled.
  Watchdog.reset();
  delay(5000);

  // Disabling watchdog
  Watchdog.disable();

  // Grab a GPS reading.
  if (!(getGPSFix() < 0)) {
    // Build Send Buffer
    buildSendbuffer();

    // Log to SD card
    sdLog();
    // Connect to cellular
    if (!(cellularConnect() < 0)) {
        httpLog();
        loopFailures = 0;
    } else {
      loopFailures++;
    }
  } else {
    loopFailures++;
  }

  // Use the watchdog to simplify retry logic and make things more robust.
  Watchdog.enable(8000);

  // Disable GPS.
  // TODO: Check if it was really disabled
  Watchdog.reset();
  fona.enableGPS(false);

  // Disable GPRS
  // TODO: Check if it was really disabled
  Watchdog.reset();
  fona.enableGPRS(false);

  // Put FONA in sleep module
  // TODO: Wait for Ok and retry
  Watchdog.reset();
  fonaSS.println("AT+CSCLK=1");

  // Disable Watchdog for delay
  Watchdog.disable();

  if (loopFailures >= MAX_LOOP_FAILURES) {
    halt(F("Too many failures, resetting..."));
  }

  // Wait 60 seconds
  delay(PUBLISH_INTERVAL * 60000);
}
<commit_msg>Fixing mime type.<commit_after>// GPS Tracker project with Adafruit IO
// Author: Martin Spier

#include "Arduino_Tracker.h"

// Alarm pins
const int ledPin = LEAD_PIN;

// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = CHIP_SELECT;

// the logging file
File logfile;

// FONA instance & configuration
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);     // FONA software serial connection.
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);                 // FONA library connection.

uint8_t txFailures = 0;                                       // Count of how many publish failures have occured in a row.
uint8_t gpsFixFailures = 0;                                   // Count of how many GPS fix failures have occured in a row.
uint8_t gprsFailures = 0;                                     // Count of how many GPS fix failures have occured in a row.
uint8_t loopFailures = 0;                                     // Count of how many general failures have occured in a row.

float latitude, longitude, speed_kph, heading, altitude;
char currentTime[23];
uint16_t vbat;

// make a string for assembling the data to log:
char sendbuffer[96];

// Halt function called when an error occurs.  Will print an error and stop execution while
// doing a fast blink of the LED.  If the watchdog is enabled it will reset after 8 seconds.
void halt(const __FlashStringHelper *error) {
  Serial.println(error);
  Watchdog.enable(8000);
  Watchdog.reset();
  while (1) {
    digitalWrite(ledPin, LOW);
    delay(100);
    digitalWrite(ledPin, HIGH);
    delay(100);
  }
}

int8_t cellularConnect() {
  Watchdog.enable(8000);
  Watchdog.reset();

  // Getting out of sleep mode
  fonaSS.println("AT+CSCLK=0");

  // Wait for FONA to connect to cell network (up to 8 seconds, then watchdog reset).
  Serial.println(F("Checking for network..."));
  Watchdog.reset();
  while (fona.getNetworkStatus() != 1) {
    fonaSS.println("AT+CSCLK=0");
    delay(500);
  }

  // Disable GPRS
  Watchdog.reset();
  Serial.println(F("Disabling GPRS"));
  fona.enableGPRS(false);

  // Wait a little bit
  Watchdog.reset();
  delay(2000);

  // Start the GPRS data connection.
  Serial.println(F("Enabling GPRS"));
  Watchdog.disable();
  while (!fona.enableGPRS(true)) {
    Serial.println(F("Failed to turn GPRS on..."));
    gprsFailures++;

    // Reset everything if too many GPRS connect failures occured in a row.
    if (gprsFailures >= MAX_GPRS_FAILURES) {
      Serial.println(F("Failed to turn GPRS on, aborting..."));
      return -1;
    }
    Serial.println(F("Retrying GPRS in 10 seconds..."));

    delay(10000);  // wait 10 seconds
  }
  Serial.println(F("Connected to Cellular!"));

  return 0;
}

int8_t buildSendbuffer() {
  char *p = sendbuffer;

  // add date and time
  sprintf (p, "time=%s", currentTime);
  p += strlen(p);

  // concat latitude
  sprintf (p, "&lat=");
  p += strlen(p);
  dtostrf(latitude, 2, 6, p);
  p += strlen(p);

  // concat longitude
  sprintf (p, "&lon=");
  p += strlen(p);
  dtostrf(longitude, 3, 6, p);
  p += strlen(p);

  // add speed value
  sprintf (p, "&spd=");
  p += strlen(p);
  dtostrf(speed_kph, 2, 2, p);
  p += strlen(p);

  // concat altitude
  sprintf (p, "&alt=");
  p += strlen(p);
  dtostrf(altitude, 2, 2, p);
  p += strlen(p);

  // add vbat value
  sprintf (p, "&bat=%u", vbat);
  p += strlen(p);

  // null terminate
  p[0] = 0;

  Serial.println(sendbuffer);

  return 0;
}

int8_t httpLog() {
  uint16_t statuscode;
  int16_t length;
  char url[] = HTTP_POST_URL;

  if (!fona.HTTP_POST_start(url, F("application/x-www-form-urlencoded"), (uint8_t *) sendbuffer, strlen(sendbuffer), &statuscode, (uint16_t *)&length)) {
    Serial.println("Failed!");
    return -1;
  }
  while (length > 0) {
    while (fona.available()) {
      char c = fona.read();

      #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
      loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
      UDR0 = c;
      #else
      Serial.write(c);
      #endif

      length--;
      if (!length) break;
    }
  }
  fona.HTTP_POST_end();

  return 0;
}

void sdLog() {
  // initialize the SD card
  Serial.println(F("Initializing SD card..."));

  // see if the card is present and can be initialized
  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present. Aborting."));
    // don't do anything else
    return;
  }

  Serial.println(F("SD card initialized."));

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  logfile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (logfile) {
    logfile.println(sendbuffer);
    logfile.close();
  } else { // if the file isn't open, pop up an error
    Serial.println(F("Error opening datalog.txt."));
  }

  return;
}

int8_t getGPSFix() {
  Serial.println(F("Trying to get a GPS fix... "));

  while (!fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude)) { // getGPS will return true for 3D fix
    Serial.println(F("Waiting for FONA GPS 3D fix..."));
    gpsFixFailures++;

    // Reset everything if too many GPS fix failures occured in a row.
    if (gpsFixFailures >= MAX_GPS_FIX_FAILURES) {
      Serial.println(F("Too many GPS fix failures, aborting..."));
      return -1;
    }
    Serial.println(F("Retrying GPS fix in 10 seconds..."));

    delay(10000);  // wait 10 seconds
  }
  Serial.println(F("FONA GPS 3D fix acquired!"));
  gpsFixFailures = 0;

  // Grab battery reading
  fona.getBattPercent(&vbat);

  // Grab time
  fona.getTime(currentTime, 23);

  return 0;
}

void setup() {

  // Initialize serial output.
  Serial.begin(115200);
  Serial.println(F("Adafruit IO & FONA808 Tracker"));

  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(chipSelect, OUTPUT);

  // Set alarm components
  pinMode(ledPin, OUTPUT);

  // Initialize the FONA module
  Serial.println(F("Initializing FONA....(may take 10 seconds)"));
  fonaSS.begin(4800);
  if (!fona.begin(fonaSS)) {
    halt(F("Couldn't find FONA"));
  }
  fonaSS.println("AT+CMEE=2");
  Serial.println(F("FONA is OK"));

  // Set GPRS network settings.
  fona.setGPRSNetworkSettings(F(FONA_APN));
  // fona.setGPRSNetworkSettings(F(FONA_APN), F(FONA_USERNAME), F(FONA_PASSWORD));

  if (!fona.enableNetworkTimeSync(true)) {
    Serial.println(F("Failed to enable network time sync."));
  }

  // Wait a little bit to make sure settings are in effect.
  delay(2000);
}

void loop() {
  // Use the watchdog to simplify retry logic and make things more robust.
  Watchdog.enable(8000);

  // Enable GPS
  Watchdog.reset();
  fona.enableGPS(true);

  // Wait a little bit to make sure GPS is enabled.
  Watchdog.reset();
  delay(5000);

  // Disabling watchdog
  Watchdog.disable();

  // Grab a GPS reading.
  if (!(getGPSFix() < 0)) {
    // Build Send Buffer
    buildSendbuffer();

    // Log to SD card
    sdLog();
    // Connect to cellular
    if (!(cellularConnect() < 0)) {
        httpLog();
        loopFailures = 0;
    } else {
      loopFailures++;
    }
  } else {
    loopFailures++;
  }

  // Use the watchdog to simplify retry logic and make things more robust.
  Watchdog.enable(8000);

  // Disable GPS.
  // TODO: Check if it was really disabled
  Watchdog.reset();
  fona.enableGPS(false);

  // Disable GPRS
  // TODO: Check if it was really disabled
  Watchdog.reset();
  fona.enableGPRS(false);

  // Put FONA in sleep module
  // TODO: Wait for Ok and retry
  Watchdog.reset();
  fonaSS.println("AT+CSCLK=1");

  // Disable Watchdog for delay
  Watchdog.disable();

  if (loopFailures >= MAX_LOOP_FAILURES) {
    halt(F("Too many failures, resetting..."));
  }

  // Wait 60 seconds
  delay(PUBLISH_INTERVAL * 60000);
}
<|endoftext|>


<commit_before>//------------------------------BLACKBOX DISCLAIMER-----------------------------
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
// Clientmenu.hh for Blackbox - an X11 Window manager
// Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
// Copyright (c) 1997 - 2000, 2002 - 2005
//         Bradley T Hughes <bhughes at trolltech.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//------------------------------BLACKBOX DISCLAIMER-----------------------------

#ifndef   __Clientmenu_hh
#define   __Clientmenu_hh

#include <Menu.hh>

class BScreen;

class Clientmenu : public bt::Menu {
public:
  Clientmenu(bt::Application &app, BScreen& screen, unsigned int workspace);

protected:
  virtual void itemClicked(unsigned int id, unsigned int button);

private:
  unsigned int _workspace;
  BScreen& _screen;
};

#endif // __Clientmenu_hh

<commit_msg>Update Clientmenu.hh<commit_after>

#ifndef   __Clientmenu_hh
#define   __Clientmenu_hh

#include <Menu.hh>

class BScreen;

class Clientmenu : public bt::Menu {
public:
  Clientmenu(bt::Application &app, BScreen& screen, unsigned int workspace);

protected:
  virtual void itemClicked(unsigned int id, unsigned int button);

private:
  unsigned int _workspace;
  BScreen& _screen;
};

#endif // __Clientmenu_hh

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009 Secure Endpoints Inc.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define OEMRESOURCE

#include "khmapp.h"
#include "AlertContainer.hpp"

namespace nim {

    AlertElement::AlertElement(Alert& a, int index) :
	m_alert(a),
	m_index(index),
	m_monitor(NULL),
        m_err_completed(false),
        m_err_context(NULL),

	el_title(NULL),
	el_message(NULL),
	el_suggestion(NULL),
	el_icon(NULL),
	el_expose(NULL),
	el_progress(NULL)
    {
	AutoLock<Alert> a_lock(&m_alert);

	m_alert->displayed = TRUE;
    }

    AlertElement::~AlertElement()
     {
	 {
	     AutoLock<Alert> a_lock(&m_alert);
	     m_alert->displayed = FALSE;
	 }

	 if (m_monitor)
	     delete m_monitor;
     }

    // alert must be locked
    HICON AlertElement::IconForAlert()
    {
	if ((m_alert->alert_type == KHUI_ALERTTYPE_PROGRESS ||
	     m_alert->alert_type == KHUI_ALERTTYPE_PROGRESSACQ) &&
	    m_alert->severity >= KHERR_INFO &&
	    (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR)) {

	    return LoadIconResource(m_err_completed ? IDI_CHECK : IDI_CLOCK);
	} else {
	    return LoadIconResource(
				    (m_alert->severity == KHERR_ERROR)? OIC_HAND :
				    (m_alert->severity == KHERR_WARNING)? OIC_BANG :
				    OIC_NOTE,
				    false, true, NULL
				    );
	}
    }

    DrawState AlertElement::GetDrawState()
    {
	return (DrawState)(0 |
			   (selected ? DrawStateSelected : DrawStateNone) |
			   (highlight ? DrawStateHotTrack : DrawStateNone) |
			   (focus ? DrawStateFocusRect : DrawStateNone));
    }

    void AlertElement::UpdateLayoutPre(Graphics & g, Rect & layout)
    {
	AutoLock<Alert> a_lock(&m_alert);
        bool was_modified = !!(m_alert->flags & KHUI_ALERT_FLAG_MODIFIED);

	if (!el_title) {
	    el_title = PNEW AlertTitleElement();
	    InsertChildAfter(el_title);
	}

        if (m_alert->title && was_modified)
            el_title->SetCaption(std::wstring(m_alert->title));

	if (!el_message) {
	    el_message = PNEW AlertMessageElement();
	    InsertChildAfter(el_message);
	}

        if (m_alert->message && was_modified)
            el_message->SetCaption(std::wstring(m_alert->message));

	if (!el_suggestion) {
	    el_suggestion = PNEW AlertSuggestionElement();
	    InsertChildAfter(el_suggestion);
	}

        if (m_alert->suggestion && was_modified)
            el_suggestion->SetCaption(std::wstring(m_alert->suggestion));

	if (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR) {

	    if (!el_progress) {
		el_progress = PNEW ProgressBarElement();
		InsertChildAfter(el_progress);
                UpdateProgress();
	    }

	    if (!el_expose) {
		el_expose = PNEW ExposeControlElement();
		InsertChildAfter(el_expose);
	    }
	}

	if (!el_icon) {
	    el_icon = PNEW IconDisplayElement(g_theme->pt_margin_cx + g_theme->pt_margin_cy,
					     IconForAlert(),
					     true /* Large */);
	    InsertChildAfter(el_icon);
	}

        if (el_buttons.size() == 0 && HasCommands()) {
            AutoLock<Alert> a_lock(&m_alert);

            for (int i = 0; i < m_alert->n_alert_commands; i++) {
                if (m_alert->alert_commands[i] != KHUI_PACTION_CLOSE) {
                    AlertCommandButtonElement * e = PNEW AlertCommandButtonElement();

                    InsertChildAfter(e);
                    el_buttons.push_back(e);

                    e->CreateFromCommand(m_alert->alert_commands[i],
                                         AlertContainer::ControlIdFromIndex(m_index, i));
                }
            }
        }

	extents.Height = 0;
	extents.Width = layout.Width;

	{
	    Size sz_icon = g_theme->sz_margin + g_theme->sz_icon + g_theme->sz_margin;

	    layout.X += sz_icon.Width;
	    layout.Width -= sz_icon.Width;
	}
    }

    void AlertElement::UpdateLayoutPost(Graphics & g, const Rect & bounds)
    {
        int left_indent = g_theme->sz_margin.Width * 2 + g_theme->sz_icon.Width;
        bool has_children = false;

        if (el_expose) {
            for (DisplayElement * e = TQFIRSTCHILD(this); e; e = TQNEXTSIBLING(e)) {
                AlertElement * ae = dynamic_cast<AlertElement *>(e);

                if (ae) {
                    has_children = true;
                    break;
                }
            }
        }

        FlowLayout layout(Rect(Point(0,0),
                               Size(bounds.Width + left_indent, 0)),
                          g_theme->sz_margin);

        layout
            .PushIndent(left_indent - g_theme->sz_margin.Width)
            .LineBreak()
            .Add(el_title)
            .LineBreak()
            .Add(el_message)
            .LineBreak()
            .Add(el_suggestion)
            .LineBreak()
            .Add(el_progress)
            .LineBreak()
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width - g_theme->sz_icon_sm.Width)
            .LineBreak()
            .Add(el_expose, FlowLayout::Left, FlowLayout::Fixed, has_children)
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width)
            ;

        for (std::vector<AlertCommandButtonElement *>::iterator i = el_buttons.begin();
             i != el_buttons.end(); ++i) {
            layout.Add(*i);
        }
        layout.LineBreak();

	for (DisplayElement * e = TQFIRSTCHILD(this); e;
	     e = TQNEXTSIBLING(e)) {
	    AlertElement * ca = dynamic_cast<AlertElement *>(e);

	    if (!ca || !ca->visible)
		continue;

            layout.Add(e).LineBreak();
	}

	extents = layout.GetSize();
        extents.Height = max(extents.Height, g_theme->sz_margin.Height * 2 + g_theme->sz_icon.Height);
    }

    void AlertElement::UpdateIcon()
    {
        if (el_icon)
            el_icon->SetIcon(IconForAlert());
    }

    void AlertElement::UpdateProgress()
    {
        khm_ui_4 num, denom;
        int norm_progress;

        if (m_err_context) {
            AutoLock<Alert> a_lock(&m_alert);
            kherr_get_progress_i(m_err_context, &num, &denom);
        } else {
            num = denom = 1;
        }

        if (denom == 0)
            norm_progress = 0;
        else if (num > denom)
            norm_progress = 256;
        else
            norm_progress = (num * 256) / denom;

        if (el_progress)
            el_progress->SetProgress(norm_progress);
        else {
            MarkForExtentUpdate();
            Invalidate();
        }

        if (norm_progress >= 256) {
            m_err_completed = true;
            UpdateIcon();
        }
    }

    void AlertElement::SetMonitor(AlertContextMonitor * m)
    {
        assert (m_monitor == NULL || m == NULL);
	m_monitor = m;
        m_err_context = m_alert->err_context;
        assert(m_err_context != NULL || m == NULL);
    }

    void AlertElement::TryMonitorNewChildContext(kherr_context * c)
    {
	for (DisplayElement * de = TQFIRSTCHILD(this); de;
	     de = TQNEXTSIBLING(de)) {
	    AlertElement * ae = dynamic_cast<AlertElement *>(de);

	    if (ae == NULL)
		continue;

	    {
		AutoLock<Alert> a_lock(&ae->m_alert);

		if (kherr_context_is_equal(c, ae->m_err_context))
		    return;	// Already there
	    }
	}

	// Wasn't there.  We need to create a new alert element and
	// add it to this element

	khui_alert * a = NULL;

	khui_alert_create_empty(&a);
	khui_alert_set_type(a, KHUI_ALERTTYPE_PROGRESSACQ);

	Alert alert(a, true);
	AlertElement * ae = PNEW AlertElement(alert, -1);

	InsertOutlineAfter(ae);

	khui_alert_monitor_progress(a, c,
				    KHUI_AMP_SHOW_EVT_ERR |
				    KHUI_AMP_SHOW_EVT_WARN);

        dynamic_cast<AlertContainer *>(owner)->BeginMonitoringAlert(alert);
    }

    void AlertElement::OnErrCtxEvent(enum kherr_ctx_event e)
    {
        if (m_err_context == NULL)
            return;

	switch (e) {
	case KHERR_CTX_DESCRIBE:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

		ev = kherr_get_desc_event(m_err_context);
		if (ev) {
		    if (ev->short_desc && ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
                        khui_alert_set_message(m_alert, ev->short_desc);
		    } else if (ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_title(m_alert, ev->short_desc);
		    }
		}
                MarkForExtentUpdate();
                Invalidate();
	    }
	    break;

	case KHERR_CTX_END:
	    {
                m_err_completed = true;
                m_err_context = NULL;
		UpdateIcon();
	    }
	    break;

	case KHERR_CTX_EVTCOMMIT:
	case KHERR_CTX_ERROR:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

		ev = kherr_get_last_event(m_err_context);

		if (((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_ERR) &&
		     ev->severity <= KHERR_ERROR) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_WARN) &&
		     ev->severity <= KHERR_WARNING) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_INFO) &&
		     ev->severity <= KHERR_INFO) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_DEBUG) &&
		     ev->severity <= KHERR_DEBUG_3)) {

		    khui_alert_set_severity(m_alert, ev->severity);

		    if (!(ev->flags & KHERR_RF_STR_RESOLVED))
			kherr_evaluate_event(ev);

		    if (ev->long_desc) {
                        khui_alert_set_message(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_message(m_alert, ev->short_desc);
		    }

		    UpdateIcon();
		}
	    }
	    break;

	case KHERR_CTX_NEWCHILD:
	    {
		kherr_context * c;

		{
		    AutoLock<Alert> a_lock(&m_alert);
		    c = kherr_get_first_context(m_err_context);
		}

		for (; c ; c = kherr_get_next_context(c)) {
		    TryMonitorNewChildContext(c);
		}
	    }
	    break;

	case KHERR_CTX_PROGRESS:
	    {
                UpdateProgress();
	    }
	    break;
	}
    }

    void AlertElement::PaintSelf(Graphics &g, const Rect& bounds, const Rect& clip)
    {
	g_theme->DrawAlertBackground(g, bounds, GetDrawState());
    }

    void AlertCommandButtonElement::CreateFromCommand(khm_int32 cmd, UINT ctl_id)
    {
        assert (owner);
        assert (owner->hwnd);

        HWND hwnd_button;
        wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";

        khm_get_action_caption(cmd, caption, sizeof(caption));

        hwnd_button = CreateWindow(L"BUTTON",
                                   caption,
                                   WS_TABSTOP | WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY,
                                   0, 0, 100, 100, // Dummy x,y,width,height
                                   owner->hwnd,
                                   (HMENU)(UINT_PTR) ctl_id,
                                   khm_hInstance,
                                   NULL);
        SendMessage(hwnd_button, WM_SETFONT, (WPARAM) g_theme->hf_normal, FALSE);
        SetWindow(hwnd_button);
    }

    void AlertCommandButtonElement::UpdateLayoutPre(Graphics& g, Rect& layout)
    {
        HWND hwnd_button;

        hwnd_button = GetWindow();

        if (hwnd_button) {
            wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";
            HFONT hf;
            Font * font;

            GetWindowText(hwnd_button, caption, ARRAYLENGTH(caption));
            hf = (HFONT) SendMessage(hwnd_button, WM_GETFONT, 0, 0);
            if (hf == NULL)
                hf = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
            {
                HDC hdc = g.GetHDC();
                font = new Font(hdc, hf);
                g.ReleaseHDC(hdc);
            }

            StringFormat fmt(StringFormatFlagsNoWrap);
            RectF brect;

            g.MeasureString(caption, -1, font, PointF(0.0, 0.0), &fmt, &brect);

            int bwidth = (int) brect.Width + g_theme->sz_margin.Width * 2;
            int bheight = (int) brect.Height + g_theme->sz_margin.Height * 2;

            SetWindowPos(hwnd_button, NULL, 0, 0,
                         bwidth, bheight, SWP_SIZEONLY);

            delete font;
        }
    }
}
<commit_msg>Don't show a progress bar to a completed alert<commit_after>/*
 * Copyright (c) 2009 Secure Endpoints Inc.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define OEMRESOURCE

#include "khmapp.h"
#include "AlertContainer.hpp"

namespace nim {

    AlertElement::AlertElement(Alert& a, int index) :
	m_alert(a),
	m_index(index),
	m_monitor(NULL),
        m_err_completed(false),
        m_err_context(NULL),

	el_title(NULL),
	el_message(NULL),
	el_suggestion(NULL),
	el_icon(NULL),
	el_expose(NULL),
	el_progress(NULL)
    {
	AutoLock<Alert> a_lock(&m_alert);

	m_alert->displayed = TRUE;
    }

    AlertElement::~AlertElement()
     {
	 {
	     AutoLock<Alert> a_lock(&m_alert);
	     m_alert->displayed = FALSE;
	 }

	 if (m_monitor)
	     delete m_monitor;
     }

    // alert must be locked
    HICON AlertElement::IconForAlert()
    {
	if ((m_alert->alert_type == KHUI_ALERTTYPE_PROGRESS ||
	     m_alert->alert_type == KHUI_ALERTTYPE_PROGRESSACQ) &&
	    m_alert->severity >= KHERR_INFO &&
	    (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR)) {

	    return LoadIconResource(m_err_completed ? IDI_CHECK : IDI_CLOCK);
	} else {
	    return LoadIconResource(
				    (m_alert->severity == KHERR_ERROR)? OIC_HAND :
				    (m_alert->severity == KHERR_WARNING)? OIC_BANG :
				    OIC_NOTE,
				    false, true, NULL
				    );
	}
    }

    DrawState AlertElement::GetDrawState()
    {
	return (DrawState)(0 |
			   (selected ? DrawStateSelected : DrawStateNone) |
			   (highlight ? DrawStateHotTrack : DrawStateNone) |
			   (focus ? DrawStateFocusRect : DrawStateNone));
    }

    void AlertElement::UpdateLayoutPre(Graphics & g, Rect & layout)
    {
	AutoLock<Alert> a_lock(&m_alert);
        bool was_modified = !!(m_alert->flags & KHUI_ALERT_FLAG_MODIFIED);

	if (!el_title) {
	    el_title = PNEW AlertTitleElement();
	    InsertChildAfter(el_title);
	}

        if (m_alert->title && was_modified)
            el_title->SetCaption(std::wstring(m_alert->title));

	if (!el_message) {
	    el_message = PNEW AlertMessageElement();
	    InsertChildAfter(el_message);
	}

        if (m_alert->message && was_modified)
            el_message->SetCaption(std::wstring(m_alert->message));

	if (!el_suggestion) {
	    el_suggestion = PNEW AlertSuggestionElement();
	    InsertChildAfter(el_suggestion);
	}

        if (m_alert->suggestion && was_modified)
            el_suggestion->SetCaption(std::wstring(m_alert->suggestion));

	if (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR) {

	    if (!el_progress) {
		el_progress = PNEW ProgressBarElement();
		InsertChildAfter(el_progress);
                UpdateProgress();
	    }

	    if (!el_expose) {
		el_expose = PNEW ExposeControlElement();
		InsertChildAfter(el_expose);
	    }
	}

	if (!el_icon) {
	    el_icon = PNEW IconDisplayElement(g_theme->pt_margin_cx + g_theme->pt_margin_cy,
					     IconForAlert(),
					     true /* Large */);
	    InsertChildAfter(el_icon);
	}

        if (el_buttons.size() == 0 && HasCommands()) {
            AutoLock<Alert> a_lock(&m_alert);

            for (int i = 0; i < m_alert->n_alert_commands; i++) {
                if (m_alert->alert_commands[i] != KHUI_PACTION_CLOSE) {
                    AlertCommandButtonElement * e = PNEW AlertCommandButtonElement();

                    InsertChildAfter(e);
                    el_buttons.push_back(e);

                    e->CreateFromCommand(m_alert->alert_commands[i],
                                         AlertContainer::ControlIdFromIndex(m_index, i));
                }
            }
        }

	extents.Height = 0;
	extents.Width = layout.Width;

	{
	    Size sz_icon = g_theme->sz_margin + g_theme->sz_icon + g_theme->sz_margin;

	    layout.X += sz_icon.Width;
	    layout.Width -= sz_icon.Width;
	}
    }

    void AlertElement::UpdateLayoutPost(Graphics & g, const Rect & bounds)
    {
        int left_indent = g_theme->sz_margin.Width * 2 + g_theme->sz_icon.Width;
        bool has_children = false;

        if (el_expose) {
            for (DisplayElement * e = TQFIRSTCHILD(this); e; e = TQNEXTSIBLING(e)) {
                AlertElement * ae = dynamic_cast<AlertElement *>(e);

                if (ae) {
                    has_children = true;
                    break;
                }
            }
        }

        FlowLayout layout(Rect(Point(0,0),
                               Size(bounds.Width + left_indent, 0)),
                          g_theme->sz_margin);

        layout
            .PushIndent(left_indent - g_theme->sz_margin.Width)
            .LineBreak()
            .Add(el_title)
            .LineBreak()
            .Add(el_message)
            .LineBreak()
            .Add(el_suggestion)
            .LineBreak()
            .Add(el_progress, !m_err_completed)
            .LineBreak()
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width - g_theme->sz_icon_sm.Width)
            .LineBreak()
            .Add(el_expose, FlowLayout::Left, FlowLayout::Fixed, has_children)
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width)
            ;

        for (std::vector<AlertCommandButtonElement *>::iterator i = el_buttons.begin();
             i != el_buttons.end(); ++i) {
            layout.Add(*i);
        }
        layout.LineBreak();

	for (DisplayElement * e = TQFIRSTCHILD(this); e;
	     e = TQNEXTSIBLING(e)) {
	    AlertElement * ca = dynamic_cast<AlertElement *>(e);

	    if (!ca || !ca->visible)
		continue;

            layout.Add(e).LineBreak();
	}

	extents = layout.GetSize();
        extents.Height = max(extents.Height, g_theme->sz_margin.Height * 2 + g_theme->sz_icon.Height);
    }

    void AlertElement::UpdateIcon()
    {
        if (el_icon)
            el_icon->SetIcon(IconForAlert());
    }

    void AlertElement::UpdateProgress()
    {
        khm_ui_4 num, denom;
        int norm_progress;

        if (m_err_context) {
            AutoLock<Alert> a_lock(&m_alert);
            kherr_get_progress_i(m_err_context, &num, &denom);
        } else {
            num = denom = 1;
        }

        if (denom == 0)
            norm_progress = 0;
        else if (num > denom)
            norm_progress = 256;
        else
            norm_progress = (num * 256) / denom;

        if (el_progress)
            el_progress->SetProgress(norm_progress);
        else {
            MarkForExtentUpdate();
            Invalidate();
        }

        if (norm_progress >= 256) {
            m_err_completed = true;
            UpdateIcon();
        }
    }

    void AlertElement::SetMonitor(AlertContextMonitor * m)
    {
        assert (m_monitor == NULL || m == NULL);
	m_monitor = m;
        m_err_context = m_alert->err_context;
        assert(m_err_context != NULL || m == NULL);
    }

    void AlertElement::TryMonitorNewChildContext(kherr_context * c)
    {
	for (DisplayElement * de = TQFIRSTCHILD(this); de;
	     de = TQNEXTSIBLING(de)) {
	    AlertElement * ae = dynamic_cast<AlertElement *>(de);

	    if (ae == NULL)
		continue;

	    {
		AutoLock<Alert> a_lock(&ae->m_alert);

		if (kherr_context_is_equal(c, ae->m_err_context))
		    return;	// Already there
	    }
	}

	// Wasn't there.  We need to create a new alert element and
	// add it to this element

	khui_alert * a = NULL;

	khui_alert_create_empty(&a);
	khui_alert_set_type(a, KHUI_ALERTTYPE_PROGRESSACQ);

	Alert alert(a, true);
	AlertElement * ae = PNEW AlertElement(alert, -1);

	InsertOutlineAfter(ae);

	khui_alert_monitor_progress(a, c,
				    KHUI_AMP_SHOW_EVT_ERR |
				    KHUI_AMP_SHOW_EVT_WARN);

        dynamic_cast<AlertContainer *>(owner)->BeginMonitoringAlert(alert);
    }

    void AlertElement::OnErrCtxEvent(enum kherr_ctx_event e)
    {
        if (m_err_context == NULL)
            return;

	switch (e) {
	case KHERR_CTX_DESCRIBE:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

		ev = kherr_get_desc_event(m_err_context);
		if (ev) {
		    if (ev->short_desc && ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
                        khui_alert_set_message(m_alert, ev->short_desc);
		    } else if (ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_title(m_alert, ev->short_desc);
		    }
		}
                MarkForExtentUpdate();
                Invalidate();
	    }
	    break;

	case KHERR_CTX_END:
	    {
                m_err_completed = true;
                m_err_context = NULL;
		UpdateIcon();
	    }
	    break;

	case KHERR_CTX_EVTCOMMIT:
	case KHERR_CTX_ERROR:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

		ev = kherr_get_last_event(m_err_context);

		if (((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_ERR) &&
		     ev->severity <= KHERR_ERROR) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_WARN) &&
		     ev->severity <= KHERR_WARNING) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_INFO) &&
		     ev->severity <= KHERR_INFO) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_DEBUG) &&
		     ev->severity <= KHERR_DEBUG_3)) {

		    khui_alert_set_severity(m_alert, ev->severity);

		    if (!(ev->flags & KHERR_RF_STR_RESOLVED))
			kherr_evaluate_event(ev);

		    if (ev->long_desc) {
                        khui_alert_set_message(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_message(m_alert, ev->short_desc);
		    }

                    if (ev->suggestion) {
                        khui_alert_set_suggestion(m_alert, ev->suggestion);
                    } else {
                        khui_alert_set_suggestion(m_alert, NULL);
                    }

                    UpdateIcon();
                    MarkForExtentUpdate();
                    Invalidate();
		}
	    }
	    break;

	case KHERR_CTX_NEWCHILD:
	    {
		kherr_context * c;

		{
		    AutoLock<Alert> a_lock(&m_alert);
		    c = kherr_get_first_context(m_err_context);
		}

		for (; c ; c = kherr_get_next_context(c)) {
		    TryMonitorNewChildContext(c);
		}
	    }
	    break;

	case KHERR_CTX_PROGRESS:
	    {
                UpdateProgress();
	    }
	    break;
	}
    }

    void AlertElement::PaintSelf(Graphics &g, const Rect& bounds, const Rect& clip)
    {
	g_theme->DrawAlertBackground(g, bounds, GetDrawState());
    }

    void AlertCommandButtonElement::CreateFromCommand(khm_int32 cmd, UINT ctl_id)
    {
        assert (owner);
        assert (owner->hwnd);

        HWND hwnd_button;
        wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";

        khm_get_action_caption(cmd, caption, sizeof(caption));

        hwnd_button = CreateWindow(L"BUTTON",
                                   caption,
                                   WS_TABSTOP | WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY,
                                   0, 0, 100, 100, // Dummy x,y,width,height
                                   owner->hwnd,
                                   (HMENU)(UINT_PTR) ctl_id,
                                   khm_hInstance,
                                   NULL);
        SendMessage(hwnd_button, WM_SETFONT, (WPARAM) g_theme->hf_normal, FALSE);
        SetWindow(hwnd_button);
    }

    void AlertCommandButtonElement::UpdateLayoutPre(Graphics& g, Rect& layout)
    {
        HWND hwnd_button;

        hwnd_button = GetWindow();

        if (hwnd_button) {
            wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";
            HFONT hf;
            Font * font;

            GetWindowText(hwnd_button, caption, ARRAYLENGTH(caption));
            hf = (HFONT) SendMessage(hwnd_button, WM_GETFONT, 0, 0);
            if (hf == NULL)
                hf = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
            {
                HDC hdc = g.GetHDC();
                font = new Font(hdc, hf);
                g.ReleaseHDC(hdc);
            }

            StringFormat fmt(StringFormatFlagsNoWrap);
            RectF brect;

            g.MeasureString(caption, -1, font, PointF(0.0, 0.0), &fmt, &brect);

            int bwidth = (int) brect.Width + g_theme->sz_margin.Width * 2;
            int bheight = (int) brect.Height + g_theme->sz_margin.Height * 2;

            SetWindowPos(hwnd_button, NULL, 0, 0,
                         bwidth, bheight, SWP_SIZEONLY);

            delete font;
        }
    }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sfx2.hxx"

#include "plugin.hxx"
#include <com/sun/star/plugin/XPluginManager.hpp>
#include <com/sun/star/plugin/PluginMode.hpp>
#include <com/sun/star/awt/XControl.hpp>

#include <tools/debug.hxx>
#include <rtl/ustring.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <svtools/miscopt.hxx>
#include <vcl/window.hxx>

using namespace ::com::sun::star;

namespace sfx2
{

class PluginWindow_Impl : public Window
{
public:
    uno::Reference < awt::XWindow > xWindow;
    PluginWindow_Impl( Window* pParent )
     : Window( pParent, WB_CLIPCHILDREN )
     {}

     virtual void Resize();
};

void PluginWindow_Impl::Resize()
{
    Size aSize( GetOutputSizePixel() );
    if ( xWindow.is() )
        xWindow->setPosSize( 0, 0, aSize.Width(), aSize.Height(), WINDOW_POSSIZE_SIZE );
}

#define PROPERTY_UNBOUND 0

#define WID_COMMANDS    1
#define WID_MIMETYPE    2
#define WID_URL         3
const SfxItemPropertyMapEntry* lcl_GetPluginPropertyMap_Impl()
{
    static SfxItemPropertyMapEntry aPluginPropertyMap_Impl[] =
    {
        { MAP_CHAR_LEN("PluginCommands"), WID_COMMANDS, &::getCppuType((::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >*)0), PROPERTY_UNBOUND, 0},
        { MAP_CHAR_LEN("PluginMimeType"), WID_MIMETYPE, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
        { MAP_CHAR_LEN("PluginURL"),      WID_URL     , &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
        {0,0,0,0,0,0}
    };
    return aPluginPropertyMap_Impl;
}

SFX_IMPL_XSERVICEINFO( PluginObject, "com.sun.star.embed.SpecialEmbeddedObject", "com.sun.star.comp.sfx2.PluginObject" )
SFX_IMPL_SINGLEFACTORY( PluginObject );

PluginObject::PluginObject( const uno::Reference < lang::XMultiServiceFactory >& rFact )
    : mxFact( rFact )
    , maPropMap( lcl_GetPluginPropertyMap_Impl() )
{
}

PluginObject::~PluginObject()
{
}

void SAL_CALL PluginObject::initialize( const uno::Sequence< uno::Any >& aArguments ) throw ( uno::Exception, uno::RuntimeException )
{
    if ( aArguments.getLength() )
        aArguments[0] >>= mxObj;
}

sal_Bool SAL_CALL PluginObject::load(
    const uno::Sequence < com::sun::star::beans::PropertyValue >& /*lDescriptor*/,
    const uno::Reference < frame::XFrame >& xFrame )
throw( uno::RuntimeException )
{
    uno::Reference< plugin::XPluginManager > xPMgr( mxFact->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.plugin.PluginManager")) ), uno::UNO_QUERY );
    if (!xPMgr.is() )
        return sal_False;

    if ( SvtMiscOptions().IsPluginsEnabled() )
    {
        Window* pParent = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
        PluginWindow_Impl* pWin = new PluginWindow_Impl( pParent );
        pWin->SetSizePixel( pParent->GetOutputSizePixel() );
        pWin->SetBackground();
        pWin->Show();

        sal_uIntPtr nCount = maCmdList.Count();
        uno::Sequence < ::rtl::OUString > aCmds( nCount ), aArgs( nCount );
        ::rtl::OUString *pCmds = aCmds.getArray(), *pArgs = aArgs.getArray();
        for( sal_uIntPtr i = 0; i < nCount; i++ )
        {
            SvCommand & rCmd = maCmdList.GetObject( i );
            pCmds[i] = rCmd.GetCommand();
            pArgs[i] = rCmd.GetArgument();
        }

        mxPlugin = xPMgr->createPluginFromURL(
            xPMgr->createPluginContext(), plugin::PluginMode::EMBED, aCmds, aArgs, uno::Reference< awt::XToolkit >(),
            uno::Reference< awt::XWindowPeer >( pWin->GetComponentInterface() ), maURL );

        if ( mxPlugin.is() )
        {
            uno::Reference< awt::XWindow > xWindow( mxPlugin, uno::UNO_QUERY );
            if ( xWindow.is() )
            {
                pWin->xWindow = xWindow;
                pWin->Resize();
                xWindow->setVisible( sal_True );
            }

            try
            {
                uno::Reference< awt::XControl > xControl( mxPlugin, uno::UNO_QUERY );
                if( xControl.is() )
                {
                    uno::Reference< awt::XControlModel > xModel = xControl->getModel();
                    uno::Reference< beans::XPropertySet > xProp( xModel, ::uno::UNO_QUERY );
                    if( xProp.is() )
                    {
                        uno::Any aValue = xProp->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ) );
                        aValue >>= maURL;
                        aValue = xProp->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TYPE" ) ) );
                        aValue >>= maMimeType;
                    }
                }
            }
            catch( uno::Exception& )
            {
            }
        }

        uno::Reference < awt::XWindow > xWindow( pWin->GetComponentInterface(), uno::UNO_QUERY );

        // we must destroy the plugin before the parent is destroyed
        xWindow->addEventListener( this );
        xFrame->setComponent( xWindow, uno::Reference < frame::XController >() );
        return mxPlugin.is() ? sal_True : sal_False;
    }

    return sal_False;
}

void SAL_CALL PluginObject::cancel() throw( com::sun::star::uno::RuntimeException )
{
    uno::Reference< lang::XComponent > xComp( mxPlugin, uno::UNO_QUERY );
    if (xComp.is())
        xComp->dispose();
    mxPlugin = 0;
}

void SAL_CALL PluginObject::close( sal_Bool /*bDeliverOwnership*/ ) throw( com::sun::star::util::CloseVetoException, com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::addCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::removeCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::disposing( const com::sun::star::lang::EventObject& ) throw (com::sun::star::uno::RuntimeException)
{
    cancel();
}

uno::Reference< beans::XPropertySetInfo > SAL_CALL PluginObject::getPropertySetInfo() throw( ::com::sun::star::uno::RuntimeException )
{
    static uno::Reference< beans::XPropertySetInfo > xInfo = new SfxItemPropertySetInfo( &maPropMap );
    return xInfo;
}

void SAL_CALL PluginObject::setPropertyValue(const ::rtl::OUString& aPropertyName, const uno::Any& aAny)
    throw ( beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
{
    if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginURL")) )
    {
        aAny >>= maURL;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginMimeType")) )
    {
        aAny >>= maMimeType;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginCommands")) )
    {
        maCmdList.Clear();
        uno::Sequence < beans::PropertyValue > aCommandSequence;
        if( aAny >>= aCommandSequence )
            maCmdList.FillFromSequence( aCommandSequence );
    }
    else
         throw beans::UnknownPropertyException();
}

uno::Any SAL_CALL PluginObject::getPropertyValue(const ::rtl::OUString& aPropertyName)
        throw ( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
{
    uno::Any aAny;
    if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginURL")) )
    {
        aAny <<= maURL;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginMimeType")) )
    {
        aAny <<= maMimeType;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginCommands")) )
    {
        uno::Sequence< beans::PropertyValue > aCommandSequence;
        maCmdList.FillSequence( aCommandSequence );
        aAny <<= aCommandSequence;
    }
    else
         throw beans::UnknownPropertyException();
    return aAny;
}

void SAL_CALL PluginObject::addPropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::removePropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::addVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::removeVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Convert SvCommandList from an OwnList to a vector<><commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sfx2.hxx"

#include "plugin.hxx"
#include <com/sun/star/plugin/XPluginManager.hpp>
#include <com/sun/star/plugin/PluginMode.hpp>
#include <com/sun/star/awt/XControl.hpp>

#include <tools/debug.hxx>
#include <rtl/ustring.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <svtools/miscopt.hxx>
#include <vcl/window.hxx>

using namespace ::com::sun::star;

namespace sfx2
{

class PluginWindow_Impl : public Window
{
public:
    uno::Reference < awt::XWindow > xWindow;
    PluginWindow_Impl( Window* pParent )
     : Window( pParent, WB_CLIPCHILDREN )
     {}

     virtual void Resize();
};

void PluginWindow_Impl::Resize()
{
    Size aSize( GetOutputSizePixel() );
    if ( xWindow.is() )
        xWindow->setPosSize( 0, 0, aSize.Width(), aSize.Height(), WINDOW_POSSIZE_SIZE );
}

#define PROPERTY_UNBOUND 0

#define WID_COMMANDS    1
#define WID_MIMETYPE    2
#define WID_URL         3
const SfxItemPropertyMapEntry* lcl_GetPluginPropertyMap_Impl()
{
    static SfxItemPropertyMapEntry aPluginPropertyMap_Impl[] =
    {
        { MAP_CHAR_LEN("PluginCommands"), WID_COMMANDS, &::getCppuType((::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >*)0), PROPERTY_UNBOUND, 0},
        { MAP_CHAR_LEN("PluginMimeType"), WID_MIMETYPE, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
        { MAP_CHAR_LEN("PluginURL"),      WID_URL     , &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
        {0,0,0,0,0,0}
    };
    return aPluginPropertyMap_Impl;
}

SFX_IMPL_XSERVICEINFO( PluginObject, "com.sun.star.embed.SpecialEmbeddedObject", "com.sun.star.comp.sfx2.PluginObject" )
SFX_IMPL_SINGLEFACTORY( PluginObject );

PluginObject::PluginObject( const uno::Reference < lang::XMultiServiceFactory >& rFact )
    : mxFact( rFact )
    , maPropMap( lcl_GetPluginPropertyMap_Impl() )
{
}

PluginObject::~PluginObject()
{
}

void SAL_CALL PluginObject::initialize( const uno::Sequence< uno::Any >& aArguments ) throw ( uno::Exception, uno::RuntimeException )
{
    if ( aArguments.getLength() )
        aArguments[0] >>= mxObj;
}

sal_Bool SAL_CALL PluginObject::load(
    const uno::Sequence < com::sun::star::beans::PropertyValue >& /*lDescriptor*/,
    const uno::Reference < frame::XFrame >& xFrame )
throw( uno::RuntimeException )
{
    uno::Reference< plugin::XPluginManager > xPMgr( mxFact->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.plugin.PluginManager")) ), uno::UNO_QUERY );
    if (!xPMgr.is() )
        return sal_False;

    if ( SvtMiscOptions().IsPluginsEnabled() )
    {
        Window* pParent = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
        PluginWindow_Impl* pWin = new PluginWindow_Impl( pParent );
        pWin->SetSizePixel( pParent->GetOutputSizePixel() );
        pWin->SetBackground();
        pWin->Show();

        size_t nCount = maCmdList.size();
        uno::Sequence < ::rtl::OUString > aCmds( nCount ), aArgs( nCount );
        ::rtl::OUString *pCmds = aCmds.getArray(), *pArgs = aArgs.getArray();
        for( size_t i = 0; i < nCount; i++ )
        {
            pCmds[i] = maCmdList[ i ].GetCommand();
            pArgs[i] = maCmdList[ i ].GetArgument();
        }

        mxPlugin = xPMgr->createPluginFromURL(
            xPMgr->createPluginContext(), plugin::PluginMode::EMBED, aCmds, aArgs, uno::Reference< awt::XToolkit >(),
            uno::Reference< awt::XWindowPeer >( pWin->GetComponentInterface() ), maURL );

        if ( mxPlugin.is() )
        {
            uno::Reference< awt::XWindow > xWindow( mxPlugin, uno::UNO_QUERY );
            if ( xWindow.is() )
            {
                pWin->xWindow = xWindow;
                pWin->Resize();
                xWindow->setVisible( sal_True );
            }

            try
            {
                uno::Reference< awt::XControl > xControl( mxPlugin, uno::UNO_QUERY );
                if( xControl.is() )
                {
                    uno::Reference< awt::XControlModel > xModel = xControl->getModel();
                    uno::Reference< beans::XPropertySet > xProp( xModel, ::uno::UNO_QUERY );
                    if( xProp.is() )
                    {
                        uno::Any aValue = xProp->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ) );
                        aValue >>= maURL;
                        aValue = xProp->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TYPE" ) ) );
                        aValue >>= maMimeType;
                    }
                }
            }
            catch( uno::Exception& )
            {
            }
        }

        uno::Reference < awt::XWindow > xWindow( pWin->GetComponentInterface(), uno::UNO_QUERY );

        // we must destroy the plugin before the parent is destroyed
        xWindow->addEventListener( this );
        xFrame->setComponent( xWindow, uno::Reference < frame::XController >() );
        return mxPlugin.is() ? sal_True : sal_False;
    }

    return sal_False;
}

void SAL_CALL PluginObject::cancel() throw( com::sun::star::uno::RuntimeException )
{
    uno::Reference< lang::XComponent > xComp( mxPlugin, uno::UNO_QUERY );
    if (xComp.is())
        xComp->dispose();
    mxPlugin = 0;
}

void SAL_CALL PluginObject::close( sal_Bool /*bDeliverOwnership*/ ) throw( com::sun::star::util::CloseVetoException, com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::addCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::removeCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::disposing( const com::sun::star::lang::EventObject& ) throw (com::sun::star::uno::RuntimeException)
{
    cancel();
}

uno::Reference< beans::XPropertySetInfo > SAL_CALL PluginObject::getPropertySetInfo() throw( ::com::sun::star::uno::RuntimeException )
{
    static uno::Reference< beans::XPropertySetInfo > xInfo = new SfxItemPropertySetInfo( &maPropMap );
    return xInfo;
}

void SAL_CALL PluginObject::setPropertyValue(const ::rtl::OUString& aPropertyName, const uno::Any& aAny)
    throw ( beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
{
    if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginURL")) )
    {
        aAny >>= maURL;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginMimeType")) )
    {
        aAny >>= maMimeType;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginCommands")) )
    {
        maCmdList.clear();
        uno::Sequence < beans::PropertyValue > aCommandSequence;
        if( aAny >>= aCommandSequence )
            maCmdList.FillFromSequence( aCommandSequence );
    }
    else
         throw beans::UnknownPropertyException();
}

uno::Any SAL_CALL PluginObject::getPropertyValue(const ::rtl::OUString& aPropertyName)
        throw ( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
{
    uno::Any aAny;
    if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginURL")) )
    {
        aAny <<= maURL;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginMimeType")) )
    {
        aAny <<= maMimeType;
    }
    else if ( aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("PluginCommands")) )
    {
        uno::Sequence< beans::PropertyValue > aCommandSequence;
        maCmdList.FillSequence( aCommandSequence );
        aAny <<= aCommandSequence;
    }
    else
         throw beans::UnknownPropertyException();
    return aAny;
}

void SAL_CALL PluginObject::addPropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::removePropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::addVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

void SAL_CALL PluginObject::removeVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException )
{
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>