From 09c25a60b00047af0b9457d56e727545a7c73150 Mon Sep 17 00:00:00 2001
From: Sergey Gorbunov <se.gorbunov@gsi.de>
Date: Sat, 7 Nov 2020 01:01:44 +0100
Subject: [PATCH] CbmQaPie class as a TPie wrapper, which prevents crashes

---
 core/qa/CMakeLists.txt     |  1 +
 core/qa/CbmQaBaseLinkDef.h |  2 +
 core/qa/CbmQaPie.cxx       | 96 ++++++++++++++++++++++++++++++++++++++
 core/qa/CbmQaPie.h         | 62 ++++++++++++++++++++++++
 4 files changed, 161 insertions(+)
 create mode 100644 core/qa/CbmQaPie.cxx
 create mode 100644 core/qa/CbmQaPie.h

diff --git a/core/qa/CMakeLists.txt b/core/qa/CMakeLists.txt
index 1140f0e592..5ba68ecd51 100644
--- a/core/qa/CMakeLists.txt
+++ b/core/qa/CMakeLists.txt
@@ -20,6 +20,7 @@ link_directories( ${LINK_DIRECTORIES})
 
 set(SRCS
 CbmQaCanvas.cxx
+CbmQaPie.cxx
 )
 
 set(LINKDEF CbmQaBaseLinkDef.h)
diff --git a/core/qa/CbmQaBaseLinkDef.h b/core/qa/CbmQaBaseLinkDef.h
index 1709eae5e1..3241d06482 100644
--- a/core/qa/CbmQaBaseLinkDef.h
+++ b/core/qa/CbmQaBaseLinkDef.h
@@ -5,4 +5,6 @@
 #pragma link off all functions;
 
 #pragma link C++ class CbmQaCanvas - ;
+#pragma link C++ class CbmQaPieSlice + ;
+#pragma link C++ class CbmQaPie - ;
 #endif
diff --git a/core/qa/CbmQaPie.cxx b/core/qa/CbmQaPie.cxx
new file mode 100644
index 0000000000..0014f3bbf9
--- /dev/null
+++ b/core/qa/CbmQaPie.cxx
@@ -0,0 +1,96 @@
+/// \file   CbmQaPie.cxx
+/// \brief  Implementation of the CbmQaPie class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \date   07.11.2020
+
+#include "CbmQaPie.h"
+#include "TBrowser.h"
+#include "TBuffer.h"
+#include "TPad.h"
+
+ClassImp(CbmQaPieSlice);
+ClassImp(CbmQaPie);
+
+CbmQaPie::CbmQaPie(const CbmQaPie& cpy)
+  : TPie(cpy.GetName(), cpy.GetTitle(), cpy.fNvals) {
+  /// Prevent original copy constructor from a crash
+  cpy.TAttText::Copy(*this);
+  fAngularOffset = cpy.fAngularOffset;
+  fX             = cpy.fX;
+  fY             = cpy.fY;
+  fRadius        = cpy.fRadius;
+  for (Int_t i = 0; i < fNvals; ++i) {
+    *fPieSlices[i] = *cpy.fPieSlices[i];
+    ((CbmQaPieSlice*) fPieSlices[i])->SetPie(this);
+  }
+}
+
+void CbmQaPie::Browse(TBrowser* b) {
+  /// Draw CbmQaPie by a mouse click in the TBrowser
+  Draw(b ? b->GetDrawOption() : "");
+  gPad->Update();
+}
+
+void CbmQaPie::Draw(Option_t* option) {
+  // Prevents original TPie::Draw() from crashing when there are no entries
+  double sum = 0.;
+  for (int i = 0; i < fNvals; i++) {
+    sum += fabs(GetEntryVal(i));
+  }
+  if (sum < 1.e-20) {
+    for (int i = 0; i < fNvals; i++) {
+      SetEntryVal(i, 1.e-20);
+    }
+  }
+  TPie::Draw(option);
+  if (sum < 1.e-20) {
+    for (int i = 0; i < fNvals; i++) {
+      SetEntryVal(i, 0.);
+    }
+  }
+}
+
+void CbmQaPie::Streamer(TBuffer& R__b) {
+  /// The Streamer is declared by ClassDef() macro
+  /// Stream an object of class CbmQaPie
+  ///
+
+  if (R__b.IsReading()) {
+
+    for (int i = 0; i < fNvals; i++) {
+      if (gPad && gPad->GetListOfPrimitives()) {
+        gPad->GetListOfPrimitives()->Remove(fPieSlices[i]);
+      }
+      delete fPieSlices[i];
+      fPieSlices[i] = nullptr;
+    }
+    delete[] fPieSlices;
+    fPieSlices = nullptr;
+    fNvals     = 0;
+
+    R__b.ReadClassBuffer(CbmQaPie::Class(), this);
+
+    fNvals     = fSliceStore.size();
+    fPieSlices = new TPieSlice*[fNvals];
+    for (int i = 0; i < fNvals; i++) {
+      fSliceStore[i].SetPie(this);
+      fPieSlices[i] = new TPieSlice(fSliceStore[i]);
+    }
+    fSliceStore.clear();
+
+  } else {
+
+    fSliceStore.resize(fNvals);
+    for (int i = 0; i < fNvals; i++) {
+      fSliceStore[i] = *fPieSlices[i];
+      fSliceStore[i].SetPie(nullptr);
+    }
+    TPieSlice** tmp = fPieSlices;
+    fPieSlices      = nullptr;
+    fNvals          = 0;
+    R__b.WriteClassBuffer(CbmQaPie::Class(), this);
+    fPieSlices = tmp;
+    fNvals     = fSliceStore.size();
+    fSliceStore.clear();
+  }
+}
diff --git a/core/qa/CbmQaPie.h b/core/qa/CbmQaPie.h
new file mode 100644
index 0000000000..6643b6972c
--- /dev/null
+++ b/core/qa/CbmQaPie.h
@@ -0,0 +1,62 @@
+/// \file   CbmQaPie.h
+/// \brief  Definition of the CbmQaPie class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \date   07.11.2020
+
+#ifndef CbmQaPie_H
+#define CbmQaPie_H
+
+#include "TPie.h"
+#include "TPieSlice.h"
+#include <vector>
+
+class TBrowser;
+
+/// A helper class for accessing protected members of TPieSlice
+///
+class CbmQaPieSlice : public TPieSlice {
+public:
+  /// assignment operator
+  CbmQaPieSlice& operator=(const TPieSlice& inp) {
+    return (*this = (const CbmQaPieSlice&) (inp));
+  }
+  /// set a TPie pointer
+  void SetPie(TPie* p) { fPie = p; }
+
+  ClassDef(CbmQaPieSlice, 1);
+};
+
+/// A modification of TPie which fixes the following issues:
+///
+/// 1. When a TPie is read from a file as a part of TCanvas, it crashes at the destructor.
+/// 2. When a TPie is created via copy constructor it crashes at the destructor.
+/// 3. An empty TPie crashes at Draw()
+/// 4. When one clicks on a TPie in the TBrowser, the TBrowser crashes.
+/// 5. TBrowser dosen't draw a TPie by a mouse click.
+///
+class CbmQaPie : public TPie {
+public:
+  /// Reimplementation of any existing TPie constructor
+  template<typename... Types>
+  CbmQaPie(Types... args) : TPie(args...) {}
+
+  /// Prevent original copy constructor from a crash
+  CbmQaPie(const CbmQaPie& cpy);
+
+  /// Destructor
+  ~CbmQaPie() {}
+
+  /// Draw TPie by a mouse click in the TBrowser
+  void Browse(TBrowser* b);
+
+  /// Prevents original TPie::Draw() from crashing when there are no entries
+  void Draw(Option_t* option = "l");
+
+private:
+  /// a vector for slice streaming. It replaces the original array of pointers.
+  std::vector<CbmQaPieSlice> fSliceStore;
+
+  ClassDef(CbmQaPie, 1);
+};
+
+#endif
-- 
GitLab