diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 1e1684cb5e95b8ddc2d4df1dab25396a2c0a7a49..2af4efb1b63902970564aa7b943a245759dafa77 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -5,6 +5,7 @@ set(CBMBASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/base)
 add_subdirectory(data)
 add_subdirectory(field)
 add_subdirectory(base)
+add_subdirectory(qa)
 
 add_subdirectory(detectors/trd)
 add_subdirectory(detectors/rich)
diff --git a/core/qa/CMakeLists.txt b/core/qa/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1140f0e592341210ff1e5e5d4c45b0df1ced8b6e
--- /dev/null
+++ b/core/qa/CMakeLists.txt
@@ -0,0 +1,30 @@
+Set(INCLUDE_DIRECTORIES
+${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+Include_Directories( ${INCLUDE_DIRECTORIES})
+
+Set(SYSTEM_INCLUDE_DIRECTORIES
+  ${BASE_INCLUDE_DIRECTORIES} 
+)
+
+Include_Directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
+
+set(LINK_DIRECTORIES
+${ROOT_LIBRARY_DIR}
+${FAIRROOT_LIBRARY_DIR}
+${Boost_LIBRARY_DIRS}
+)
+ 
+link_directories( ${LINK_DIRECTORIES})
+
+set(SRCS
+CbmQaCanvas.cxx
+)
+
+set(LINKDEF CbmQaBaseLinkDef.h)
+Set(LIBRARY_NAME CbmQaBase)
+Set(DEPENDENCIES
+)
+
+GENERATE_LIBRARY()
diff --git a/core/qa/CbmQaBaseLinkDef.h b/core/qa/CbmQaBaseLinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..1709eae5e18db5a891cc4b2ca5d1f03f24b064b1
--- /dev/null
+++ b/core/qa/CbmQaBaseLinkDef.h
@@ -0,0 +1,8 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class CbmQaCanvas - ;
+#endif
diff --git a/core/qa/CbmQaCanvas.cxx b/core/qa/CbmQaCanvas.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..932ed9b23ac8e4e1ba9641794379b5654b2e180a
--- /dev/null
+++ b/core/qa/CbmQaCanvas.cxx
@@ -0,0 +1,35 @@
+/// \file   CbmQaCanvas.cxx
+/// \brief  Implementation of the CbmQaCanvas class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \date   17.09.2020
+
+#include "CbmQaCanvas.h"
+#include "TBuffer.h"
+#include "TVirtualPad.h"
+
+ClassImp(CbmQaCanvas);
+
+/// The Streamer is declared by ClassDef() macro
+/// Stream an object of class CbmQaCanvas
+///
+void CbmQaCanvas::Streamer(TBuffer& R__b) {
+
+  // Save global gPad pointer,
+  // because it will be modified by TCanvas streamer
+  auto store = gPad;
+  if (R__b.IsReading()) {
+    R__b.ReadClassBuffer(CbmQaCanvas::Class(), this);
+  } else {
+    R__b.WriteClassBuffer(CbmQaCanvas::Class(), this);
+  }
+  // restore the global pointer
+  gPad = store;
+}
+
+void CbmQaCanvas::Divide2D(int nPads) {
+  if (nPads < 1) nPads = 1;
+  int rows = (int) sqrt(nPads);
+  int cols = nPads / rows;
+  if (cols * rows < nPads) cols++;
+  TCanvas::Divide(cols, rows);
+}
diff --git a/core/qa/CbmQaCanvas.h b/core/qa/CbmQaCanvas.h
new file mode 100644
index 0000000000000000000000000000000000000000..d88209aa46c6daa2588a8700512b98171b4d5d06
--- /dev/null
+++ b/core/qa/CbmQaCanvas.h
@@ -0,0 +1,64 @@
+/// \file   CbmQaCanvas.h
+/// \brief  Definition of the CbmQaCanvas class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \date   17.09.2020
+
+#ifndef CbmQaCanvas_H
+#define CbmQaCanvas_H
+
+#include "TCanvas.h"
+#include "TROOT.h"
+
+/// A modification of TCanvas which is helpful for storing canvases in a root
+/// file together with other objects.
+///
+/// 1. When ROOT reads a file which contains canvases, for no reason it sets
+/// global gPad to the last canvas in the file, thus deactivating the browser
+/// window. CbmQaCanvas modifies the standard TCanvas::Streamer() to suppress
+/// this feature.
+///
+/// 2. The CbmQaCanvas is created in the batch mode, i.e. it is not
+/// automatically displayed.
+///
+/// 3. Please use DrawCopy() methods instead of Draw(), to draw objects in the
+/// canvas. Otherwise the same object can be stored several times in the file;
+/// later this will cause crashes in the ROOT Browser for whatever reason.
+///
+class CbmQaCanvas : public TCanvas {
+public:
+  /// Default constructor needed by the ROOT streamer
+  CbmQaCanvas() : TCanvas() {}
+
+  /// Reimplementation of any existing TCanvas constructor
+  /// It sets the batch mode ON and then calls the constructor
+  template<typename... Types>
+  CbmQaCanvas(Types... args) : CbmQaCanvas(SetBatchModeOn(), args...) {}
+
+  /// Destructor
+  virtual ~CbmQaCanvas() {}
+
+  /// Divide canvas into nPads in 2D in a nice way
+  void Divide2D(int nPads);
+
+private:
+  /// Use a specific type name in order to avoid ambiguities when unrolling
+  /// templates
+  enum MyBoolean : Bool_t;
+
+  /// Constructor which calls TCanvas constructor and restores the bach mode
+  template<typename... Types>
+  CbmQaCanvas(MyBoolean oldBatchMode, Types... args) : TCanvas(args...) {
+    gROOT->SetBatch((Bool_t) oldBatchMode);
+  }
+
+  /// Set batch mode ON and return its old value
+  static MyBoolean SetBatchModeOn() {
+    MyBoolean oldBatchMode = (MyBoolean) gROOT->IsBatch();
+    gROOT->SetBatch(kTRUE);
+    return oldBatchMode;
+  }
+
+  ClassDef(CbmQaCanvas, 1);
+};
+
+#endif