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

  Program: Bender

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Bender includes
#include "vtkMRMLArmatureNode.h"
#include "vtkMRMLArmatureNodeHelper.h"
#include "vtkMRMLBoneNode.h"

#include <vtkQuaternion.h>

// Slicer includes
#include <vtkMRMLHierarchyNode.h>

// VTK includes
#include <vtkCollection.h>
#include <vtkMath.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkTransform.h>

// STD includes

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkMRMLArmatureNodeHelper)

//----------------------------------------------------------------------------
double vtkMRMLArmatureNodeHelper::GetBoneSize(vtkMRMLBoneNode* bone)
{
  if (!bone)
    {
    return 0.0;
    }

  double localTail[3];
  bone->GetLocalTailRest(localTail);
  return vtkMath::Norm(localTail);
}

//----------------------------------------------------------------------------
double vtkMRMLArmatureNodeHelper::GetBoneSize(vtkBoneWidget* bone)
{
  if (!bone)
    {
    return 0.0;
    }

  double localTail[3];
  bone->GetLocalTailRest(localTail);
  return vtkMath::Norm(localTail);
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper::ResizeArmature(vtkMRMLArmatureNode* armature,
                                               vtkCollection* bones,
                                               std::vector<double>& sizes,
                                               double origin[3],
                                               std::vector<double>* oldSizes)
{
 // In the general case, bones are like this:
  // ParentTail  -  -  -  -  -  -  Head------Tail
  //           <------Offset------><---Length--->
  //           <--------------Size-------------->
  // We need to scale the target bone size to the size of the anim bone.
  if (!bones || bones->GetNumberOfItems() < 1)
    {
    std::cerr<<"There are no bones in the given armature !"<<std::endl;
    return false;
    }
  if (bones->GetNumberOfItems() != static_cast<int>(sizes.size()))
    {
    std::cerr<<"There should be as many sizes as bone nodes !"<<std::endl;
    return false;
    }

  vtkNew<vtkCollection> roots;
  armature->GetDirectChildren(roots.GetPointer());
  if (roots->GetNumberOfItems() != 1)
    {
    std::cerr<<"Cannot resize armature that don't have exactly one root."
      <<std::endl;
    return false;
    }

  int oldState = armature->SetWidgetState(vtkMRMLArmatureNode::Rest);

  // First move target root to anim root
  vtkMRMLBoneNode* root =
    vtkMRMLBoneNode::SafeDownCast(roots->GetItemAsObject(0));

  double rootHead[3], rootTranslation[3];
  root->GetWorldHeadRest(rootHead);
  vtkMath::Subtract(origin, rootHead, rootTranslation);
  armature->Translate(rootTranslation);

  for (int i = 0; i < bones->GetNumberOfItems(); ++i)
    {
    vtkMRMLBoneNode* bone =
      vtkMRMLBoneNode::SafeDownCast(bones->GetItemAsObject(i));

    // Before anything, save bone size and length
    double size = GetBoneSize(bone);
    if (oldSizes)
      {
      oldSizes->push_back(size);
      }

    // Get bone children
    vtkNew<vtkCollection> directBoneChildren;
    vtkMRMLAnnotationHierarchyNode* hierarchyNode =
      vtkMRMLAnnotationHierarchyNode::SafeDownCast(
        vtkMRMLHierarchyNode::GetAssociatedHierarchyNode(
          bone->GetScene(), bone->GetID()));
    hierarchyNode->GetDirectChildren(directBoneChildren.GetPointer());

    // Unlink from bone children
    std::vector<bool> wasLinked;
    for (int j = 0; j < directBoneChildren->GetNumberOfItems(); ++j)
      {
      vtkMRMLBoneNode* child =
        vtkMRMLBoneNode::SafeDownCast(directBoneChildren->GetItemAsObject(j));
      wasLinked.push_back(child->GetBoneLinkedWithParent());
      child->SetBoneLinkedWithParent(false);
      }

    // Save old tail position
    double oldTargetTail[3];
    bone->GetWorldTailRest(oldTargetTail);

    // Resize bone
    //\todo fixme, root isn't necessary the only top level bone
    bool isTopLevel = (bone == root);
    double newSize = sizes[i];
    if (bone->GetBoneLinkedWithParent() || isTopLevel)
      {
      // Easy case, the bone is linked to its parent (or root).
      // We can just change its length to the new size
      bone->SetLength(newSize);
      }
    else
      {
      // Harder case, the bone isn't linked to its parent (nor root).
      // We need to scale its length and its offset.

      // Get the line vector between the parent's head and head
      double lineVect[3], parentHead[3], head[3];
      bone->GetWorldToParentRestTranslation(parentHead);
      bone->GetWorldHeadRest(head);
      vtkMath::Subtract(head, parentHead, lineVect);
      vtkMath::Normalize(lineVect);

      // Change length
      bone->SetLength((newSize * bone->GetLength()) / size);

      // Change target offset
      vtkMath::MultiplyScalar(lineVect, newSize - bone->GetLength());
      vtkMath::Add(lineVect, parentHead, head);
      bone->SetWorldHeadRest(head);
      }

    // Get translation
    double newTail[3];
    bone->GetWorldTailRest(newTail);
    double translation[3];
    vtkMath::Subtract(newTail, oldTargetTail, translation);

    // Move Bone children
    vtkNew<vtkCollection> boneChildren;
    hierarchyNode->GetChildren(boneChildren.GetPointer(), -1);
    for (int j = 0; j < boneChildren->GetNumberOfItems(); ++j)
      {
      vtkMRMLBoneNode* child =
        vtkMRMLBoneNode::SafeDownCast(boneChildren->GetItemAsObject(j));
      child->Translate(translation);
      }

    // Re-link direct children
    for (int j = 0; j < directBoneChildren->GetNumberOfItems(); ++j)
      {
      vtkMRMLBoneNode* child =
        vtkMRMLBoneNode::SafeDownCast(directBoneChildren->GetItemAsObject(j));
      child->SetBoneLinkedWithParent(wasLinked[j]);
      }

    }

  armature->SetWidgetState(oldState);
  return true;
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper
::AnimateArmature(vtkMRMLArmatureNode* targetArmature,
                  vtkArmatureWidget* animationarmature)
{
  vtkNew<vtkCollection> roots;
  targetArmature->GetDirectChildren(roots.GetPointer());
  if (roots->GetNumberOfItems() != 1)
    {
    std::cerr<<"Cannot resize armature that don't have exactly one root."
      <<std::endl;
    return false;
    }

  targetArmature->ResetPoseMode();
  int oldState = targetArmature->SetWidgetState(vtkMRMLArmatureNode::Pose);

  vtkNew<vtkCollection> targetBones;
  targetArmature->GetAllBones(targetBones.GetPointer());

  // Get correspondence
  CorrespondenceList correspondence;
  if (!vtkMRMLArmatureNodeHelper::GetCorrespondence(
    targetBones.GetPointer(), animationarmature, correspondence))
    {
    return false;
    }

  // Prepare resizing
  std::vector<double> animationSizes;
  for (CorrespondenceList::iterator it = correspondence.begin();
    it < correspondence.end(); ++it)
    {
    animationSizes.push_back(
      vtkMRMLArmatureNodeHelper::GetBoneSize(it->second));
    }

  // Get anim and target origin

  // First move target root to anim root
  vtkMRMLBoneNode* targetRoot =
    vtkMRMLBoneNode::SafeDownCast(roots->GetItemAsObject(0));

  double targetRootHead[3], animRootHead[3];
  targetRoot->GetWorldHeadRest(targetRootHead);
  for (CorrespondenceList::iterator it = correspondence.begin();
    it < correspondence.end(); ++it)
    {
    if (it->first == targetRoot)
      {
      it->second->GetWorldHeadRest(animRootHead);
      break;
      }
    }

  // Scale to animation's size
  std::vector<double> targetDistances;
  bool resizingSuccess =
    vtkMRMLArmatureNodeHelper::ResizeArmature(
      targetArmature, targetBones.GetPointer(),
      animationSizes, animRootHead, &targetDistances);
  if (!resizingSuccess)
    {
    return false;
    }

  // Animate
  if (!vtkMRMLArmatureNodeHelper::AnimateBones(correspondence))
    {
    return false;
    }

  // Resize the armature to its original size
  resizingSuccess =
    vtkMRMLArmatureNodeHelper::ResizeArmature(
      targetArmature, targetBones.GetPointer(),
      targetDistances, targetRootHead);
  if (!resizingSuccess)
    {
    return false;
    }

  targetArmature->SetWidgetState(oldState);

  return true;
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper
::AnimateBones(CorrespondenceList& correspondence)
{
  for (CorrespondenceList::iterator it = correspondence.begin();
    it < correspondence.end(); ++it)
    {
    vtkMRMLBoneNode* targetBone = it->first;
    vtkBoneWidget* animBone = it->second;

    if (!targetBone || !animBone)
      {
      std::cerr<<"All the bones of target bone are expected to be valid "
        <<" vtkMRMLBoneNodes and all the bones of target bone are expected "
        << "to be valid vtkBoneWidget."<<std::endl;
      return false;
      }

    double targetHead[3], targetTail[3];
    targetBone->GetWorldHeadPose(targetHead);
    targetBone->GetWorldTailPose(targetTail);
    double targetDirection[3];
    vtkMath::Subtract(targetTail, targetHead, targetDirection);
    vtkMath::Normalize(targetDirection);

    double animHead[3], animTail[3];
    animBone->GetWorldToParentPoseTranslation(animHead);
    animBone->GetWorldTailPose(animTail);
    double animDirection[3];
    vtkMath::Subtract(animTail, targetHead, animDirection);
    vtkMath::Normalize(animDirection);

    vtkQuaterniond animToTarget =
      vtkBoneWidget::RotationFromReferenceAxis(
        targetDirection, animDirection);

    double axis[3];
    double angle = animToTarget.GetRotationAngleAndAxis(axis);
    targetBone->RotateTailWithWorldWXYZ(angle, axis);

    // Roll ?
    double h[3], diff[3];
    animBone->GetWorldHeadPose(h);
    vtkMath::Subtract(animHead, h, diff);
    bool animBoneIsLinked = (vtkMath::Norm(diff) < 1e-6);
    if (animBoneIsLinked && targetBone->GetBoneLinkedWithParent())
      {
      targetBone->GetWorldHeadPose(targetHead);
      targetBone->GetWorldTailPose(targetTail);
      vtkMath::Subtract(targetTail, targetHead, targetDirection);
      vtkMath::Normalize(targetDirection);

      vtkQuaterniond rollRotation =
        animBone->GetWorldToBonePoseRotation() *
        targetBone->GetWorldToBonePoseRotation().Inverse();

      angle = rollRotation.GetRotationAngleAndAxis(axis);
      targetBone->RotateTailWithWorldWXYZ(angle, targetDirection);
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper
::GetCorrespondence(vtkCollection* targetBones,
                    vtkArmatureWidget* animationArmature,
                    CorrespondenceList& correspondence)
{
  //Get all the bones
  for (int i = 0; i < targetBones->GetNumberOfItems(); ++i)
    {
    vtkMRMLBoneNode* targetBone =
      vtkMRMLBoneNode::SafeDownCast(targetBones->GetItemAsObject(i));
    if (!targetBone)
      {
      std::cerr<<"Could not find correspondence. Stopping."<<std::endl;
      return false;
      }
    correspondence.push_back(
      std::make_pair(targetBone,
        animationArmature->GetBoneByName(targetBone->GetName())));
    }
  return true;
}

//----------------------------------------------------------------------------
void vtkMRMLArmatureNodeHelper::PrintSelf(ostream& os, vtkIndent indent)
{
  Superclass::PrintSelf(os, indent);
}
<commit_msg>Improve failure when using different armatures<commit_after>/*=========================================================================

  Program: Bender

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Bender includes
#include "vtkMRMLArmatureNode.h"
#include "vtkMRMLArmatureNodeHelper.h"
#include "vtkMRMLBoneNode.h"

#include <vtkQuaternion.h>

// Slicer includes
#include <vtkMRMLHierarchyNode.h>

// VTK includes
#include <vtkCollection.h>
#include <vtkMath.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkTransform.h>

// STD includes

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkMRMLArmatureNodeHelper)

//----------------------------------------------------------------------------
double vtkMRMLArmatureNodeHelper::GetBoneSize(vtkMRMLBoneNode* bone)
{
  if (!bone)
    {
    return 0.0;
    }

  double localTail[3];
  bone->GetLocalTailRest(localTail);
  return vtkMath::Norm(localTail);
}

//----------------------------------------------------------------------------
double vtkMRMLArmatureNodeHelper::GetBoneSize(vtkBoneWidget* bone)
{
  if (!bone)
    {
    return 0.0;
    }

  double localTail[3];
  bone->GetLocalTailRest(localTail);
  return vtkMath::Norm(localTail);
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper::ResizeArmature(vtkMRMLArmatureNode* armature,
                                               vtkCollection* bones,
                                               std::vector<double>& sizes,
                                               double origin[3],
                                               std::vector<double>* oldSizes)
{
 // In the general case, bones are like this:
  // ParentTail  -  -  -  -  -  -  Head------Tail
  //           <------Offset------><---Length--->
  //           <--------------Size-------------->
  // We need to scale the target bone size to the size of the anim bone.
  if (!bones || bones->GetNumberOfItems() < 1)
    {
    std::cerr<<"There are no bones in the given armature !"<<std::endl;
    return false;
    }
  if (bones->GetNumberOfItems() != static_cast<int>(sizes.size()))
    {
    std::cerr<<"There should be as many sizes as bone nodes !"<<std::endl;
    return false;
    }

  vtkNew<vtkCollection> roots;
  armature->GetDirectChildren(roots.GetPointer());
  if (roots->GetNumberOfItems() != 1)
    {
    std::cerr<<"Cannot resize armature that don't have exactly one root."
      <<std::endl;
    return false;
    }

  int oldState = armature->SetWidgetState(vtkMRMLArmatureNode::Rest);

  // First move target root to anim root
  vtkMRMLBoneNode* root =
    vtkMRMLBoneNode::SafeDownCast(roots->GetItemAsObject(0));

  double rootHead[3], rootTranslation[3];
  root->GetWorldHeadRest(rootHead);
  vtkMath::Subtract(origin, rootHead, rootTranslation);
  armature->Translate(rootTranslation);

  for (int i = 0; i < bones->GetNumberOfItems(); ++i)
    {
    vtkMRMLBoneNode* bone =
      vtkMRMLBoneNode::SafeDownCast(bones->GetItemAsObject(i));

    // Before anything, save bone size and length
    double size = GetBoneSize(bone);
    if (oldSizes)
      {
      oldSizes->push_back(size);
      }

    // Get bone children
    vtkNew<vtkCollection> directBoneChildren;
    vtkMRMLAnnotationHierarchyNode* hierarchyNode =
      vtkMRMLAnnotationHierarchyNode::SafeDownCast(
        vtkMRMLHierarchyNode::GetAssociatedHierarchyNode(
          bone->GetScene(), bone->GetID()));
    hierarchyNode->GetDirectChildren(directBoneChildren.GetPointer());

    // Unlink from bone children
    std::vector<bool> wasLinked;
    for (int j = 0; j < directBoneChildren->GetNumberOfItems(); ++j)
      {
      vtkMRMLBoneNode* child =
        vtkMRMLBoneNode::SafeDownCast(directBoneChildren->GetItemAsObject(j));
      wasLinked.push_back(child->GetBoneLinkedWithParent());
      child->SetBoneLinkedWithParent(false);
      }

    // Save old tail position
    double oldTargetTail[3];
    bone->GetWorldTailRest(oldTargetTail);

    // Resize bone
    //\todo fixme, root isn't necessary the only top level bone
    bool isTopLevel = (bone == root);
    double newSize = sizes[i];
    if (bone->GetBoneLinkedWithParent() || isTopLevel)
      {
      // Easy case, the bone is linked to its parent (or root).
      // We can just change its length to the new size
      bone->SetLength(newSize);
      }
    else
      {
      // Harder case, the bone isn't linked to its parent (nor root).
      // We need to scale its length and its offset.

      // Get the line vector between the parent's head and head
      double lineVect[3], parentHead[3], head[3];
      bone->GetWorldToParentRestTranslation(parentHead);
      bone->GetWorldHeadRest(head);
      vtkMath::Subtract(head, parentHead, lineVect);
      vtkMath::Normalize(lineVect);

      // Change length
      bone->SetLength((newSize * bone->GetLength()) / size);

      // Change target offset
      vtkMath::MultiplyScalar(lineVect, newSize - bone->GetLength());
      vtkMath::Add(lineVect, parentHead, head);
      bone->SetWorldHeadRest(head);
      }

    // Get translation
    double newTail[3];
    bone->GetWorldTailRest(newTail);
    double translation[3];
    vtkMath::Subtract(newTail, oldTargetTail, translation);

    // Move Bone children
    vtkNew<vtkCollection> boneChildren;
    hierarchyNode->GetChildren(boneChildren.GetPointer(), -1);
    for (int j = 0; j < boneChildren->GetNumberOfItems(); ++j)
      {
      vtkMRMLBoneNode* child =
        vtkMRMLBoneNode::SafeDownCast(boneChildren->GetItemAsObject(j));
      child->Translate(translation);
      }

    // Re-link direct children
    for (int j = 0; j < directBoneChildren->GetNumberOfItems(); ++j)
      {
      vtkMRMLBoneNode* child =
        vtkMRMLBoneNode::SafeDownCast(directBoneChildren->GetItemAsObject(j));
      child->SetBoneLinkedWithParent(wasLinked[j]);
      }

    }

  armature->SetWidgetState(oldState);
  return true;
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper
::AnimateArmature(vtkMRMLArmatureNode* targetArmature,
                  vtkArmatureWidget* animationarmature)
{
  vtkNew<vtkCollection> roots;
  targetArmature->GetDirectChildren(roots.GetPointer());
  if (roots->GetNumberOfItems() != 1)
    {
    std::cerr<<"Cannot resize armature that don't have exactly one root."
      <<std::endl;
    return false;
    }

  vtkNew<vtkCollection> targetBones;
  targetArmature->GetAllBones(targetBones.GetPointer());

  // Get correspondence
  CorrespondenceList correspondence;
  if (!vtkMRMLArmatureNodeHelper::GetCorrespondence(
    targetBones.GetPointer(), animationarmature, correspondence))
    {
    return false;
    }

  targetArmature->ResetPoseMode();
  int oldState = targetArmature->SetWidgetState(vtkMRMLArmatureNode::Pose);
  // Prepare resizing
  std::vector<double> animationSizes;
  for (CorrespondenceList::iterator it = correspondence.begin();
    it < correspondence.end(); ++it)
    {
    animationSizes.push_back(
      vtkMRMLArmatureNodeHelper::GetBoneSize(it->second));
    }

  // Get anim and target origin

  // First move target root to anim root
  vtkMRMLBoneNode* targetRoot =
    vtkMRMLBoneNode::SafeDownCast(roots->GetItemAsObject(0));

  double targetRootHead[3], animRootHead[3];
  targetRoot->GetWorldHeadRest(targetRootHead);
  for (CorrespondenceList::iterator it = correspondence.begin();
    it < correspondence.end(); ++it)
    {
    if (it->first == targetRoot)
      {
      it->second->GetWorldHeadRest(animRootHead);
      break;
      }
    }

  // Scale to animation's size
  std::vector<double> targetDistances;
  bool resizingSuccess =
    vtkMRMLArmatureNodeHelper::ResizeArmature(
      targetArmature, targetBones.GetPointer(),
      animationSizes, animRootHead, &targetDistances);
  if (!resizingSuccess)
    {
    return false;
    }

  // Animate
  if (!vtkMRMLArmatureNodeHelper::AnimateBones(correspondence))
    {
    return false;
    }

  // Resize the armature to its original size
  resizingSuccess =
    vtkMRMLArmatureNodeHelper::ResizeArmature(
      targetArmature, targetBones.GetPointer(),
      targetDistances, targetRootHead);
  if (!resizingSuccess)
    {
    return false;
    }

  targetArmature->SetWidgetState(oldState);

  return true;
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper
::AnimateBones(CorrespondenceList& correspondence)
{
  for (CorrespondenceList::iterator it = correspondence.begin();
    it < correspondence.end(); ++it)
    {
    vtkMRMLBoneNode* targetBone = it->first;
    vtkBoneWidget* animBone = it->second;

    if (!targetBone || !animBone)
      {
      std::cerr<<"All the bones of target bone are expected to be valid "
        <<" vtkMRMLBoneNodes and all the bones of target bone are expected "
        << "to be valid vtkBoneWidget."<<std::endl;
      return false;
      }

    double targetHead[3], targetTail[3];
    targetBone->GetWorldHeadPose(targetHead);
    targetBone->GetWorldTailPose(targetTail);
    double targetDirection[3];
    vtkMath::Subtract(targetTail, targetHead, targetDirection);
    vtkMath::Normalize(targetDirection);

    double animHead[3], animTail[3];
    animBone->GetWorldToParentPoseTranslation(animHead);
    animBone->GetWorldTailPose(animTail);
    double animDirection[3];
    vtkMath::Subtract(animTail, targetHead, animDirection);
    vtkMath::Normalize(animDirection);

    vtkQuaterniond animToTarget =
      vtkBoneWidget::RotationFromReferenceAxis(
        targetDirection, animDirection);

    double axis[3];
    double angle = animToTarget.GetRotationAngleAndAxis(axis);
    targetBone->RotateTailWithWorldWXYZ(angle, axis);

    // Roll ?
    double h[3], diff[3];
    animBone->GetWorldHeadPose(h);
    vtkMath::Subtract(animHead, h, diff);
    bool animBoneIsLinked = (vtkMath::Norm(diff) < 1e-6);
    if (animBoneIsLinked && targetBone->GetBoneLinkedWithParent())
      {
      targetBone->GetWorldHeadPose(targetHead);
      targetBone->GetWorldTailPose(targetTail);
      vtkMath::Subtract(targetTail, targetHead, targetDirection);
      vtkMath::Normalize(targetDirection);

      vtkQuaterniond rollRotation =
        animBone->GetWorldToBonePoseRotation() *
        targetBone->GetWorldToBonePoseRotation().Inverse();

      angle = rollRotation.GetRotationAngleAndAxis(axis);
      targetBone->RotateTailWithWorldWXYZ(angle, targetDirection);
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkMRMLArmatureNodeHelper
::GetCorrespondence(vtkCollection* targetBones,
                    vtkArmatureWidget* animationArmature,
                    CorrespondenceList& correspondence)
{
  //Get all the bones
  for (int i = 0; i < targetBones->GetNumberOfItems(); ++i)
    {
    vtkMRMLBoneNode* targetBone =
      vtkMRMLBoneNode::SafeDownCast(targetBones->GetItemAsObject(i));
    if (!targetBone)
      {
      std::cerr<<"Could not find correspondence. Stopping."<<std::endl;
      return false;
      }
    vtkBoneWidget* correspondingBone =
      animationArmature->GetBoneByName(targetBone->GetName());
    if (!correspondingBone)
      {
      std::cerr<<"Could not find matching bone for "
        <<targetBone->GetName()<<". Stopping."<<std::endl;
      return false;
      }

    correspondence.push_back(std::make_pair(targetBone, correspondingBone));
    }
  return true;
}

//----------------------------------------------------------------------------
void vtkMRMLArmatureNodeHelper::PrintSelf(ostream& os, vtkIndent indent)
{
  Superclass::PrintSelf(os, indent);
}
<|endoftext|>


<commit_before>/*********************************************************************
** Author: Zach Colbert
** Date: 18 October 2017
** Description: Defines a function to find the vertical displacement of a falling body in a given time.
*********************************************************************/

/*********************************************************************
Testing section MUST BE REMOVED OR COMMENTED BEFORE SUBMISSION
*********************************************************************/
double fallDistance(double time);

int main()
{
    // Don't write the actual code here! Use this to call the real function.
    return 0;
}
/*********************************************************************
End testing section
*********************************************************************/

// Description
double fallDistance(double time)
{
    // The actual code goes here.
}<commit_msg>Working copy ready to be tested<commit_after>/*********************************************************************
** Author: Zach Colbert
** Date: 18 October 2017
** Description: Defines a function to find the vertical displacement of a falling body in a given time.
*********************************************************************/

// For std::pow()
#include <cmath>

/*********************************************************************
Testing section MUST BE REMOVED OR COMMENTED BEFORE SUBMISSION
*********************************************************************/
// For testing
#include <iostream>

using std::cout;
using std::cin;
using std::endl;

double fallDistance(double time);

int main()
{
    // Declare a variable for the test input
    double testInput;

    // Get a time from the command line
    cout << "Enter a time falling:" << endl;
    cin >> testInput;

    // Print the result of the fallDistance function
    cout << "The displacement is " << fallDistance(testInput) << "m" << endl;

    return 0;
}
/*********************************************************************
End testing section
*********************************************************************/

// The function takes a time as its argument, and returns the vertical displacement of a body falling from rest over that time.
double fallDistance(double time)
{
    // One-liner: Calculate the displacement
    double displacement = 0.5*9.8*std::pow(time,2);

    // Return the displacement
    return displacement;
}<|endoftext|>


<commit_before><commit_msg>Add members to initialization list<commit_after><|endoftext|>


<commit_before>#include "cmdlinetask.h"

WARNINGS_DISABLE
#include <QChar>
#include <QProcess>
#include <QStandardPaths>
WARNINGS_ENABLE

#include "utils.h"

#include <ConsoleLog.h>

#include <signal.h>

#define DEFAULT_TIMEOUT_MS 5000
#define LOG_MAX_LENGTH 3072
#define LOG_MAX_SEARCH_NL 1024

CmdlineTask::CmdlineTask()
    : BaseTask(),
      _process(nullptr),
      _exitCode(EXIT_NO_MEANING),
      _truncateLogOutput(false)
{
}

CmdlineTask::~CmdlineTask()
{
}

void CmdlineTask::run()
{
    Q_ASSERT(_process == nullptr);

    // Set up new _process
    _process = new QProcess();
    _process->setProgram(_command);
    _process->setArguments(_arguments);
    if(!_stdOutFilename.isEmpty())
        _process->setStandardOutputFile(_stdOutFilename);

    LOG << tr("Task %1 started:\n[%2 %3]\n")
               .arg(_uuid.toString())
               .arg(_process->program())
               .arg(Utils::quoteCommandLine(_process->arguments()));

#ifdef QT_TESTLIB_LIB
    // Bail if desired.  Make sure this happens before we check if the
    // command exists, otherwise we might bail for the wrong reason.
    if(_fake)
    {
        LOG << "Not running task due to 'fake this task' request.\n";
        _fake = false;
        emit started(_data);
        emit finished(_data, EXIT_FAKE_REQUEST, "", "");
        goto cleanup;
    }
#endif

    // Make sure that the command exists and is executable, because QProcess
    // doesn't clean up its memory if it fails due to "command not found".
    if(QStandardPaths::findExecutable(_command).isEmpty())
    {
        LOG << QString("Command '%1' not found\n").arg(_command);
        emit finished(_data, EXIT_CMD_NOT_FOUND, "", "");
        goto cleanup;
    }

    // Start the _process, and wait for confirmation of it starting.
    _process->start();
    if(_process->waitForStarted(DEFAULT_TIMEOUT_MS))
    {
        emit started(_data);
    }
    else
    {
        _exitCode = EXIT_DID_NOT_START;
        processError(_process);
        goto cleanup;
    }

    // Write to the process' stdin.
    if(!_stdIn.isEmpty())
    {
        _process->write(_stdIn.data(), _stdIn.size());
        _process->closeWriteChannel();
    }

    // Wait indefinitely for the process to finish
    if(_process->waitForFinished(-1))
    {
        readProcessOutput(_process);
        processFinished(_process);
    }
    else
    {
        readProcessOutput(_process);
        processError(_process);
        goto cleanup;
    }

cleanup:
    delete _process;
    _process = nullptr;
    emit dequeue();
}

void CmdlineTask::stop()
{
    // Bail if the TaskManager has recorded this as "started" but it
    // hasn't actually begun yet.  See taskqueuer.cpp for the explanation.
    if(_process == nullptr)
        return;

    if(_process->state() == QProcess::Running)
        _process->terminate();
}

void CmdlineTask::sigquit()
{
    // Bail if the TaskManager has recorded this as "started" but it
    // hasn't actually begun yet.  See taskqueuer.cpp for the explanation.
    if(_process == nullptr)
        return;

    // Assume that Q_PID is a valid pid on this system.
    pid_t pid = static_cast<pid_t>(_process->pid());
    // If this is sent to the Tarsnap client creating an archive, it will
    // truncate it and leave a '.part' partial archive.
    kill(pid, SIGQUIT);
}

QString CmdlineTask::command() const
{
    return _command;
}

void CmdlineTask::setCommand(const QString &command)
{
    _command = command;
}

QStringList CmdlineTask::arguments() const
{
    return _arguments;
}

void CmdlineTask::setArguments(const QStringList &arguments)
{
    _arguments = arguments;
}

void CmdlineTask::setStdIn(const QString &standardIn)
{
    _stdIn = QByteArray(standardIn.toUtf8());
}

void CmdlineTask::setStdOutFile(const QString &fileName)
{
    _stdOutFilename = fileName;
}

QVariant CmdlineTask::data() const
{
    return _data;
}

void CmdlineTask::setData(const QVariant &data)
{
    _data = data;
}

void CmdlineTask::setTruncateLogOutput(bool truncateLogOutput)
{
    _truncateLogOutput = truncateLogOutput;
}

void CmdlineTask::readProcessOutput(QProcess *process)
{
    if(_stdOutFilename.isEmpty())
        _stdOut.append(process->readAllStandardOutput().trimmed());
    _stdErr.append(process->readAllStandardError().trimmed());
}

QByteArray CmdlineTask::truncate_output(QByteArray stdOut)
{
    // Find a good newline to which to truncate.
    int from = LOG_MAX_LENGTH
               + std::min(stdOut.size() - LOG_MAX_LENGTH, LOG_MAX_SEARCH_NL);
    int nextNL = stdOut.lastIndexOf(QChar('\n'), from);
    // Only keep the first part of the logfile.
    stdOut.truncate(std::max(LOG_MAX_LENGTH, nextNL));
    // Notify about truncation in log.
    int num_truncated = _stdOut.mid(stdOut.size()).count('\n');
    stdOut.append(tr("\n...\n-- %1 output lines truncated by Tarsnap GUI --\n")
                      .arg(num_truncated));
    return stdOut;
}

void CmdlineTask::processFinished(QProcess *process)
{
    switch(process->exitStatus())
    {
    case QProcess::NormalExit:
    {
        _exitCode = process->exitCode();
        emit finished(_data, _exitCode, QString(_stdOut), QString(_stdErr));

        // Truncate LOG output
        QByteArray stdOut(_stdOut);
        if(_truncateLogOutput && (stdOut.size() > LOG_MAX_LENGTH))
            stdOut = truncate_output(stdOut);

        LOG << tr("Task %1 finished with exit code %2:\n[%3 %4]\n%5\n")
                   .arg(_uuid.toString())
                   .arg(_exitCode)
                   .arg(_command)
                   .arg(Utils::quoteCommandLine(_arguments))
                   .arg(QString(stdOut + _stdErr));
        break;
    }
    case QProcess::CrashExit:
    {
        _exitCode = EXIT_CRASHED;
        processError(process);
        break;
    }
    }
}

void CmdlineTask::processError(QProcess *process)
{
    LOG << tr("Task %1 finished with error %2 (%3) occured "
              "(exit code %4):\n[%5 %6]\n%7\n")
               .arg(_uuid.toString())
               .arg(process->error())
               .arg(process->errorString())
               .arg(_exitCode)
               .arg(_command)
               .arg(Utils::quoteCommandLine(_arguments))
               .arg(QString(_stdOut + _stdErr).trimmed());
    emit finished(_data, _exitCode, QString(_stdOut), QString(_stdErr));
    emit canceled();
}
<commit_msg>CmdlineTask: use qMax() and qMin()<commit_after>#include "cmdlinetask.h"

WARNINGS_DISABLE
#include <QChar>
#include <QProcess>
#include <QStandardPaths>
WARNINGS_ENABLE

#include "utils.h"

#include <ConsoleLog.h>

#include <signal.h>

#define DEFAULT_TIMEOUT_MS 5000
#define LOG_MAX_LENGTH 3072
#define LOG_MAX_SEARCH_NL 1024

CmdlineTask::CmdlineTask()
    : BaseTask(),
      _process(nullptr),
      _exitCode(EXIT_NO_MEANING),
      _truncateLogOutput(false)
{
}

CmdlineTask::~CmdlineTask()
{
}

void CmdlineTask::run()
{
    Q_ASSERT(_process == nullptr);

    // Set up new _process
    _process = new QProcess();
    _process->setProgram(_command);
    _process->setArguments(_arguments);
    if(!_stdOutFilename.isEmpty())
        _process->setStandardOutputFile(_stdOutFilename);

    LOG << tr("Task %1 started:\n[%2 %3]\n")
               .arg(_uuid.toString())
               .arg(_process->program())
               .arg(Utils::quoteCommandLine(_process->arguments()));

#ifdef QT_TESTLIB_LIB
    // Bail if desired.  Make sure this happens before we check if the
    // command exists, otherwise we might bail for the wrong reason.
    if(_fake)
    {
        LOG << "Not running task due to 'fake this task' request.\n";
        _fake = false;
        emit started(_data);
        emit finished(_data, EXIT_FAKE_REQUEST, "", "");
        goto cleanup;
    }
#endif

    // Make sure that the command exists and is executable, because QProcess
    // doesn't clean up its memory if it fails due to "command not found".
    if(QStandardPaths::findExecutable(_command).isEmpty())
    {
        LOG << QString("Command '%1' not found\n").arg(_command);
        emit finished(_data, EXIT_CMD_NOT_FOUND, "", "");
        goto cleanup;
    }

    // Start the _process, and wait for confirmation of it starting.
    _process->start();
    if(_process->waitForStarted(DEFAULT_TIMEOUT_MS))
    {
        emit started(_data);
    }
    else
    {
        _exitCode = EXIT_DID_NOT_START;
        processError(_process);
        goto cleanup;
    }

    // Write to the process' stdin.
    if(!_stdIn.isEmpty())
    {
        _process->write(_stdIn.data(), _stdIn.size());
        _process->closeWriteChannel();
    }

    // Wait indefinitely for the process to finish
    if(_process->waitForFinished(-1))
    {
        readProcessOutput(_process);
        processFinished(_process);
    }
    else
    {
        readProcessOutput(_process);
        processError(_process);
        goto cleanup;
    }

cleanup:
    delete _process;
    _process = nullptr;
    emit dequeue();
}

void CmdlineTask::stop()
{
    // Bail if the TaskManager has recorded this as "started" but it
    // hasn't actually begun yet.  See taskqueuer.cpp for the explanation.
    if(_process == nullptr)
        return;

    if(_process->state() == QProcess::Running)
        _process->terminate();
}

void CmdlineTask::sigquit()
{
    // Bail if the TaskManager has recorded this as "started" but it
    // hasn't actually begun yet.  See taskqueuer.cpp for the explanation.
    if(_process == nullptr)
        return;

    // Assume that Q_PID is a valid pid on this system.
    pid_t pid = static_cast<pid_t>(_process->pid());
    // If this is sent to the Tarsnap client creating an archive, it will
    // truncate it and leave a '.part' partial archive.
    kill(pid, SIGQUIT);
}

QString CmdlineTask::command() const
{
    return _command;
}

void CmdlineTask::setCommand(const QString &command)
{
    _command = command;
}

QStringList CmdlineTask::arguments() const
{
    return _arguments;
}

void CmdlineTask::setArguments(const QStringList &arguments)
{
    _arguments = arguments;
}

void CmdlineTask::setStdIn(const QString &standardIn)
{
    _stdIn = QByteArray(standardIn.toUtf8());
}

void CmdlineTask::setStdOutFile(const QString &fileName)
{
    _stdOutFilename = fileName;
}

QVariant CmdlineTask::data() const
{
    return _data;
}

void CmdlineTask::setData(const QVariant &data)
{
    _data = data;
}

void CmdlineTask::setTruncateLogOutput(bool truncateLogOutput)
{
    _truncateLogOutput = truncateLogOutput;
}

void CmdlineTask::readProcessOutput(QProcess *process)
{
    if(_stdOutFilename.isEmpty())
        _stdOut.append(process->readAllStandardOutput().trimmed());
    _stdErr.append(process->readAllStandardError().trimmed());
}

QByteArray CmdlineTask::truncate_output(QByteArray stdOut)
{
    // Find a good newline to which to truncate.
    int from = LOG_MAX_LENGTH
               + qMin(stdOut.size() - LOG_MAX_LENGTH, LOG_MAX_SEARCH_NL);
    int nextNL = stdOut.lastIndexOf(QChar('\n'), from);
    // Only keep the first part of the logfile.
    stdOut.truncate(qMax(LOG_MAX_LENGTH, nextNL));
    // Notify about truncation in log.
    int num_truncated = _stdOut.mid(stdOut.size()).count('\n');
    stdOut.append(tr("\n...\n-- %1 output lines truncated by Tarsnap GUI --\n")
                      .arg(num_truncated));
    return stdOut;
}

void CmdlineTask::processFinished(QProcess *process)
{
    switch(process->exitStatus())
    {
    case QProcess::NormalExit:
    {
        _exitCode = process->exitCode();
        emit finished(_data, _exitCode, QString(_stdOut), QString(_stdErr));

        // Truncate LOG output
        QByteArray stdOut(_stdOut);
        if(_truncateLogOutput && (stdOut.size() > LOG_MAX_LENGTH))
            stdOut = truncate_output(stdOut);

        LOG << tr("Task %1 finished with exit code %2:\n[%3 %4]\n%5\n")
                   .arg(_uuid.toString())
                   .arg(_exitCode)
                   .arg(_command)
                   .arg(Utils::quoteCommandLine(_arguments))
                   .arg(QString(stdOut + _stdErr));
        break;
    }
    case QProcess::CrashExit:
    {
        _exitCode = EXIT_CRASHED;
        processError(process);
        break;
    }
    }
}

void CmdlineTask::processError(QProcess *process)
{
    LOG << tr("Task %1 finished with error %2 (%3) occured "
              "(exit code %4):\n[%5 %6]\n%7\n")
               .arg(_uuid.toString())
               .arg(process->error())
               .arg(process->errorString())
               .arg(_exitCode)
               .arg(_command)
               .arg(Utils::quoteCommandLine(_arguments))
               .arg(QString(_stdOut + _stdErr).trimmed());
    emit finished(_data, _exitCode, QString(_stdOut), QString(_stdErr));
    emit canceled();
}
<|endoftext|>


<commit_before>#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "clone.h"
#include "clientmodel.h"
#include "clientversion.h"

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(
        tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers") + QString(",
") +
        tr("Copyright") + QString(" © 2014 ") + tr("The " + FIRSTCASENAME + " developers"));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<commit_msg>Update aboutdialog.cpp<commit_after>#include "aboutdialog.h"
#include "ui_aboutdialog.h"
//#include "clone.h"
#include "clientmodel.h"
#include "clientversion.h"

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(
        tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers") + QString(",
") +
        tr("Copyright") + QString(" © 2014 ") + tr("The Dirac developers"));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "clientmodel.h"

#include "bantablemodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "peertablemodel.h"

#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
#include "config.h"
#include "net.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
#include "validation.h"
#include "warnings.h"

#include <cstdint>

#include <QDebug>
#include <QTimer>

class CBlockIndex;

static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;

ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent)
    : QObject(parent), optionsModel(_optionsModel), peerTableModel(0),
      banTableModel(0), pollTimer(0) {
    cachedBestHeaderHeight = -1;
    cachedBestHeaderTime = -1;
    peerTableModel = new PeerTableModel(this);
    banTableModel = new BanTableModel(this);
    pollTimer = new QTimer(this);
    connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
    pollTimer->start(MODEL_UPDATE_DELAY);

    subscribeToCoreSignals();
}

ClientModel::~ClientModel() {
    unsubscribeFromCoreSignals();
}

int ClientModel::getNumConnections(unsigned int flags) const {
    CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;

    if (flags == CONNECTIONS_IN)
        connections = CConnman::CONNECTIONS_IN;
    else if (flags == CONNECTIONS_OUT)
        connections = CConnman::CONNECTIONS_OUT;
    else if (flags == CONNECTIONS_ALL)
        connections = CConnman::CONNECTIONS_ALL;

    if (g_connman) return g_connman->GetNodeCount(connections);
    return 0;
}

int ClientModel::getNumBlocks() const {
    LOCK(cs_main);
    return chainActive.Height();
}

int ClientModel::getHeaderTipHeight() const {
    if (cachedBestHeaderHeight == -1) {
        // make sure we initially populate the cache via a cs_main lock
        // otherwise we need to wait for a tip update
        LOCK(cs_main);
        if (pindexBestHeader) {
            cachedBestHeaderHeight = pindexBestHeader->nHeight;
            cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
        }
    }
    return cachedBestHeaderHeight;
}

int64_t ClientModel::getHeaderTipTime() const {
    if (cachedBestHeaderTime == -1) {
        LOCK(cs_main);
        if (pindexBestHeader) {
            cachedBestHeaderHeight = pindexBestHeader->nHeight;
            cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
        }
    }
    return cachedBestHeaderTime;
}

quint64 ClientModel::getTotalBytesRecv() const {
    if (!g_connman) return 0;
    return g_connman->GetTotalBytesRecv();
}

quint64 ClientModel::getTotalBytesSent() const {
    if (!g_connman) return 0;
    return g_connman->GetTotalBytesSent();
}

QDateTime ClientModel::getLastBlockDate() const {
    LOCK(cs_main);

    if (chainActive.Tip())
        return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());

    // Genesis block's time of current network
    return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime());
}

long ClientModel::getMempoolSize() const {
    return g_mempool.size();
}

size_t ClientModel::getMempoolDynamicUsage() const {
    return g_mempool.DynamicMemoryUsage();
}

double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const {
    CBlockIndex *tip = const_cast<CBlockIndex *>(tipIn);
    if (!tip) {
        LOCK(cs_main);
        tip = chainActive.Tip();
    }
    return GuessVerificationProgress(Params().TxData(), tip);
}

void ClientModel::updateTimer() {
    // no locking required at this point
    // the following calls will acquire the required lock
    Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage());
    Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}

void ClientModel::updateNumConnections(int numConnections) {
    Q_EMIT numConnectionsChanged(numConnections);
}

void ClientModel::updateNetworkActive(bool networkActive) {
    Q_EMIT networkActiveChanged(networkActive);
}

void ClientModel::updateAlert() {
    Q_EMIT alertsChanged(getStatusBarWarnings());
}

bool ClientModel::inInitialBlockDownload() const {
    return IsInitialBlockDownload();
}

enum BlockSource ClientModel::getBlockSource() const {
    if (fReindex)
        return BlockSource::REINDEX;
    else if (fImporting)
        return BlockSource::DISK;
    else if (getNumConnections() > 0)
        return BlockSource::NETWORK;

    return BlockSource::NONE;
}

void ClientModel::setNetworkActive(bool active) {
    if (g_connman) {
        g_connman->SetNetworkActive(active);
    }
}

bool ClientModel::getNetworkActive() const {
    if (g_connman) {
        return g_connman->GetNetworkActive();
    }
    return false;
}

QString ClientModel::getStatusBarWarnings() const {
    return QString::fromStdString(GetWarnings("gui"));
}

OptionsModel *ClientModel::getOptionsModel() {
    return optionsModel;
}

PeerTableModel *ClientModel::getPeerTableModel() {
    return peerTableModel;
}

BanTableModel *ClientModel::getBanTableModel() {
    return banTableModel;
}

QString ClientModel::formatFullVersion() const {
    return QString::fromStdString(FormatFullVersion());
}

QString ClientModel::formatSubVersion() const {
    return QString::fromStdString(userAgent(GetConfig()));
}

bool ClientModel::isReleaseVersion() const {
    return CLIENT_VERSION_IS_RELEASE;
}

QString ClientModel::formatClientStartupTime() const {
    return QDateTime::fromTime_t(GetStartupTime()).toString();
}

QString ClientModel::dataDir() const {
    return GUIUtil::boostPathToQString(GetDataDir());
}

void ClientModel::updateBanlist() {
    banTableModel->refresh();
}

// Handlers for core signals
static void ShowProgress(ClientModel *clientmodel, const std::string &title,
                         int nProgress) {
    // emits signal "showProgress"
    QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(title)),
                              Q_ARG(int, nProgress));
}

static void NotifyNumConnectionsChanged(ClientModel *clientmodel,
                                        int newNumConnections) {
    // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " +
    // QString::number(newNumConnections);
    QMetaObject::invokeMethod(clientmodel, "updateNumConnections",
                              Qt::QueuedConnection,
                              Q_ARG(int, newNumConnections));
}

static void NotifyNetworkActiveChanged(ClientModel *clientmodel,
                                       bool networkActive) {
    QMetaObject::invokeMethod(clientmodel, "updateNetworkActive",
                              Qt::QueuedConnection, Q_ARG(bool, networkActive));
}

static void NotifyAlertChanged(ClientModel *clientmodel) {
    qDebug() << "NotifyAlertChanged";
    QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
}

static void BannedListChanged(ClientModel *clientmodel) {
    qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
    QMetaObject::invokeMethod(clientmodel, "updateBanlist",
                              Qt::QueuedConnection);
}

static void BlockTipChanged(ClientModel *clientmodel, bool initialSync,
                            const CBlockIndex *pIndex, bool fHeader) {
    // lock free async UI updates in case we have a new block tip
    // during initial sync, only update the UI if the last update
    // was > 250ms (MODEL_UPDATE_DELAY) ago
    int64_t now = 0;
    if (initialSync) now = GetTimeMillis();

    int64_t &nLastUpdateNotification = fHeader
                                           ? nLastHeaderTipUpdateNotification
                                           : nLastBlockTipUpdateNotification;

    if (fHeader) {
        // cache best headers time and height to reduce future cs_main locks
        clientmodel->cachedBestHeaderHeight = pIndex->nHeight;
        clientmodel->cachedBestHeaderTime = pIndex->GetBlockTime();
    }
    // if we are in-sync, update the UI regardless of last update time
    if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
        // pass a async signal to the UI thread
        QMetaObject::invokeMethod(
            clientmodel, "numBlocksChanged", Qt::QueuedConnection,
            Q_ARG(int, pIndex->nHeight),
            Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())),
            Q_ARG(double, clientmodel->getVerificationProgress(pIndex)),
            Q_ARG(bool, fHeader));
        nLastUpdateNotification = now;
    }
}

void ClientModel::subscribeToCoreSignals() {
    // Connect signals to client
    uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
    uiInterface.NotifyNumConnectionsChanged.connect(
        boost::bind(NotifyNumConnectionsChanged, this, _1));
    uiInterface.NotifyNetworkActiveChanged.connect(
        boost::bind(NotifyNetworkActiveChanged, this, _1));
    uiInterface.NotifyAlertChanged.connect(
        boost::bind(NotifyAlertChanged, this));
    uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
    uiInterface.NotifyBlockTip.connect(
        boost::bind(BlockTipChanged, this, _1, _2, false));
    uiInterface.NotifyHeaderTip.connect(
        boost::bind(BlockTipChanged, this, _1, _2, true));
}

void ClientModel::unsubscribeFromCoreSignals() {
    // Disconnect signals from client
    uiInterface.ShowProgress.disconnect(
        boost::bind(ShowProgress, this, _1, _2));
    uiInterface.NotifyNumConnectionsChanged.disconnect(
        boost::bind(NotifyNumConnectionsChanged, this, _1));
    uiInterface.NotifyNetworkActiveChanged.disconnect(
        boost::bind(NotifyNetworkActiveChanged, this, _1));
    uiInterface.NotifyAlertChanged.disconnect(
        boost::bind(NotifyAlertChanged, this));
    uiInterface.BannedListChanged.disconnect(
        boost::bind(BannedListChanged, this));
    uiInterface.NotifyBlockTip.disconnect(
        boost::bind(BlockTipChanged, this, _1, _2, false));
    uiInterface.NotifyHeaderTip.disconnect(
        boost::bind(BlockTipChanged, this, _1, _2, true));
}
<commit_msg>Fix braces in qt/clientmodel.cpp<commit_after>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "clientmodel.h"

#include "bantablemodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "peertablemodel.h"

#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
#include "config.h"
#include "net.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
#include "validation.h"
#include "warnings.h"

#include <cstdint>

#include <QDebug>
#include <QTimer>

class CBlockIndex;

static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;

ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent)
    : QObject(parent), optionsModel(_optionsModel), peerTableModel(0),
      banTableModel(0), pollTimer(0) {
    cachedBestHeaderHeight = -1;
    cachedBestHeaderTime = -1;
    peerTableModel = new PeerTableModel(this);
    banTableModel = new BanTableModel(this);
    pollTimer = new QTimer(this);
    connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
    pollTimer->start(MODEL_UPDATE_DELAY);

    subscribeToCoreSignals();
}

ClientModel::~ClientModel() {
    unsubscribeFromCoreSignals();
}

int ClientModel::getNumConnections(unsigned int flags) const {
    CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;

    if (flags == CONNECTIONS_IN) {
        connections = CConnman::CONNECTIONS_IN;
    } else if (flags == CONNECTIONS_OUT) {
        connections = CConnman::CONNECTIONS_OUT;
    } else if (flags == CONNECTIONS_ALL) {
        connections = CConnman::CONNECTIONS_ALL;
    }

    if (g_connman) {
        return g_connman->GetNodeCount(connections);
    }
    return 0;
}

int ClientModel::getNumBlocks() const {
    LOCK(cs_main);
    return chainActive.Height();
}

int ClientModel::getHeaderTipHeight() const {
    if (cachedBestHeaderHeight == -1) {
        // make sure we initially populate the cache via a cs_main lock
        // otherwise we need to wait for a tip update
        LOCK(cs_main);
        if (pindexBestHeader) {
            cachedBestHeaderHeight = pindexBestHeader->nHeight;
            cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
        }
    }
    return cachedBestHeaderHeight;
}

int64_t ClientModel::getHeaderTipTime() const {
    if (cachedBestHeaderTime == -1) {
        LOCK(cs_main);
        if (pindexBestHeader) {
            cachedBestHeaderHeight = pindexBestHeader->nHeight;
            cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
        }
    }
    return cachedBestHeaderTime;
}

quint64 ClientModel::getTotalBytesRecv() const {
    if (!g_connman) {
        return 0;
    }
    return g_connman->GetTotalBytesRecv();
}

quint64 ClientModel::getTotalBytesSent() const {
    if (!g_connman) {
        return 0;
    }
    return g_connman->GetTotalBytesSent();
}

QDateTime ClientModel::getLastBlockDate() const {
    LOCK(cs_main);

    if (chainActive.Tip()) {
        return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
    }

    // Genesis block's time of current network
    return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime());
}

long ClientModel::getMempoolSize() const {
    return g_mempool.size();
}

size_t ClientModel::getMempoolDynamicUsage() const {
    return g_mempool.DynamicMemoryUsage();
}

double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const {
    CBlockIndex *tip = const_cast<CBlockIndex *>(tipIn);
    if (!tip) {
        LOCK(cs_main);
        tip = chainActive.Tip();
    }
    return GuessVerificationProgress(Params().TxData(), tip);
}

void ClientModel::updateTimer() {
    // no locking required at this point
    // the following calls will acquire the required lock
    Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage());
    Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}

void ClientModel::updateNumConnections(int numConnections) {
    Q_EMIT numConnectionsChanged(numConnections);
}

void ClientModel::updateNetworkActive(bool networkActive) {
    Q_EMIT networkActiveChanged(networkActive);
}

void ClientModel::updateAlert() {
    Q_EMIT alertsChanged(getStatusBarWarnings());
}

bool ClientModel::inInitialBlockDownload() const {
    return IsInitialBlockDownload();
}

enum BlockSource ClientModel::getBlockSource() const {
    if (fReindex) {
        return BlockSource::REINDEX;
    } else if (fImporting) {
        return BlockSource::DISK;
    } else if (getNumConnections() > 0) {
        return BlockSource::NETWORK;
    }

    return BlockSource::NONE;
}

void ClientModel::setNetworkActive(bool active) {
    if (g_connman) {
        g_connman->SetNetworkActive(active);
    }
}

bool ClientModel::getNetworkActive() const {
    if (g_connman) {
        return g_connman->GetNetworkActive();
    }
    return false;
}

QString ClientModel::getStatusBarWarnings() const {
    return QString::fromStdString(GetWarnings("gui"));
}

OptionsModel *ClientModel::getOptionsModel() {
    return optionsModel;
}

PeerTableModel *ClientModel::getPeerTableModel() {
    return peerTableModel;
}

BanTableModel *ClientModel::getBanTableModel() {
    return banTableModel;
}

QString ClientModel::formatFullVersion() const {
    return QString::fromStdString(FormatFullVersion());
}

QString ClientModel::formatSubVersion() const {
    return QString::fromStdString(userAgent(GetConfig()));
}

bool ClientModel::isReleaseVersion() const {
    return CLIENT_VERSION_IS_RELEASE;
}

QString ClientModel::formatClientStartupTime() const {
    return QDateTime::fromTime_t(GetStartupTime()).toString();
}

QString ClientModel::dataDir() const {
    return GUIUtil::boostPathToQString(GetDataDir());
}

void ClientModel::updateBanlist() {
    banTableModel->refresh();
}

// Handlers for core signals
static void ShowProgress(ClientModel *clientmodel, const std::string &title,
                         int nProgress) {
    // emits signal "showProgress"
    QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(title)),
                              Q_ARG(int, nProgress));
}

static void NotifyNumConnectionsChanged(ClientModel *clientmodel,
                                        int newNumConnections) {
    // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " +
    // QString::number(newNumConnections);
    QMetaObject::invokeMethod(clientmodel, "updateNumConnections",
                              Qt::QueuedConnection,
                              Q_ARG(int, newNumConnections));
}

static void NotifyNetworkActiveChanged(ClientModel *clientmodel,
                                       bool networkActive) {
    QMetaObject::invokeMethod(clientmodel, "updateNetworkActive",
                              Qt::QueuedConnection, Q_ARG(bool, networkActive));
}

static void NotifyAlertChanged(ClientModel *clientmodel) {
    qDebug() << "NotifyAlertChanged";
    QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
}

static void BannedListChanged(ClientModel *clientmodel) {
    qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
    QMetaObject::invokeMethod(clientmodel, "updateBanlist",
                              Qt::QueuedConnection);
}

static void BlockTipChanged(ClientModel *clientmodel, bool initialSync,
                            const CBlockIndex *pIndex, bool fHeader) {
    // lock free async UI updates in case we have a new block tip
    // during initial sync, only update the UI if the last update
    // was > 250ms (MODEL_UPDATE_DELAY) ago
    int64_t now = 0;
    if (initialSync) {
        now = GetTimeMillis();
    }

    int64_t &nLastUpdateNotification = fHeader
                                           ? nLastHeaderTipUpdateNotification
                                           : nLastBlockTipUpdateNotification;

    if (fHeader) {
        // cache best headers time and height to reduce future cs_main locks
        clientmodel->cachedBestHeaderHeight = pIndex->nHeight;
        clientmodel->cachedBestHeaderTime = pIndex->GetBlockTime();
    }
    // if we are in-sync, update the UI regardless of last update time
    if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
        // pass a async signal to the UI thread
        QMetaObject::invokeMethod(
            clientmodel, "numBlocksChanged", Qt::QueuedConnection,
            Q_ARG(int, pIndex->nHeight),
            Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())),
            Q_ARG(double, clientmodel->getVerificationProgress(pIndex)),
            Q_ARG(bool, fHeader));
        nLastUpdateNotification = now;
    }
}

void ClientModel::subscribeToCoreSignals() {
    // Connect signals to client
    uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
    uiInterface.NotifyNumConnectionsChanged.connect(
        boost::bind(NotifyNumConnectionsChanged, this, _1));
    uiInterface.NotifyNetworkActiveChanged.connect(
        boost::bind(NotifyNetworkActiveChanged, this, _1));
    uiInterface.NotifyAlertChanged.connect(
        boost::bind(NotifyAlertChanged, this));
    uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
    uiInterface.NotifyBlockTip.connect(
        boost::bind(BlockTipChanged, this, _1, _2, false));
    uiInterface.NotifyHeaderTip.connect(
        boost::bind(BlockTipChanged, this, _1, _2, true));
}

void ClientModel::unsubscribeFromCoreSignals() {
    // Disconnect signals from client
    uiInterface.ShowProgress.disconnect(
        boost::bind(ShowProgress, this, _1, _2));
    uiInterface.NotifyNumConnectionsChanged.disconnect(
        boost::bind(NotifyNumConnectionsChanged, this, _1));
    uiInterface.NotifyNetworkActiveChanged.disconnect(
        boost::bind(NotifyNetworkActiveChanged, this, _1));
    uiInterface.NotifyAlertChanged.disconnect(
        boost::bind(NotifyAlertChanged, this));
    uiInterface.BannedListChanged.disconnect(
        boost::bind(BannedListChanged, this));
    uiInterface.NotifyBlockTip.disconnect(
        boost::bind(BlockTipChanged, this, _1, _2, false));
    uiInterface.NotifyHeaderTip.disconnect(
        boost::bind(BlockTipChanged, this, _1, _2, true));
}
<|endoftext|>


<commit_before>#include "marketmodel.h"

#include <QHBoxLayout>
#include <QList>
#include <QWidget>
#include <sstream>

#include "marketgraphwidget.h"
#include "txdb.h"
#include "wallet.h"
#include "walletmodel.h"

extern CMarketTreeDB *pmarkettree;

// Private implementation
class MarketModelPriv
{
public:
    MarketModelPriv(CWallet *wallet, MarketModel *parent)
        : wallet(wallet),
          parent(parent)
    {
    }

    CWallet *wallet;
    MarketModel *parent;

    QList<const marketMarket *> cached;

    int size()
    {
        return cached.size();
    }

    const marketMarket *index(int idx)
    {
        if(idx >= 0 && idx < cached.size())
            return cached[idx];
        return 0;
    }
};

MarketModel::MarketModel(CWallet *wallet, WalletModel *parent) :
   QAbstractTableModel(parent),
   wallet(wallet),
   walletModel(parent),
   priv(new MarketModelPriv(wallet, this))
{
}

MarketModel::~MarketModel()
{
    delete priv;
}

int MarketModel::rowCount(const QModelIndex & /*parent*/) const
{
   return priv->size();
}

int MarketModel::columnCount(const QModelIndex & /*parent*/) const
{
    return 2;
}

QVariant MarketModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return false;
    }

    int row = index.row();
    int col = index.column();

    const marketMarket *market = priv->index(row);

    switch(role) {
    case Qt::DisplayRole:
    {
        // Market Details
        if (col == 1) {
            std::stringstream sstream;
            sstream << "Title: " << market->title << std::endl;
            sstream << "Description: " << market->description << std::endl;
            sstream << "Tags: " << market->tags << std::endl;
            sstream << "Market ID: " << market->GetHash().GetHex() << std::endl;

            return QString::fromStdString(sstream.str());
        }
    }

    case Qt::DecorationRole:
    {
        // Graph
        if (col == 0) {
            MarketGraphWidget graphWidget;
            return graphWidget.getTableGraphPixmap(QString::fromStdString(market->title), market);
        }
    }

    case Qt::SizeHintRole:
    {
        // Graph
        if (col == 0) {
            return QSize(480, 360);
        }
    }
    }

    return QVariant();
}

const marketMarket *MarketModel::index(int row) const
{
    return priv->index(row);
}

QVariant MarketModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole) {
        if (orientation == Qt::Horizontal) {
            switch(section) {
            case 0:
                return QString("Graph");
            case 1:
                return QString("Market Info");
            }
        }
    }

    return QVariant();
}

void MarketModel::setBranch(uint256 branchID)
{
    std::cout << "Setting branch\n";

    if (!priv) return;

    // Make sure the branch exists
    const marketBranch *branch = pmarkettree->GetBranch(branchID);
    if (!branch) return;

    // Erase / reset the cache
    resetModel();

    // Get the list of decisions on the branch
    vector<marketDecision *> decisions = pmarkettree->GetDecisions(branchID);

    // Make a list of markets from every decision on the branch
    vector<marketMarket *> markets;

    for (unsigned int x = 0; x < decisions.size(); x++) {
        // Get the markets for this decision
        uint256 uDecision;
        uDecision.SetHex(decisions.at(x)->GetHash().GetHex());
        vector<marketMarket* > decisionMarkets = pmarkettree->GetMarkets(uDecision);

        // Add the markets to the markets vector
        for (unsigned int y = 0; y < decisionMarkets.size(); y++) {
            markets.push_back(decisionMarkets.at(y));
        }
    }

    // Add markets to the model
    if (markets.size()) {
        beginInsertRows(QModelIndex(), 0, markets.size()-1);

        for (unsigned int i = 0; i < markets.size(); i++)
            priv->cached.append(markets.at(i));

        endInsertRows();
    }
}

void MarketModel::resetModel()
{
    beginResetModel();

    if (priv->cached.size()) {
        beginRemoveRows(QModelIndex(), 0, priv->cached.size()-1);
        for (ssize_t i = 0; i < priv->cached.size(); i++)
            delete priv->cached.at(i);
        priv->cached.clear();
        endRemoveRows();
    }

    endResetModel();
}
<commit_msg>Remove debug output<commit_after>#include "marketmodel.h"

#include <QHBoxLayout>
#include <QList>
#include <QWidget>
#include <sstream>

#include "marketgraphwidget.h"
#include "txdb.h"
#include "wallet.h"
#include "walletmodel.h"

extern CMarketTreeDB *pmarkettree;

// Private implementation
class MarketModelPriv
{
public:
    MarketModelPriv(CWallet *wallet, MarketModel *parent)
        : wallet(wallet),
          parent(parent)
    {
    }

    CWallet *wallet;
    MarketModel *parent;

    QList<const marketMarket *> cached;

    int size()
    {
        return cached.size();
    }

    const marketMarket *index(int idx)
    {
        if(idx >= 0 && idx < cached.size())
            return cached[idx];
        return 0;
    }
};

MarketModel::MarketModel(CWallet *wallet, WalletModel *parent) :
   QAbstractTableModel(parent),
   wallet(wallet),
   walletModel(parent),
   priv(new MarketModelPriv(wallet, this))
{
}

MarketModel::~MarketModel()
{
    delete priv;
}

int MarketModel::rowCount(const QModelIndex & /*parent*/) const
{
   return priv->size();
}

int MarketModel::columnCount(const QModelIndex & /*parent*/) const
{
    return 2;
}

QVariant MarketModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return false;
    }

    int row = index.row();
    int col = index.column();

    const marketMarket *market = priv->index(row);

    switch(role) {
    case Qt::DisplayRole:
    {
        // Market Details
        if (col == 1) {
            std::stringstream sstream;
            sstream << "Title: " << market->title << std::endl;
            sstream << "Description: " << market->description << std::endl;
            sstream << "Tags: " << market->tags << std::endl;
            sstream << "Market ID: " << market->GetHash().GetHex() << std::endl;

            return QString::fromStdString(sstream.str());
        }
    }

    case Qt::DecorationRole:
    {
        // Graph
        if (col == 0) {
            MarketGraphWidget graphWidget;
            return graphWidget.getTableGraphPixmap(QString::fromStdString(market->title), market);
        }
    }

    case Qt::SizeHintRole:
    {
        // Graph
        if (col == 0) {
            return QSize(480, 360);
        }
    }
    }

    return QVariant();
}

const marketMarket *MarketModel::index(int row) const
{
    return priv->index(row);
}

QVariant MarketModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole) {
        if (orientation == Qt::Horizontal) {
            switch(section) {
            case 0:
                return QString("Graph");
            case 1:
                return QString("Market Info");
            }
        }
    }

    return QVariant();
}

void MarketModel::setBranch(uint256 branchID)
{
    if (!priv) return;

    // Make sure the branch exists
    const marketBranch *branch = pmarkettree->GetBranch(branchID);
    if (!branch) return;

    // Erase / reset the cache
    resetModel();

    // Get the list of decisions on the branch
    vector<marketDecision *> decisions = pmarkettree->GetDecisions(branchID);

    // Make a list of markets from every decision on the branch
    vector<marketMarket *> markets;

    for (unsigned int x = 0; x < decisions.size(); x++) {
        // Get the markets for this decision
        uint256 uDecision;
        uDecision.SetHex(decisions.at(x)->GetHash().GetHex());
        vector<marketMarket* > decisionMarkets = pmarkettree->GetMarkets(uDecision);

        // Add the markets to the markets vector
        for (unsigned int y = 0; y < decisionMarkets.size(); y++) {
            markets.push_back(decisionMarkets.at(y));
        }
    }

    // Add markets to the model
    if (markets.size()) {
        beginInsertRows(QModelIndex(), 0, markets.size()-1);

        for (unsigned int i = 0; i < markets.size(); i++)
            priv->cached.append(markets.at(i));

        endInsertRows();
    }
}

void MarketModel::resetModel()
{
    beginResetModel();

    if (priv->cached.size()) {
        beginRemoveRows(QModelIndex(), 0, priv->cached.size()-1);
        for (ssize_t i = 0; i < priv->cached.size(); i++)
            delete priv->cached.at(i);
        priv->cached.clear();
        endRemoveRows();
    }

    endResetModel();
}
<|endoftext|>


<commit_before>#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#include <qt/qtumhwitool.h>
#include <qt/guiutil.h>
#include <qt/execrpccommand.h>
#include <qt/walletmodel.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <chainparams.h>
#include <outputtype.h>

#include <QProcess>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QVariantMap>
#include <QVariantList>

#include <atomic>

static const QString PARAM_START_HEIGHT = "start_height";
static const QString PARAM_STOP_HEIGHT = "stop_height";
static const QString PARAM_REQUESTS = "requests";
static const QString PARAM_PSBT = "psbt";
static const QString PARAM_HEXTX = "hextx";

class QtumHwiToolPriv
{
public:
    QtumHwiToolPriv(QObject *parent)
    {
        toolPath = GUIUtil::getHwiToolPath();
        QStringList optionalRescan = QStringList() << PARAM_START_HEIGHT << PARAM_STOP_HEIGHT;
        cmdRescan = new ExecRPCCommand("rescanblockchain", QStringList(), optionalRescan,  QMap<QString, QString>(), parent);
        QStringList mandatoryImport = QStringList() << PARAM_REQUESTS;
        cmdImport = new ExecRPCCommand("importmulti", mandatoryImport, QStringList(),  QMap<QString, QString>(), parent);
        QStringList mandatoryFinalize = QStringList() << PARAM_PSBT;
        cmdFinalize = new ExecRPCCommand("finalizepsbt", mandatoryFinalize, QStringList(),  QMap<QString, QString>(), parent);
        QStringList mandatorySend = QStringList() << PARAM_HEXTX;
        cmdSend = new ExecRPCCommand("finalizepsbt", mandatorySend, QStringList(),  QMap<QString, QString>(), parent);
        QStringList mandatoryDecode = QStringList() << PARAM_PSBT;
        cmdDecode = new ExecRPCCommand("decodepsbt", mandatoryDecode, QStringList(),  QMap<QString, QString>(), parent);
        if(gArgs.GetChainName() != CBaseChainParams::MAIN)
        {
            arguments << "--testnet";
        }
    }

    std::atomic<bool> fStarted{false};
    QProcess process;
    QString strStdout;
    QString strError;
    QString toolPath;
    QStringList arguments;

    ExecRPCCommand* cmdRescan = 0;
    ExecRPCCommand* cmdImport = 0;
    ExecRPCCommand* cmdFinalize = 0;
    ExecRPCCommand* cmdSend = 0;
    ExecRPCCommand* cmdDecode = 0;
    WalletModel* model = 0;
};

HWDevice::HWDevice()
{}

QString HWDevice::toString() const
{
    return QString("[ %1 \\ %2 \\ %3 \\ %4 ]").arg(type, model, path, fingerprint);
}

bool HWDevice::isValid() const
{
    return fingerprint != "";
}

QString HWDevice::errorMessage() const
{
    return QString("Error: %1\nCode: %2").arg(error, code);
}

QtumHwiTool::QtumHwiTool(QObject *parent) : QObject(parent)
{
    d = new QtumHwiToolPriv(this);
}

QtumHwiTool::~QtumHwiTool()
{
    delete d;
}

bool QtumHwiTool::enumerate(QList<HWDevice> &devices)
{
    // Enumerate hardware wallet devices
    if(isStarted())
        return false;

    if(!beginEnumerate(devices))
        return false;

    wait();

    return endEnumerate(devices);
}

bool QtumHwiTool::isConnected(const QString &fingerprint)
{
    // Check if a device is connected
    QList<HWDevice> devices;
    if(enumerate(devices))
    {
        for(HWDevice device: devices)
        {
            if(device.fingerprint == fingerprint)
                return true;
        }
    }
    return false;
}

bool QtumHwiTool::getKeyPool(const QString &fingerprint, int type, QString &desc)
{
    // Get the key pool for a device
    if(isStarted())
        return false;

    if(!beginGetKeyPool(fingerprint, type, desc))
        return false;

    wait();

    return endGetKeyPool(fingerprint, type, desc);
}

bool QtumHwiTool::getKeyPoolPKH(const QString &fingerprint, QString &desc)
{
    return getKeyPool(fingerprint, (int)OutputType::LEGACY, desc);
}

bool QtumHwiTool::getKeyPoolP2SH(const QString &fingerprint, QString &desc)
{
    return getKeyPool(fingerprint, (int)OutputType::P2SH_SEGWIT, desc);
}

bool QtumHwiTool::getKeyPoolBech32(const QString &fingerprint, QString &desc)
{
    return getKeyPool(fingerprint, (int)OutputType::BECH32, desc);
}

bool QtumHwiTool::signTx(const QString &fingerprint, QString &psbt)
{
    // Sign PSBT transaction
    if(isStarted())
        return false;

    if(!beginSignTx(fingerprint, psbt))
        return false;

    wait();

    return endSignTx(fingerprint, psbt);
}

QString QtumHwiTool::errorMessage()
{
    // Get the last error message
    if(d->fStarted)
        return tr("Started");

    return d->strError;
}

bool QtumHwiTool::isStarted()
{
    return d->fStarted;
}

void QtumHwiTool::wait()
{
    if(d->fStarted)
    {
        d->process.waitForFinished(-1);
        d->strStdout = d->process.readAllStandardOutput();
        d->strError = d->process.readAllStandardError();
        d->fStarted = false;
    }
}

bool QtumHwiTool::beginEnumerate(QList<HWDevice> &devices)
{
    Q_UNUSED(devices);

    // Execute command line
    QStringList arguments = d->arguments;
    arguments << "enumerate";
    d->process.start(d->toolPath, arguments);
    d->fStarted = true;

    return d->fStarted;
}

bool QtumHwiTool::beginGetKeyPool(const QString &fingerprint, int type, QString &desc)
{
    Q_UNUSED(desc);

    // Get the output type
    QString descType;
    switch (type) {
    case (int)OutputType::P2SH_SEGWIT:
        descType = "--sh_wpkh";
        break;
    case (int)OutputType::BECH32:
        descType = "--wpkh";
        break;
    default:
        break;
    }

    // Execute command line
    QStringList arguments = d->arguments;
    arguments << "-f" << fingerprint << "getkeypool";
    if(descType != "")
        arguments << descType;
    arguments << "0" << "1000";
    d->process.start(d->toolPath, arguments);
    d->fStarted = true;

    return d->fStarted;
}

bool QtumHwiTool::beginSignTx(const QString &fingerprint, QString &psbt)
{
    // Execute command line
    QStringList arguments = d->arguments;
    arguments << "-f" << fingerprint << "signtx" << psbt;
    d->process.start(d->toolPath, arguments);
    d->fStarted = true;

    return d->fStarted;
}

bool QtumHwiTool::endEnumerate(QList<HWDevice> &devices)
{
    // Decode command line results
    QJsonDocument jsonDocument = QJsonDocument::fromJson(d->strStdout.toUtf8());
    QJsonArray jsonDevices = jsonDocument.array();
    for(QJsonValue jsonDevice : jsonDevices)
    {
        if(!jsonDevice.isObject())
            return false;

        // Get device info
        QVariantMap data = jsonDevice.toObject().toVariantMap();
        HWDevice device;
        device.fingerprint = data["fingerprint"].toString();
        device.serial_number = data["serial_number"].toString();
        device.type = data["type"].toString();
        device.path = data["path"].toString();
        device.error = data["error"].toString();
        device.model = data["model"].toString();
        device.code = data["code"].toString();
        devices.push_back(device);

        // Set error message
        if(!device.isValid())
            addError(device.errorMessage());
    }

    return devices.size() > 0;
}

bool QtumHwiTool::endGetKeyPool(const QString &fingerprint, int type, QString &desc)
{
    Q_UNUSED(fingerprint);
    Q_UNUSED(type);

    // Decode command line results
    bool ret = d->strStdout.contains("desc");
    if(ret)
    {
        desc = "\"" + d->strStdout.replace("\"", "\\\"") + "\"";
    }
    else
    {
        desc = d->strStdout;
    }

    return ret;
}

bool QtumHwiTool::endSignTx(const QString &fingerprint, QString &psbt)
{
    Q_UNUSED(fingerprint);

    // Decode command line results
    QJsonDocument jsonDocument = QJsonDocument::fromJson(d->strStdout.toUtf8());
    QVariantMap data = jsonDocument.object().toVariantMap();
    QString psbtSigned = data["psbt"].toString();
    if(!psbtSigned.isEmpty())
    {
        psbt = psbtSigned;
        return true;
    }

    return false;
}

bool QtumHwiTool::rescanBlockchain(int startHeight, int stopHeight)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultJson;
    ExecRPCCommand::appendParam(lstParams, PARAM_START_HEIGHT, QString::number(startHeight));
    if(stopHeight > -1)
    {
        ExecRPCCommand::appendParam(lstParams, PARAM_STOP_HEIGHT, QString::number(stopHeight));
    }

    // Exec RPC
    if(!execRPC(d->cmdRescan, lstParams, result, resultJson))
        return false;

    // Parse results
    QVariantMap variantMap = result.toMap();
    int resStartHeight = variantMap.value(PARAM_START_HEIGHT).toInt();
    int resStopHeight = variantMap.value(PARAM_STOP_HEIGHT).toInt();

    return resStartHeight < resStopHeight;
}

bool QtumHwiTool::importMulti(const QString &desc)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultJson;
    ExecRPCCommand::appendParam(lstParams, PARAM_REQUESTS, desc);

    // Exec RPC
    if(!execRPC(d->cmdImport, lstParams, result, resultJson))
        return false;

    // Parse results
    int countSuccess = 0;
    QVariantList variantList = result.toList();
    for(const QVariant& item : variantList)
    {
        QVariantMap variantMap = item.toMap();
        if(variantMap.value("success").toBool())
            countSuccess++;
    }

    return countSuccess > 0;
}

bool QtumHwiTool::finalizePsbt(const QString &psbt, QString &hexTx, bool &complete)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultJson;
    ExecRPCCommand::appendParam(lstParams, PARAM_PSBT, psbt);

    // Exec RPC
    if(!execRPC(d->cmdFinalize, lstParams, result, resultJson))
        return false;

    // Parse results
    QVariantMap variantMap = result.toMap();
    hexTx = variantMap.value("hex").toString();
    complete = variantMap.value("complete").toBool();

    return true;
}

bool QtumHwiTool::sendRawTransaction(const QString &hexTx)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultStr;
    ExecRPCCommand::appendParam(lstParams, PARAM_HEXTX, hexTx);

    // Exec RPC
    if(!execRPC(d->cmdSend, lstParams, result, resultStr))
        return false;

    // Parse results
    std::string strHash = resultStr.toStdString();

    return strHash.length() == 64 && IsHex(strHash);
}

bool QtumHwiTool::decodePsbt(const QString &psbt, QString &decoded)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultStr;
    ExecRPCCommand::appendParam(lstParams, PARAM_PSBT, psbt);

    // Exec RPC
    if(!execRPC(d->cmdDecode, lstParams, result, resultStr))
        return false;

    // Parse results
    decoded = resultStr;

    return true;
}

void QtumHwiTool::setModel(WalletModel *model)
{
    d->model = model;
}

bool QtumHwiTool::execRPC(ExecRPCCommand *cmd, const QMap<QString, QString> &lstParams, QVariant &result, QString &resultJson)
{
    d->strError.clear();
    if(!cmd->exec(d->model->node(), d->model, lstParams, result, resultJson, d->strError))
        return false;

    return true;
}

void QtumHwiTool::addError(const QString &error)
{
    if(d->strError != "")
        d->strError += "\n";
    d->strError += error;
}
<commit_msg>Add wait for started<commit_after>#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#include <qt/qtumhwitool.h>
#include <qt/guiutil.h>
#include <qt/execrpccommand.h>
#include <qt/walletmodel.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <chainparams.h>
#include <outputtype.h>

#include <QProcess>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QVariantMap>
#include <QVariantList>

#include <atomic>

static const QString PARAM_START_HEIGHT = "start_height";
static const QString PARAM_STOP_HEIGHT = "stop_height";
static const QString PARAM_REQUESTS = "requests";
static const QString PARAM_PSBT = "psbt";
static const QString PARAM_HEXTX = "hextx";

class QtumHwiToolPriv
{
public:
    QtumHwiToolPriv(QObject *parent)
    {
        toolPath = GUIUtil::getHwiToolPath();
        QStringList optionalRescan = QStringList() << PARAM_START_HEIGHT << PARAM_STOP_HEIGHT;
        cmdRescan = new ExecRPCCommand("rescanblockchain", QStringList(), optionalRescan,  QMap<QString, QString>(), parent);
        QStringList mandatoryImport = QStringList() << PARAM_REQUESTS;
        cmdImport = new ExecRPCCommand("importmulti", mandatoryImport, QStringList(),  QMap<QString, QString>(), parent);
        QStringList mandatoryFinalize = QStringList() << PARAM_PSBT;
        cmdFinalize = new ExecRPCCommand("finalizepsbt", mandatoryFinalize, QStringList(),  QMap<QString, QString>(), parent);
        QStringList mandatorySend = QStringList() << PARAM_HEXTX;
        cmdSend = new ExecRPCCommand("finalizepsbt", mandatorySend, QStringList(),  QMap<QString, QString>(), parent);
        QStringList mandatoryDecode = QStringList() << PARAM_PSBT;
        cmdDecode = new ExecRPCCommand("decodepsbt", mandatoryDecode, QStringList(),  QMap<QString, QString>(), parent);
        if(gArgs.GetChainName() != CBaseChainParams::MAIN)
        {
            arguments << "--testnet";
        }
    }

    std::atomic<bool> fStarted{false};
    QProcess process;
    QString strStdout;
    QString strError;
    QString toolPath;
    QStringList arguments;

    ExecRPCCommand* cmdRescan = 0;
    ExecRPCCommand* cmdImport = 0;
    ExecRPCCommand* cmdFinalize = 0;
    ExecRPCCommand* cmdSend = 0;
    ExecRPCCommand* cmdDecode = 0;
    WalletModel* model = 0;
};

HWDevice::HWDevice()
{}

QString HWDevice::toString() const
{
    return QString("[ %1 \\ %2 \\ %3 \\ %4 ]").arg(type, model, path, fingerprint);
}

bool HWDevice::isValid() const
{
    return fingerprint != "";
}

QString HWDevice::errorMessage() const
{
    return QString("Error: %1\nCode: %2").arg(error, code);
}

QtumHwiTool::QtumHwiTool(QObject *parent) : QObject(parent)
{
    d = new QtumHwiToolPriv(this);
}

QtumHwiTool::~QtumHwiTool()
{
    delete d;
}

bool QtumHwiTool::enumerate(QList<HWDevice> &devices)
{
    // Enumerate hardware wallet devices
    if(isStarted())
        return false;

    if(!beginEnumerate(devices))
        return false;

    wait();

    return endEnumerate(devices);
}

bool QtumHwiTool::isConnected(const QString &fingerprint)
{
    // Check if a device is connected
    QList<HWDevice> devices;
    if(enumerate(devices))
    {
        for(HWDevice device: devices)
        {
            if(device.fingerprint == fingerprint)
                return true;
        }
    }
    return false;
}

bool QtumHwiTool::getKeyPool(const QString &fingerprint, int type, QString &desc)
{
    // Get the key pool for a device
    if(isStarted())
        return false;

    if(!beginGetKeyPool(fingerprint, type, desc))
        return false;

    wait();

    return endGetKeyPool(fingerprint, type, desc);
}

bool QtumHwiTool::getKeyPoolPKH(const QString &fingerprint, QString &desc)
{
    return getKeyPool(fingerprint, (int)OutputType::LEGACY, desc);
}

bool QtumHwiTool::getKeyPoolP2SH(const QString &fingerprint, QString &desc)
{
    return getKeyPool(fingerprint, (int)OutputType::P2SH_SEGWIT, desc);
}

bool QtumHwiTool::getKeyPoolBech32(const QString &fingerprint, QString &desc)
{
    return getKeyPool(fingerprint, (int)OutputType::BECH32, desc);
}

bool QtumHwiTool::signTx(const QString &fingerprint, QString &psbt)
{
    // Sign PSBT transaction
    if(isStarted())
        return false;

    if(!beginSignTx(fingerprint, psbt))
        return false;

    wait();

    return endSignTx(fingerprint, psbt);
}

QString QtumHwiTool::errorMessage()
{
    // Get the last error message
    if(d->fStarted)
        return tr("Started");

    return d->strError;
}

bool QtumHwiTool::isStarted()
{
    return d->fStarted;
}

void QtumHwiTool::wait()
{
    if(d->fStarted)
    {
        if(d->process.waitForStarted())
        {
            d->process.waitForFinished(-1);
        }
        d->strStdout = d->process.readAllStandardOutput();
        d->strError = d->process.readAllStandardError();
        d->fStarted = false;
    }
}

bool QtumHwiTool::beginEnumerate(QList<HWDevice> &devices)
{
    Q_UNUSED(devices);

    // Execute command line
    QStringList arguments = d->arguments;
    arguments << "enumerate";
    d->process.start(d->toolPath, arguments);
    d->fStarted = true;

    return d->fStarted;
}

bool QtumHwiTool::beginGetKeyPool(const QString &fingerprint, int type, QString &desc)
{
    Q_UNUSED(desc);

    // Get the output type
    QString descType;
    switch (type) {
    case (int)OutputType::P2SH_SEGWIT:
        descType = "--sh_wpkh";
        break;
    case (int)OutputType::BECH32:
        descType = "--wpkh";
        break;
    default:
        break;
    }

    // Execute command line
    QStringList arguments = d->arguments;
    arguments << "-f" << fingerprint << "getkeypool";
    if(descType != "")
        arguments << descType;
    arguments << "0" << "1000";
    d->process.start(d->toolPath, arguments);
    d->fStarted = true;

    return d->fStarted;
}

bool QtumHwiTool::beginSignTx(const QString &fingerprint, QString &psbt)
{
    // Execute command line
    QStringList arguments = d->arguments;
    arguments << "-f" << fingerprint << "signtx" << psbt;
    d->process.start(d->toolPath, arguments);
    d->fStarted = true;

    return d->fStarted;
}

bool QtumHwiTool::endEnumerate(QList<HWDevice> &devices)
{
    // Decode command line results
    QJsonDocument jsonDocument = QJsonDocument::fromJson(d->strStdout.toUtf8());
    QJsonArray jsonDevices = jsonDocument.array();
    for(QJsonValue jsonDevice : jsonDevices)
    {
        if(!jsonDevice.isObject())
            return false;

        // Get device info
        QVariantMap data = jsonDevice.toObject().toVariantMap();
        HWDevice device;
        device.fingerprint = data["fingerprint"].toString();
        device.serial_number = data["serial_number"].toString();
        device.type = data["type"].toString();
        device.path = data["path"].toString();
        device.error = data["error"].toString();
        device.model = data["model"].toString();
        device.code = data["code"].toString();
        devices.push_back(device);

        // Set error message
        if(!device.isValid())
            addError(device.errorMessage());
    }

    return devices.size() > 0;
}

bool QtumHwiTool::endGetKeyPool(const QString &fingerprint, int type, QString &desc)
{
    Q_UNUSED(fingerprint);
    Q_UNUSED(type);

    // Decode command line results
    bool ret = d->strStdout.contains("desc");
    if(ret)
    {
        desc = "\"" + d->strStdout.replace("\"", "\\\"") + "\"";
    }
    else
    {
        desc = d->strStdout;
    }

    return ret;
}

bool QtumHwiTool::endSignTx(const QString &fingerprint, QString &psbt)
{
    Q_UNUSED(fingerprint);

    // Decode command line results
    QJsonDocument jsonDocument = QJsonDocument::fromJson(d->strStdout.toUtf8());
    QVariantMap data = jsonDocument.object().toVariantMap();
    QString psbtSigned = data["psbt"].toString();
    if(!psbtSigned.isEmpty())
    {
        psbt = psbtSigned;
        return true;
    }

    return false;
}

bool QtumHwiTool::rescanBlockchain(int startHeight, int stopHeight)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultJson;
    ExecRPCCommand::appendParam(lstParams, PARAM_START_HEIGHT, QString::number(startHeight));
    if(stopHeight > -1)
    {
        ExecRPCCommand::appendParam(lstParams, PARAM_STOP_HEIGHT, QString::number(stopHeight));
    }

    // Exec RPC
    if(!execRPC(d->cmdRescan, lstParams, result, resultJson))
        return false;

    // Parse results
    QVariantMap variantMap = result.toMap();
    int resStartHeight = variantMap.value(PARAM_START_HEIGHT).toInt();
    int resStopHeight = variantMap.value(PARAM_STOP_HEIGHT).toInt();

    return resStartHeight < resStopHeight;
}

bool QtumHwiTool::importMulti(const QString &desc)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultJson;
    ExecRPCCommand::appendParam(lstParams, PARAM_REQUESTS, desc);

    // Exec RPC
    if(!execRPC(d->cmdImport, lstParams, result, resultJson))
        return false;

    // Parse results
    int countSuccess = 0;
    QVariantList variantList = result.toList();
    for(const QVariant& item : variantList)
    {
        QVariantMap variantMap = item.toMap();
        if(variantMap.value("success").toBool())
            countSuccess++;
    }

    return countSuccess > 0;
}

bool QtumHwiTool::finalizePsbt(const QString &psbt, QString &hexTx, bool &complete)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultJson;
    ExecRPCCommand::appendParam(lstParams, PARAM_PSBT, psbt);

    // Exec RPC
    if(!execRPC(d->cmdFinalize, lstParams, result, resultJson))
        return false;

    // Parse results
    QVariantMap variantMap = result.toMap();
    hexTx = variantMap.value("hex").toString();
    complete = variantMap.value("complete").toBool();

    return true;
}

bool QtumHwiTool::sendRawTransaction(const QString &hexTx)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultStr;
    ExecRPCCommand::appendParam(lstParams, PARAM_HEXTX, hexTx);

    // Exec RPC
    if(!execRPC(d->cmdSend, lstParams, result, resultStr))
        return false;

    // Parse results
    std::string strHash = resultStr.toStdString();

    return strHash.length() == 64 && IsHex(strHash);
}

bool QtumHwiTool::decodePsbt(const QString &psbt, QString &decoded)
{
    if(!d->model) return false;

    // Add params for RPC
    QMap<QString, QString> lstParams;
    QVariant result;
    QString resultStr;
    ExecRPCCommand::appendParam(lstParams, PARAM_PSBT, psbt);

    // Exec RPC
    if(!execRPC(d->cmdDecode, lstParams, result, resultStr))
        return false;

    // Parse results
    decoded = resultStr;

    return true;
}

void QtumHwiTool::setModel(WalletModel *model)
{
    d->model = model;
}

bool QtumHwiTool::execRPC(ExecRPCCommand *cmd, const QMap<QString, QString> &lstParams, QVariant &result, QString &resultJson)
{
    d->strError.clear();
    if(!cmd->exec(d->model->node(), d->model, lstParams, result, resultJson, d->strError))
        return false;

    return true;
}

void QtumHwiTool::addError(const QString &error)
{
    if(d->strError != "")
        d->strError += "\n";
    d->strError += error;
}
<|endoftext|>


<commit_before>
<commit_msg>Delete 1.cpp<commit_after><|endoftext|>