0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-25 23:40:51 +08:00

#106 [Core][UI] Added possibility to add user bookmarks with double-clicking on a timeline in the Diagram window.

#112 [UI] Fixed losing focus (and getting under MainWindow) for Blocks widget.
#0 [UI] UI styling, added custom window header and dialogs (could be turned off/on and adjusted position at [Settings -> Appearance] menu).
This commit is contained in:
Victor Zarubkin 2018-06-09 02:18:39 +03:00
parent 91d10c2b46
commit 0ae430410d
39 changed files with 2985 additions and 503 deletions

View File

@ -6,8 +6,8 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
option(EASY_PROFILER_NO_GUI "Build easy_profiler without the GUI application (required Qt)" OFF) option(EASY_PROFILER_NO_GUI "Build easy_profiler without the GUI application (required Qt)" OFF)
set(EASY_PROGRAM_VERSION_MAJOR 2) set(EASY_PROGRAM_VERSION_MAJOR 2)
set(EASY_PROGRAM_VERSION_MINOR 0) set(EASY_PROGRAM_VERSION_MINOR 1)
set(EASY_PROGRAM_VERSION_PATCH 1) set(EASY_PROGRAM_VERSION_PATCH 0)
set(EASY_PRODUCT_VERSION_STRING "${EASY_PROGRAM_VERSION_MAJOR}.${EASY_PROGRAM_VERSION_MINOR}.${EASY_PROGRAM_VERSION_PATCH}") set(EASY_PRODUCT_VERSION_STRING "${EASY_PROGRAM_VERSION_MAJOR}.${EASY_PROGRAM_VERSION_MINOR}.${EASY_PROGRAM_VERSION_PATCH}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)

View File

@ -80,44 +80,70 @@ void JsonExporter::convert(const ::std::string& inputFile, const ::std::string&
nlohmann::json json = {{"version", fr.getVersionString()}, {"timeUnits", "ns"}}; nlohmann::json json = {{"version", fr.getVersionString()}, {"timeUnits", "ns"}};
auto descriptors = nlohmann::json::array(); // convert descriptors
const auto& block_descriptors = fr.getBlockDescriptors();
for (const auto& descriptor : block_descriptors)
{ {
descriptors.emplace_back(); auto descriptors = nlohmann::json::array();
const auto& block_descriptors = fr.getBlockDescriptors();
for (const auto& descriptor : block_descriptors)
{
descriptors.emplace_back();
std::stringstream stream; std::stringstream stream;
stream << "0x" << std::hex << descriptor.argbColor; stream << "0x" << std::hex << descriptor.argbColor;
auto& desc = descriptors.back(); auto& desc = descriptors.back();
desc["id"] = descriptor.id; desc["id"] = descriptor.id;
if (descriptor.parentId != descriptor.id) if (descriptor.parentId != descriptor.id)
desc["parentId"] = descriptor.parentId; desc["parentId"] = descriptor.parentId;
desc["name"] = descriptor.blockName; desc["name"] = descriptor.blockName;
desc["type"] = descriptor.blockType; desc["type"] = descriptor.blockType;
desc["color"] = stream.str(); desc["color"] = stream.str();
desc["sourceFile"] = descriptor.fileName; desc["sourceFile"] = descriptor.fileName;
desc["sourceLine"] = descriptor.lineNumber; desc["sourceLine"] = descriptor.lineNumber;
}
json["blockDescriptors"] = descriptors;
} }
json["blockDescriptors"] = descriptors; // convert threads and blocks
auto threads = nlohmann::json::array();
const auto& blocks_tree = fr.getBlocksTree();
for (const auto& kv : blocks_tree)
{ {
threads.emplace_back(); auto threads = nlohmann::json::array();
const auto& blocks_tree = fr.getBlocksTree();
for (const auto& kv : blocks_tree)
{
threads.emplace_back();
auto& thread = threads.back(); auto& thread = threads.back();
thread["threadId"] = kv.first; thread["threadId"] = kv.first;
thread["threadName"] = fr.getThreadName(kv.first); thread["threadName"] = fr.getThreadName(kv.first);
convertChildren(kv.second, thread); convertChildren(kv.second, thread);
}
json["threads"] = threads;
} }
json["threads"] = threads; // convert bookmarks
{
auto bookmarks = nlohmann::json::array();
const auto& bmarks = fr.getBookmarks();
for (const auto& mark : bmarks)
{
std::stringstream stream;
stream << "0x" << std::hex << mark.color;
bookmarks.emplace_back();
auto& bookmark = bookmarks.back();
bookmark["timestamp"] = mark.pos;
bookmark["color"] = stream.str();
bookmark["text"] = mark.text;
}
json["bookmarks"] = bookmarks;
}
try try
{ {

View File

@ -57,17 +57,20 @@ namespace reader
profiler::block_index_t FileReader::readFile(const std::string& filename) profiler::block_index_t FileReader::readFile(const std::string& filename)
{ {
::profiler::SerializedData serialized_blocks, serialized_descriptors; profiler::SerializedData serialized_blocks, serialized_descriptors;
profiler::descriptors_list_t descriptors; profiler::descriptors_list_t descriptors;
profiler::blocks_t blocks; profiler::blocks_t blocks;
profiler::thread_blocks_tree_t threaded_trees; profiler::thread_blocks_tree_t threaded_trees;
profiler::bookmarks_t bookmarks;
profiler::BeginEndTime beginEndTime;
profiler::processid_t pid = 0; profiler::processid_t pid = 0;
uint32_t total_descriptors_number = 0; uint32_t total_descriptors_number = 0;
EASY_CONSTEXPR bool DoNotGatherStats = false; EASY_CONSTEXPR bool DoNotGatherStats = false;
const auto blocks_number = ::fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, const auto blocks_number = ::fillTreesFromFile(filename.c_str(), beginEndTime, serialized_blocks, serialized_descriptors,
descriptors, blocks, threaded_trees, total_descriptors_number, m_version, pid, DoNotGatherStats, m_errorMessage); descriptors, blocks, threaded_trees, bookmarks, total_descriptors_number, m_version, pid, DoNotGatherStats,
m_errorMessage);
if (blocks_number == 0) if (blocks_number == 0)
return 0; return 0;
@ -156,6 +159,8 @@ profiler::block_index_t FileReader::readFile(const std::string& filename)
} }
} }
m_bookmarks.swap(bookmarks);
return blocks_number; return blocks_number;
} }
@ -169,6 +174,11 @@ const descriptors_list_t& FileReader::getBlockDescriptors() const
return m_blockDescriptors; return m_blockDescriptors;
} }
const profiler::bookmarks_t& FileReader::getBookmarks() const
{
return m_bookmarks;
}
const std::string& FileReader::getThreadName(uint64_t threadId) const const std::string& FileReader::getThreadName(uint64_t threadId) const
{ {
auto it = m_threadNames.find(threadId); auto it = m_threadNames.find(threadId);

View File

@ -108,6 +108,8 @@ public:
const descriptors_list_t& getBlockDescriptors() const; const descriptors_list_t& getBlockDescriptors() const;
const profiler::bookmarks_t& getBookmarks() const;
/*! get thread name by Id /*! get thread name by Id
\param threadId thread Id \param threadId thread Id
\return Name of thread \return Name of thread
@ -132,6 +134,7 @@ private:
thread_names_t m_threadNames; ///< [thread_id, thread_name] thread_names_t m_threadNames; ///< [thread_id, thread_name]
context_switches_t m_contextSwitches; ///< context switches info context_switches_t m_contextSwitches; ///< context switches info
descriptors_list_t m_blockDescriptors; ///< block descriptors descriptors_list_t m_blockDescriptors; ///< block descriptors
profiler::bookmarks_t m_bookmarks; ///< User bookmarks
uint32_t m_version; ///< .prof file version uint32_t m_version; ///< .prof file version
}; // end of class FileReader. }; // end of class FileReader.

View File

@ -110,15 +110,15 @@ namespace profiler {
children_t children; ///< List of children blocks. May be empty. children_t children; ///< List of children blocks. May be empty.
union { union {
profiler::SerializedBlock* node; ///< Pointer to serialized data for regular block (id, name, begin, end etc.) profiler::SerializedBlock* node; ///< Pointer to serialized data for regular block (id, name, begin, end etc.)
profiler::SerializedCSwitch* cs; ///< Pointer to serialized data for context switch (thread_id, name, begin, end etc.) profiler::SerializedCSwitch* cs; ///< Pointer to serialized data for context switch (thread_id, name, begin, end etc.)
profiler::ArbitraryValue* value; ///< Pointer to serialized data for arbitrary value profiler::ArbitraryValue* value; ///< Pointer to serialized data for arbitrary value
}; };
profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks) profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks) profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
uint8_t depth; ///< Maximum number of sublevels (maximum children depth) uint8_t depth; ///< Maximum number of sublevels (maximum children depth)
BlocksTree(const This&) = delete; BlocksTree(const This&) = delete;
This& operator = (const This&) = delete; This& operator = (const This&) = delete;
@ -204,22 +204,36 @@ namespace profiler {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
struct Bookmark EASY_FINAL
{
EASY_STATIC_CONSTEXPR size_t BaseSize = sizeof(profiler::timestamp_t) +
sizeof(profiler::color_t) + 1;
std::string text;
profiler::timestamp_t pos;
profiler::color_t color;
};
using bookmarks_t = std::vector<Bookmark>;
//////////////////////////////////////////////////////////////////////////
class BlocksTreeRoot EASY_FINAL class BlocksTreeRoot EASY_FINAL
{ {
using This = BlocksTreeRoot; using This = BlocksTreeRoot;
public: public:
BlocksTree::children_t children; ///< List of children indexes BlocksTree::children_t children; ///< List of children indexes
BlocksTree::children_t sync; ///< List of context-switch events BlocksTree::children_t sync; ///< List of context-switch events
BlocksTree::children_t events; ///< List of events indexes BlocksTree::children_t events; ///< List of events indexes
std::string thread_name; ///< Name of this thread std::string thread_name; ///< Name of this thread
profiler::timestamp_t profiled_time; ///< Profiled time of this thread (sum of all children duration) profiler::timestamp_t profiled_time; ///< Profiled time of this thread (sum of all children duration)
profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches) profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches)
profiler::thread_id_t thread_id; ///< System Id of this thread profiler::thread_id_t thread_id; ///< System Id of this thread
profiler::block_index_t frames_number; ///< Total frames number (top-level blocks) profiler::block_index_t frames_number; ///< Total frames number (top-level blocks)
profiler::block_index_t blocks_number; ///< Total blocks number including their children profiler::block_index_t blocks_number; ///< Total blocks number including their children
uint8_t depth; ///< Maximum stack depth (number of levels) uint8_t depth; ///< Maximum stack depth (number of levels)
BlocksTreeRoot(const This&) = delete; BlocksTreeRoot(const This&) = delete;
This& operator = (const This&) = delete; This& operator = (const This&) = delete;
@ -275,6 +289,12 @@ namespace profiler {
}; // END of class BlocksTreeRoot. }; // END of class BlocksTreeRoot.
struct BeginEndTime
{
profiler::timestamp_t beginTime;
profiler::timestamp_t endTime;
};
using blocks_t = profiler::BlocksTree::blocks_t; using blocks_t = profiler::BlocksTree::blocks_t;
using thread_blocks_tree_t = std::unordered_map<profiler::thread_id_t, profiler::BlocksTreeRoot, ::estd::hash<profiler::thread_id_t> >; using thread_blocks_tree_t = std::unordered_map<profiler::thread_id_t, profiler::BlocksTreeRoot, ::estd::hash<profiler::thread_id_t> >;
using block_getter_fn = std::function<const profiler::BlocksTree&(profiler::block_index_t)>; using block_getter_fn = std::function<const profiler::BlocksTree&(profiler::block_index_t)>;
@ -334,24 +354,28 @@ namespace profiler {
extern "C" { extern "C" {
PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename, PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks, profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors, profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::descriptors_list_t& descriptors,
profiler::blocks_t& _blocks, profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees, profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number, profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version, uint32_t& version,
profiler::processid_t& pid, profiler::processid_t& pid,
bool gather_statistics, bool gather_statistics,
std::ostream& _log); std::ostream& _log);
PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& str, PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& str,
profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks, profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors, profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::descriptors_list_t& descriptors,
profiler::blocks_t& _blocks, profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees, profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number, profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version, uint32_t& version,
profiler::processid_t& pid, profiler::processid_t& pid,
bool gather_statistics, bool gather_statistics,
@ -364,19 +388,22 @@ extern "C" {
} }
inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::SerializedData& serialized_blocks, inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors, profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::blocks_t& _blocks, profiler::descriptors_list_t& descriptors, profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees, profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number, profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version, uint32_t& version,
profiler::processid_t& pid, profiler::processid_t& pid,
bool gather_statistics, bool gather_statistics,
std::ostream& _log) std::ostream& _log)
{ {
std::atomic<int> progress = ATOMIC_VAR_INIT(0); std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, return fillTreesFromFile(progress, filename, begin_end_time, serialized_blocks, serialized_descriptors,
threaded_trees, total_descriptors_number, version, pid, gather_statistics, _log); descriptors, _blocks, threaded_trees, bookmarks, descriptors_count, version, pid,
gather_statistics, _log);
} }
inline bool readDescriptionsFromStream(std::istream& str, inline bool readDescriptionsFromStream(std::istream& str,

View File

@ -52,6 +52,7 @@ extern "C" {
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count, profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees, const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter, profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time, profiler::timestamp_t begin_time,
profiler::timestamp_t end_time, profiler::timestamp_t end_time,
@ -63,6 +64,7 @@ extern "C" {
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count, profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees, const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter, profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time, profiler::timestamp_t begin_time,
profiler::timestamp_t end_time, profiler::timestamp_t end_time,
@ -75,6 +77,7 @@ inline profiler::block_index_t writeTreesToFile(const char* filename,
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count, profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees, const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter, profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time, profiler::timestamp_t begin_time,
profiler::timestamp_t end_time, profiler::timestamp_t end_time,
@ -83,7 +86,7 @@ inline profiler::block_index_t writeTreesToFile(const char* filename,
{ {
std::atomic<int> progress = ATOMIC_VAR_INIT(0); std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return writeTreesToFile(progress, filename, serialized_descriptors, descriptors, descriptors_count, trees, return writeTreesToFile(progress, filename, serialized_descriptors, descriptors, descriptors_count, trees,
std::move(block_getter), begin_time, end_time, pid, log); bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
} }
inline profiler::block_index_t writeTreesToStream(std::ostream& str, inline profiler::block_index_t writeTreesToStream(std::ostream& str,
@ -91,6 +94,7 @@ inline profiler::block_index_t writeTreesToStream(std::ostream& str,
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count, profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees, const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter, profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time, profiler::timestamp_t begin_time,
profiler::timestamp_t end_time, profiler::timestamp_t end_time,
@ -99,7 +103,7 @@ inline profiler::block_index_t writeTreesToStream(std::ostream& str,
{ {
std::atomic<int> progress = ATOMIC_VAR_INIT(0); std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return writeTreesToStream(progress, str, serialized_descriptors, descriptors, descriptors_count, trees, return writeTreesToStream(progress, str, serialized_descriptors, descriptors, descriptors_count, trees,
std::move(block_getter), begin_time, end_time, pid, log); bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
} }
#endif //EASY_PROFILER_WRITER_H #endif //EASY_PROFILER_WRITER_H

View File

@ -1074,6 +1074,9 @@ uint32_t ProfileManager::dumpBlocksToStream(std::ostream& _outputStream, bool _l
write(_outputStream, m_descriptorsMemorySize); write(_outputStream, m_descriptorsMemorySize);
write(_outputStream, blocks_number); write(_outputStream, blocks_number);
write(_outputStream, static_cast<uint32_t>(m_descriptors.size())); write(_outputStream, static_cast<uint32_t>(m_descriptors.size()));
write(_outputStream, static_cast<uint32_t>(m_threads.size()));
write(_outputStream, static_cast<uint16_t>(0)); // Bookmarks count (they can be created by user in the UI)
write(_outputStream, static_cast<uint16_t>(0)); // padding
// Write block descriptors // Write block descriptors
for (const auto descriptor : m_descriptors) for (const auto descriptor : m_descriptors)
@ -1135,6 +1138,9 @@ uint32_t ProfileManager::dumpBlocksToStream(std::ostream& _outputStream, bool _l
} }
} }
// End of threads section
write(_outputStream, EASY_PROFILER_SIGNATURE);
m_storedSpin.unlock(); m_storedSpin.unlock();
m_spin.unlock(); m_spin.unlock();

View File

@ -49,9 +49,10 @@
* : limitations under the License. * : limitations under the License.
************************************************************************/ ************************************************************************/
#include <algorithm>
#include <fstream> #include <fstream>
#include <iterator> #include <iterator>
#include <algorithm> #include <limits>
#include <unordered_map> #include <unordered_map>
#include <thread> #include <thread>
@ -73,10 +74,11 @@ EASY_CONSTEXPR uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///<
EASY_CONSTEXPR uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file EASY_CONSTEXPR uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file
EASY_CONSTEXPR uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t EASY_CONSTEXPR uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t
EASY_CONSTEXPR uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged EASY_CONSTEXPR uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged
EASY_CONSTEXPR uint32_t EASY_V_210 = EASY_VERSION_INT(2, 1, 0); ///< in v2.1.0 user bookmarks were added
# undef EASY_VERSION_INT # undef EASY_VERSION_INT
const uint64_t TIME_FACTOR = 1000000000ULL; EASY_CONSTEXPR uint64_t TIME_FACTOR = 1000000000ULL;
// TODO: use 128 bit integer operations for better accuracy // TODO: use 128 bit integer operations for better accuracy
#define EASY_USE_FLOATING_POINT_CONVERSION #define EASY_USE_FLOATING_POINT_CONVERSION
@ -383,6 +385,31 @@ static bool update_progress(std::atomic<int>& progress, int new_value, std::ostr
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
static void read(std::istream& inStream, char* value, size_t size)
{
inStream.read(value, size);
}
template <class T>
static void read(std::istream& inStream, T& value)
{
read(inStream, (char*)&value, sizeof(T));
}
static bool tryReadMarker(std::istream& inStream, uint32_t& marker)
{
read(inStream, marker);
return marker == EASY_PROFILER_SIGNATURE;
}
static bool tryReadMarker(std::istream& inStream)
{
uint32_t marker = 0;
return tryReadMarker(inStream, marker);
}
//////////////////////////////////////////////////////////////////////////
struct EasyFileHeader struct EasyFileHeader
{ {
uint32_t signature = 0; uint32_t signature = 0;
@ -393,11 +420,14 @@ struct EasyFileHeader
profiler::timestamp_t end_time = 0; profiler::timestamp_t end_time = 0;
uint64_t memory_size = 0; uint64_t memory_size = 0;
uint64_t descriptors_memory_size = 0; uint64_t descriptors_memory_size = 0;
uint32_t total_blocks_number = 0; uint32_t blocks_count = 0;
uint32_t total_descriptors_number = 0; uint32_t descriptors_count = 0;
uint32_t threads_count = 0;
uint16_t bookmarks_count = 0;
uint16_t padding = 0;
}; };
static bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log) static bool readHeader_v1(EasyFileHeader& _header, std::istream& inStream, std::ostream& _log)
{ {
// File header before v2.0.0 // File header before v2.0.0
@ -406,82 +436,82 @@ static bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::os
if (_header.version < EASY_V_130) if (_header.version < EASY_V_130)
{ {
uint32_t old_pid = 0; uint32_t old_pid = 0;
inFile.read((char*)&old_pid, sizeof(uint32_t)); read(inStream, old_pid);
_header.pid = old_pid; _header.pid = old_pid;
} }
else else
{ {
inFile.read((char*)&_header.pid, sizeof(decltype(_header.pid))); read(inStream, _header.pid);
} }
} }
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t)); read(inStream, _header.cpu_frequency);
inFile.read((char*)&_header.begin_time, sizeof(profiler::timestamp_t)); read(inStream, _header.begin_time);
inFile.read((char*)&_header.end_time, sizeof(profiler::timestamp_t)); read(inStream, _header.end_time);
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t)); read(inStream, _header.blocks_count);
if (_header.total_blocks_number == 0) if (_header.blocks_count == 0)
{ {
_log << "Profiled blocks number == 0"; _log << "Profiled blocks number == 0";
return false; return false;
} }
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size))); read(inStream, _header.memory_size);
if (_header.memory_size == 0) if (_header.memory_size == 0)
{ {
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks"; _log << "Wrong memory size == 0 for " << _header.blocks_count << " blocks";
return false; return false;
} }
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t)); read(inStream, _header.descriptors_count);
if (_header.total_descriptors_number == 0) if (_header.descriptors_count == 0)
{ {
_log << "Blocks description number == 0"; _log << "Blocks description number == 0";
return false; return false;
} }
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size))); read(inStream, _header.descriptors_memory_size);
if (_header.descriptors_memory_size == 0) if (_header.descriptors_memory_size == 0)
{ {
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions"; _log << "Wrong memory size == 0 for " << _header.descriptors_count << " blocks descriptions";
return false; return false;
} }
return true; return true;
} }
static bool readHeader_v2(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log) static bool readHeader_v2(EasyFileHeader& _header, std::istream& inStream, std::ostream& _log)
{ {
// File header after v2.0.0 // File header after v2.0.0
inFile.read((char*)&_header.pid, sizeof(decltype(_header.pid))); read(inStream, _header.pid);
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t)); read(inStream, _header.cpu_frequency);
inFile.read((char*)&_header.begin_time, sizeof(profiler::timestamp_t)); read(inStream, _header.begin_time);
inFile.read((char*)&_header.end_time, sizeof(profiler::timestamp_t)); read(inStream, _header.end_time);
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size))); read(inStream, _header.memory_size);
if (_header.memory_size == 0) if (_header.memory_size == 0)
{ {
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks"; _log << "Wrong memory size == 0 for " << _header.blocks_count << " blocks";
return false; return false;
} }
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size))); read(inStream, _header.descriptors_memory_size);
if (_header.descriptors_memory_size == 0) if (_header.descriptors_memory_size == 0)
{ {
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions"; _log << "Wrong memory size == 0 for " << _header.descriptors_count << " blocks descriptions";
return false; return false;
} }
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t)); read(inStream, _header.blocks_count);
if (_header.total_blocks_number == 0) if (_header.blocks_count == 0)
{ {
_log << "Profiled blocks number == 0"; _log << "Profiled blocks number == 0";
return false; return false;
} }
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t)); read(inStream, _header.descriptors_count);
if (_header.total_descriptors_number == 0) if (_header.descriptors_count == 0)
{ {
_log << "Blocks description number == 0"; _log << "Blocks description number == 0";
return false; return false;
@ -490,15 +520,41 @@ static bool readHeader_v2(EasyFileHeader& _header, std::istream& inFile, std::os
return true; return true;
} }
static bool readHeader_v2_1(EasyFileHeader& _header, std::istream& inStream, std::ostream& _log)
{
if (!readHeader_v2(_header, inStream, _log))
return false;
read(inStream, _header.threads_count);
if (_header.threads_count == 0)
{
_log << "Threads count == 0.\nNothing to read.";
return false;
}
read(inStream, _header.bookmarks_count);
read(inStream, _header.padding);
if (_header.padding != 0)
{
_log << "Header padding != 0.\nFile corrupted.";
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
extern "C" PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename, extern "C" PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks, profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors, profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::descriptors_list_t& descriptors,
profiler::blocks_t& blocks, profiler::blocks_t& blocks,
profiler::thread_blocks_tree_t& threaded_trees, profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number, profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version, uint32_t& version,
profiler::processid_t& pid, profiler::processid_t& pid,
bool gather_statistics, bool gather_statistics,
@ -517,21 +573,24 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<in
} }
// Read data from file // Read data from file
auto result = fillTreesFromStream(progress, inFile, serialized_blocks, serialized_descriptors, descriptors, blocks, auto result = fillTreesFromStream(progress, inFile, begin_end_time, serialized_blocks, serialized_descriptors,
threaded_trees, total_descriptors_number, version, pid, gather_statistics, _log); descriptors, blocks, threaded_trees, bookmarks, descriptors_count, version, pid,
gather_statistics, _log);
return result; return result;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& inFile, extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& inStream,
profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks, profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors, profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::descriptors_list_t& descriptors,
profiler::blocks_t& blocks, profiler::blocks_t& blocks,
profiler::thread_blocks_tree_t& threaded_trees, profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number, profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version, uint32_t& version,
profiler::processid_t& pid, profiler::processid_t& pid,
bool gather_statistics, bool gather_statistics,
@ -545,18 +604,18 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
} }
uint32_t signature = 0; uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t)); if (!tryReadMarker(inStream, signature))
if (signature != EASY_PROFILER_SIGNATURE)
{ {
_log << "Wrong signature " << signature << "\nThis is not EasyProfiler file/stream."; _log << "Wrong signature " << signature << ".\nThis is not EasyProfiler file/stream.";
return 0; return 0;
} }
version = 0; version = 0;
inFile.read((char*)&version, sizeof(uint32_t)); read(inStream, version);
if (!isCompatibleVersion(version)) if (!isCompatibleVersion(version))
{ {
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff); _log << "Incompatible version: v"
<< (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
return 0; return 0;
} }
@ -566,12 +625,19 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
if (version < EASY_V_200) if (version < EASY_V_200)
{ {
if (!readHeader_v1(header, inFile, _log)) if (!readHeader_v1(header, inStream, _log))
return 0; return 0;
header.threads_count = std::numeric_limits<decltype(header.threads_count)>::max();
}
else if (version < EASY_V_210)
{
if (!readHeader_v2(header, inStream, _log))
return 0;
header.threads_count = std::numeric_limits<decltype(header.threads_count)>::max();
} }
else else
{ {
if (!readHeader_v2(header, inFile, _log)) if (!readHeader_v2_1(header, inStream, _log))
return 0; return 0;
} }
@ -585,8 +651,8 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
const auto memory_size = header.memory_size; const auto memory_size = header.memory_size;
const auto descriptors_memory_size = header.descriptors_memory_size; const auto descriptors_memory_size = header.descriptors_memory_size;
const auto total_blocks_number = header.total_blocks_number; const auto total_blocks_count = header.blocks_count;
total_descriptors_number = header.total_descriptors_number; descriptors_count = header.descriptors_count;
if (cpu_frequency != 0) if (cpu_frequency != 0)
{ {
@ -594,16 +660,19 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor); EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor);
} }
descriptors.reserve(total_descriptors_number); begin_end_time.beginTime = begin_time;
begin_end_time.endTime = end_time;
descriptors.reserve(descriptors_count);
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr; //const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
serialized_descriptors.set(descriptors_memory_size); serialized_descriptors.set(descriptors_memory_size);
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size()); //validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
uint64_t i = 0; uint64_t i = 0;
while (!inFile.eof() && descriptors.size() < total_descriptors_number) while (!inStream.eof() && descriptors.size() < descriptors_count)
{ {
uint16_t sz = 0; uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz)); read(inStream, sz);
if (sz == 0) if (sz == 0)
{ {
descriptors.push_back(nullptr); descriptors.push_back(nullptr);
@ -616,7 +685,7 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
//} //}
char* data = serialized_descriptors[i]; char* data = serialized_descriptors[i];
inFile.read(data, sz); read(inStream, data, sz);
auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data); auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data);
descriptors.push_back(descriptor); descriptors.push_back(descriptor);
@ -631,51 +700,59 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
PerThreadStats parent_statistics, frame_statistics; PerThreadStats parent_statistics, frame_statistics;
IdMap identification_table; IdMap identification_table;
blocks.reserve(total_blocks_number); blocks.reserve(total_blocks_count);
//olddata = append_regime ? serialized_blocks.data() : nullptr; //olddata = append_regime ? serialized_blocks.data() : nullptr;
serialized_blocks.set(memory_size); serialized_blocks.set(memory_size);
//validate_pointers(progress, olddata, serialized_blocks, blocks, blocks.size()); //validate_pointers(progress, olddata, serialized_blocks, blocks, blocks.size());
i = 0; i = 0;
uint32_t read_number = 0; uint32_t read_number = 0, threads_read_number = 0;
profiler::block_index_t blocks_counter = 0; profiler::block_index_t blocks_counter = 0;
std::vector<char> name; std::vector<char> name;
const size_t thread_id_t_size = version < EASY_V_130 ? sizeof(uint32_t) : sizeof(profiler::thread_id_t); while (!inStream.eof() && threads_read_number++ < header.threads_count)
while (!inFile.eof())
{ {
EASY_BLOCK("Read thread data", profiler::colors::DarkGreen); EASY_BLOCK("Read thread data", profiler::colors::DarkGreen);
profiler::thread_id_t thread_id = 0; profiler::thread_id_t thread_id = 0;
inFile.read((char*)&thread_id, thread_id_t_size); if (version < EASY_V_130)
if (inFile.eof()) {
uint32_t thread_id32 = 0;
read(inStream, thread_id32);
thread_id = thread_id32;
}
else
{
read(inStream, thread_id);
}
if (inStream.eof())
break; break;
auto& root = threaded_trees[thread_id]; auto& root = threaded_trees[thread_id];
uint16_t name_size = 0; uint16_t name_size = 0;
inFile.read((char*)&name_size, sizeof(uint16_t)); read(inStream, name_size);
if (name_size != 0) if (name_size != 0)
{ {
name.resize(name_size); name.resize(name_size);
inFile.read(name.data(), name_size); read(inStream, name.data(), name_size);
root.thread_name = name.data(); root.thread_name = name.data();
} }
CsStatsMap per_thread_statistics_cs; CsStatsMap per_thread_statistics_cs;
uint32_t blocks_number_in_thread = 0; uint32_t blocks_number_in_thread = 0;
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); read(inStream, blocks_number_in_thread);
auto threshold = read_number + blocks_number_in_thread; auto threshold = read_number + blocks_number_in_thread;
while (!inFile.eof() && read_number < threshold) while (!inStream.eof() && read_number < threshold)
{ {
EASY_BLOCK("Read context switch", profiler::colors::Green); EASY_BLOCK("Read context switch", profiler::colors::Green);
++read_number; ++read_number;
uint16_t sz = 0; uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz)); read(inStream, sz);
if (sz == 0) if (sz == 0)
{ {
_log << "Bad CSwitch block size == 0"; _log << "Bad CSwitch block size == 0";
@ -689,8 +766,9 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
} }
char* data = serialized_blocks[i]; char* data = serialized_blocks[i];
inFile.read(data, sz); read(inStream, data, sz);
i += sz; i += sz;
auto baseData = reinterpret_cast<profiler::SerializedCSwitch*>(data); auto baseData = reinterpret_cast<profiler::SerializedCSwitch*>(data);
auto t_begin = reinterpret_cast<profiler::timestamp_t*>(data); auto t_begin = reinterpret_cast<profiler::timestamp_t*>(data);
auto t_end = t_begin + 1; auto t_end = t_begin + 1;
@ -721,28 +799,28 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
} }
} }
if (!update_progress(progress, 20 + static_cast<int>(70 * i / memory_size), _log)) if (!update_progress(progress, 20 + static_cast<int>(67 * i / memory_size), _log))
{ {
return 0; // Loading interrupted return 0; // Loading interrupted
} }
} }
if (inFile.eof()) if (inStream.eof())
break; break;
StatsMap per_thread_statistics; StatsMap per_thread_statistics;
blocks_number_in_thread = 0; blocks_number_in_thread = 0;
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); read(inStream, blocks_number_in_thread);
threshold = read_number + blocks_number_in_thread; threshold = read_number + blocks_number_in_thread;
while (!inFile.eof() && read_number < threshold) while (!inStream.eof() && read_number < threshold)
{ {
EASY_BLOCK("Read block", profiler::colors::Green); EASY_BLOCK("Read block", profiler::colors::Green);
++read_number; ++read_number;
uint16_t sz = 0; uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz)); read(inStream, sz);
if (sz == 0) if (sz == 0)
{ {
_log << "Bad block size == 0"; _log << "Bad block size == 0";
@ -756,10 +834,10 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
} }
char* data = serialized_blocks[i]; char* data = serialized_blocks[i];
inFile.read(data, sz); read(inStream, data, sz);
i += sz; i += sz;
auto baseData = reinterpret_cast<profiler::SerializedBlock*>(data); auto baseData = reinterpret_cast<profiler::SerializedBlock*>(data);
if (baseData->id() >= total_descriptors_number) if (baseData->id() >= descriptors_count)
{ {
_log << "Bad block id == " << baseData->id(); _log << "Bad block id == " << baseData->id();
return 0; return 0;
@ -891,17 +969,83 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
} }
} }
if (!update_progress(progress, 20 + static_cast<int>(70 * i / memory_size), _log)) if (!update_progress(progress, 20 + static_cast<int>(67 * i / memory_size), _log))
{
return 0; // Loading interrupted return 0; // Loading interrupted
}
}
if (total_blocks_count != blocks_counter)
{
_log << "Read blocks count: " << blocks_counter
<< "\ndoes not match blocks count\nstored in header: " << total_blocks_count
<< ".\nFile corrupted.";
return 0;
}
if (!inStream.eof() && version >= EASY_V_210)
{
if (!tryReadMarker(inStream))
{
_log << "Bad threads section end mark.\nFile corrupted.";
return 0;
}
if (!inStream.eof() && header.bookmarks_count != 0)
{
// Read bookmarks
bookmarks.reserve(header.bookmarks_count);
std::vector<char> stringBuffer;
read_number = 0;
while (!inStream.eof() && read_number < header.bookmarks_count)
{
profiler::Bookmark bookmark;
uint16_t usedMemorySize = 0;
read(inStream, usedMemorySize);
read(inStream, bookmark.pos);
read(inStream, bookmark.color);
if (usedMemorySize < profiler::Bookmark::BaseSize)
{
_log << "Bad bookmark size: " << usedMemorySize
<< ", which is less than Bookmark::BaseSize: "
<< profiler::Bookmark::BaseSize;
return 0;
}
usedMemorySize -= static_cast<uint16_t>(profiler::Bookmark::BaseSize) - 1;
if (usedMemorySize > 1)
{
stringBuffer.resize(usedMemorySize);
inStream.read(stringBuffer.data(), usedMemorySize);
bookmark.text = stringBuffer.data();
}
else
{
bookmark.text.clear();
}
bookmarks.push_back(bookmark);
++read_number;
if (!update_progress(progress, 87 + static_cast<int>(3 * read_number / header.bookmarks_count), _log))
return 0; // Loading interrupted
}
if (!inStream.eof() && !tryReadMarker(inStream))
{
_log << "Bad bookmarks section end mark.\nFile corrupted.";
return 0;
} }
} }
} }
if (!update_progress(progress, 90, _log)) if (!update_progress(progress, 90, _log))
{
return 0; // Loading interrupted return 0; // Loading interrupted
}
EASY_BLOCK("Gather statistics for roots", profiler::colors::Purple); EASY_BLOCK("Gather statistics for roots", profiler::colors::Purple);
if (gather_statistics) if (gather_statistics)
@ -1012,7 +1156,7 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& inFile, extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& inStream,
profiler::SerializedData& serialized_descriptors, profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::descriptors_list_t& descriptors,
std::ostream& _log) std::ostream& _log)
@ -1022,7 +1166,7 @@ extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progre
progress.store(0); progress.store(0);
uint32_t signature = 0; uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t)); read(inStream, signature);
if (signature != EASY_PROFILER_SIGNATURE) if (signature != EASY_PROFILER_SIGNATURE)
{ {
_log << "Wrong file signature.\nThis is not EasyProfiler file/stream."; _log << "Wrong file signature.\nThis is not EasyProfiler file/stream.";
@ -1030,60 +1174,64 @@ extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progre
} }
uint32_t version = 0; uint32_t version = 0;
inFile.read((char*)&version, sizeof(uint32_t)); read(inStream, version);
if (!isCompatibleVersion(version)) if (!isCompatibleVersion(version))
{ {
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff); _log << "Incompatible version: v"
<< (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
return false; return false;
} }
uint32_t total_descriptors_number = 0; uint32_t descriptors_count = 0;
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); read(inStream, descriptors_count);
if (total_descriptors_number == 0) if (descriptors_count == 0)
{ {
_log << "Blocks description number == 0"; _log << "Blocks description number == 0";
return false; return false;
} }
uint64_t descriptors_memory_size = 0; uint64_t descriptors_memory_size = 0;
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); read(inStream, descriptors_memory_size);
if (descriptors_memory_size == 0) if (descriptors_memory_size == 0)
{ {
_log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions"; _log << "Wrong memory size == 0 for " << descriptors_count << " blocks descriptions";
return false; return false;
} }
descriptors.reserve(total_descriptors_number); descriptors.reserve(descriptors_count);
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr; //const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
serialized_descriptors.set(descriptors_memory_size); serialized_descriptors.set(descriptors_memory_size);
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size()); //validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
uint64_t i = 0; uint64_t i = 0;
while (!inFile.eof() && descriptors.size() < total_descriptors_number) while (!inStream.eof() && descriptors.size() < descriptors_count)
{ {
uint16_t sz = 0; uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz)); read(inStream, sz);
if (sz == 0) if (sz == 0)
{ {
descriptors.push_back(nullptr); //descriptors.push_back(nullptr);
continue; _log << "Zero descriptor size.\nFile/Stream corrupted.";
return false;
} }
//if (i + sz > descriptors_memory_size) { if (i + sz > descriptors_memory_size)
// printf("FILE CORRUPTED\n"); {
// return 0; _log << "Exceeded memory size.\npos: " << i << "\nsize: " << sz
//} << "\nnext pos: " << i + sz
<< "\nmax pos: " << descriptors_memory_size
<< "\nFile/Stream corrupted.";
return false;
}
char* data = serialized_descriptors[i]; char* data = serialized_descriptors[i];
inFile.read(data, sz); read(inStream, data, sz);
auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data); auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data);
descriptors.push_back(descriptor); descriptors.push_back(descriptor);
i += sz; i += sz;
if (!update_progress(progress, static_cast<int>(100 * i / descriptors_memory_size), _log)) if (!update_progress(progress, static_cast<int>(100 * i / descriptors_memory_size), _log))
{
return false; // Loading interrupted return false; // Loading interrupted
}
} }
return !descriptors.empty(); return !descriptors.empty();

View File

@ -63,6 +63,8 @@
extern const uint32_t EASY_PROFILER_SIGNATURE; extern const uint32_t EASY_PROFILER_SIGNATURE;
extern const uint32_t EASY_PROFILER_VERSION; extern const uint32_t EASY_PROFILER_VERSION;
EASY_CONSTEXPR auto BaseCSwitchSize = sizeof(profiler::SerializedCSwitch) + 1;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
struct BlocksRange struct BlocksRange
@ -71,7 +73,7 @@ struct BlocksRange
profiler::block_index_t end; profiler::block_index_t end;
BlocksRange(profiler::block_index_t size = 0) BlocksRange(profiler::block_index_t size = 0)
: begin(size), end(size) : begin(0), end(size)
{ {
} }
@ -181,6 +183,54 @@ static BlocksRange findRange(const profiler::BlocksTree::children_t& children, p
return range; return range;
} }
static BlocksRange findRange(const profiler::bookmarks_t& bookmarks, profiler::timestamp_t beginTime, profiler::timestamp_t endTime)
{
const auto size = static_cast<profiler::block_index_t>(bookmarks.size());
BlocksRange range(size);
if (size == 0)
return range;
if (beginTime <= bookmarks.front().pos && bookmarks.back().pos <= endTime)
return range; // All blocks inside range
auto first_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), beginTime,
[](const profiler::Bookmark& element, profiler::timestamp_t value)
{
return element.pos < value;
});
for (; first_it != bookmarks.end(); ++first_it)
{
const auto& bookmark = *first_it;
if (bookmark.pos >= beginTime)
break;
}
if (first_it != bookmarks.end() && first_it->pos <= endTime)
{
auto last_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), endTime,
[](const profiler::Bookmark& element, profiler::timestamp_t value)
{
return element.pos <= value;
});
if (last_it != bookmarks.end() && last_it->pos >= beginTime)
{
const auto begin = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), first_it));
const auto end = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), last_it));
if (begin <= end)
{
range.begin = begin;
range.end = end;
}
}
}
return range;
}
static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children, static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children,
const BlocksRange& range, const BlocksRange& range,
const profiler::block_getter_fn& getter, const profiler::block_getter_fn& getter,
@ -221,7 +271,7 @@ static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::Bl
for (auto i = range.begin; i < range.end; ++i) for (auto i = range.begin; i < range.end; ++i)
{ {
const auto& child = getter(children[i]); const auto& child = getter(children[i]);
const uint64_t usedMemorySize = sizeof(profiler::SerializedCSwitch) + strlen(child.cs->name()) + 1; const uint64_t usedMemorySize = BaseCSwitchSize + strlen(child.cs->name());
memoryAndCount.usedMemorySize += usedMemorySize; memoryAndCount.usedMemorySize += usedMemorySize;
++memoryAndCount.blocksCount; ++memoryAndCount.blocksCount;
} }
@ -284,8 +334,7 @@ static void serializeContextSwitches(std::ostream& output, std::vector<char>& bu
{ {
const auto& child = getter(children[i]); const auto& child = getter(children[i]);
const auto usedMemorySize = static_cast<uint16_t>( const auto usedMemorySize = static_cast<uint16_t>(BaseCSwitchSize + strlen(child.cs->name()));
sizeof(profiler::SerializedCSwitch) + strlen(child.cs->name()) + 1);
buffer.resize(usedMemorySize + sizeof(uint16_t)); buffer.resize(usedMemorySize + sizeof(uint16_t));
unaligned_store16(buffer.data(), usedMemorySize); unaligned_store16(buffer.data(), usedMemorySize);
@ -317,6 +366,20 @@ static void serializeDescriptors(std::ostream& output, std::vector<char>& buffer
} }
} }
static void serializeBookmarks(std::ostream& output, const profiler::bookmarks_t& bookmarks, const BlocksRange& range)
{
for (auto i = range.begin; i < range.end; ++i)
{
const auto& bookmark = bookmarks[i];
const auto usedMemorySize = static_cast<uint16_t>(profiler::Bookmark::BaseSize + bookmark.text.size());
write(output, usedMemorySize);
write(output, bookmark.pos);
write(output, bookmark.color);
write(output, bookmark.text.c_str(), bookmark.text.size() + 1);
}
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename, extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
@ -324,6 +387,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count, profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees, const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter, profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time, profiler::timestamp_t begin_time,
profiler::timestamp_t end_time, profiler::timestamp_t end_time,
@ -342,7 +406,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int
// Write data to file // Write data to file
auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors, descriptors_count, trees, auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors, descriptors_count, trees,
std::move(block_getter), begin_time, end_time, pid, log); bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
return result; return result;
} }
@ -354,6 +418,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count, profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees, const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter, profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time, profiler::timestamp_t begin_time,
profiler::timestamp_t end_time, profiler::timestamp_t end_time,
@ -412,6 +477,19 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
++i; ++i;
} }
BlocksRange bookmarksRange;
uint16_t bookmarksCount = 0;
if (!bookmarks.empty())
{
bookmarksRange = findRange(bookmarks, begin_time, end_time);
bookmarksCount = static_cast<uint16_t>(bookmarksRange.end - bookmarksRange.begin);
if (bookmarksCount != 0)
{
beginTime = std::min(beginTime, bookmarks[bookmarksRange.begin].pos);
endTime = std::max(endTime, bookmarks[bookmarksRange.end - 1].pos);
}
}
if (total.blocksCount == 0) if (total.blocksCount == 0)
{ {
log << "Nothing to save"; log << "Nothing to save";
@ -435,6 +513,9 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
write(str, usedMemorySizeDescriptors); write(str, usedMemorySizeDescriptors);
write(str, total.blocksCount); write(str, total.blocksCount);
write(str, descriptors_count); write(str, descriptors_count);
write(str, static_cast<uint32_t>(trees.size()));
write(str, bookmarksCount);
write(str, static_cast<uint16_t>(0)); // padding
std::vector<char> buffer; std::vector<char> buffer;
@ -464,10 +545,19 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
if (range.blocksMemoryAndCount.blocksCount != 0) if (range.blocksMemoryAndCount.blocksCount != 0)
serializeBlocks(str, buffer, tree.children, range.blocks, block_getter, descriptors); serializeBlocks(str, buffer, tree.children, range.blocks, block_getter, descriptors);
if (!update_progress_write(progress, 40 + 60 / static_cast<int>(trees.size() - i), log)) if (!update_progress_write(progress, 40 + 57 / static_cast<int>(trees.size() - i), log))
return 0; return 0;
} }
write(str, EASY_PROFILER_SIGNATURE);
// Serialize bookmarks
if (bookmarksCount != 0)
{
serializeBookmarks(str, bookmarks, bookmarksRange);
write(str, EASY_PROFILER_SIGNATURE);
}
return total.blocksCount; return total.blocksCount;
} }

View File

@ -20,11 +20,15 @@ if (Qt5Widgets_FOUND)
blocks_graphics_view.cpp blocks_graphics_view.cpp
blocks_tree_widget.h blocks_tree_widget.h
blocks_tree_widget.cpp blocks_tree_widget.cpp
bookmarks_editor.h
bookmarks_editor.cpp
common_functions.h common_functions.h
common_functions.cpp common_functions.cpp
common_types.h common_types.h
descriptors_tree_widget.h descriptors_tree_widget.h
descriptors_tree_widget.cpp descriptors_tree_widget.cpp
dialog.h
dialog.cpp
fps_widget.h fps_widget.h
fps_widget.cpp fps_widget.cpp
globals.h globals.h
@ -54,6 +58,8 @@ if (Qt5Widgets_FOUND)
tree_widget_item.cpp tree_widget_item.cpp
tree_widget_loader.h tree_widget_loader.h
tree_widget_loader.cpp tree_widget_loader.cpp
window_header.h
window_header.cpp
resources.qrc resources.qrc
resources.rc resources.rc
) )

View File

@ -56,7 +56,6 @@
#include <QActionGroup> #include <QActionGroup>
#include <QColor> #include <QColor>
#include <QComboBox> #include <QComboBox>
#include <QDialog>
#include <QFileDialog> #include <QFileDialog>
#include <QFileInfo> #include <QFileInfo>
#include <QGraphicsScene> #include <QGraphicsScene>
@ -77,6 +76,7 @@
#include <set> #include <set>
#include <cmath> #include <cmath>
#include "arbitrary_value_inspector.h" #include "arbitrary_value_inspector.h"
#include "dialog.h"
#include "globals.h" #include "globals.h"
#include "complexity_calculator.h" #include "complexity_calculator.h"
@ -2581,18 +2581,19 @@ void ArbitraryValuesWidget::onOpenInNewWindowClicked(bool)
{ {
saveSettings(); saveSettings();
auto dialog = new QDialog(nullptr); auto viewer = new ArbitraryValuesWidget(m_checkedItems, m_treeWidget->currentItem(), m_threadId, m_blockIndex, m_blockId);
#ifdef WIN32
const WindowHeader::Buttons buttons = WindowHeader::AllButtons;
#else
const WindowHeader::Buttons buttons {WindowHeader::MaximizeButton | WindowHeader::CloseButton};
#endif
auto dialog = new Dialog(nullptr, "EasyProfiler", viewer, buttons, QMessageBox::NoButton);
dialog->setProperty("stayVisible", true);
dialog->setAttribute(Qt::WA_DeleteOnClose, true); dialog->setAttribute(Qt::WA_DeleteOnClose, true);
dialog->setWindowTitle("EasyProfiler");
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::allDataGoingToBeDeleted, dialog, &QDialog::reject); connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::allDataGoingToBeDeleted, dialog, &QDialog::reject);
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::closeEvent, dialog, &QDialog::reject); connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::closeEvent, dialog, &QDialog::reject);
auto viewer = new ArbitraryValuesWidget(m_checkedItems, m_treeWidget->currentItem(), m_threadId, m_blockIndex, m_blockId, dialog);
auto layout = new QHBoxLayout(dialog);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(viewer);
// Load last dialog geometry // Load last dialog geometry
{ {
QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME); QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME);

View File

@ -61,7 +61,7 @@
ArbitraryValueToolTip::ArbitraryValueToolTip(const QString& _name ArbitraryValueToolTip::ArbitraryValueToolTip(const QString& _name
, const profiler::BlocksTree& _block, QWidget* _parent) , const profiler::BlocksTree& _block, QWidget* _parent)
: QWidget(_parent, Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint) : QWidget(_parent, Qt::Tool | Qt::SubWindow | Qt::FramelessWindowHint)
{ {
auto content = new QWidget(); auto content = new QWidget();
content->setObjectName("cnt"); content->setObjectName("cnt");

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,7 @@
#include <QGraphicsView> #include <QGraphicsView>
#include <QGraphicsItem> #include <QGraphicsItem>
#include <QPainterPath>
#include <QPoint> #include <QPoint>
#include <QRectF> #include <QRectF>
#include <QTimer> #include <QTimer>
@ -88,23 +89,84 @@ class GraphicsRulerItem;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define EASY_QGRAPHICSITEM(ClassName) \ class AuxItem : public QObject, public QGraphicsItem
class ClassName : public QGraphicsItem { \ {
QRectF m_boundingRect; \ Q_OBJECT;
public: \ Q_INTERFACES(QGraphicsItem);
ClassName() : QGraphicsItem() {} \
virtual ~ClassName() {} \
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override; \
QRectF boundingRect() const override { return m_boundingRect; } \
void setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); } \
void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } \
}
EASY_QGRAPHICSITEM(BackgroundItem); protected:
EASY_QGRAPHICSITEM(TimelineIndicatorItem);
EASY_QGRAPHICSITEM(ThreadNameItem);
#undef EASY_QGRAPHICSITEM QRectF m_boundingRect;
public:
explicit AuxItem() : QObject(nullptr), QGraphicsItem() {}
~AuxItem() override {}
QRectF boundingRect() const override { return m_boundingRect; }
void setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); }
void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; }
};
class ThreadNameItem : public AuxItem
{
public:
explicit ThreadNameItem() : AuxItem() {}
~ThreadNameItem() override {}
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
};
class BackgroundItem : public AuxItem
{
Q_OBJECT;
QTimer m_idleTimer;
QPainterPath m_bookmarkSign;
size_t m_bookmark;
bool m_bButtonPressed;
public:
explicit BackgroundItem();
~BackgroundItem() override {}
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
bool mouseMove(const QPointF& scenePos);
bool mousePress(const QPointF& scenePos);
bool mouseRelease(const QPointF& scenePos);
bool mouseDoubleClick(const QPointF& scenePos);
bool contains(const QPointF& scenePos) const;
signals:
void bookmarkChanged(size_t index);
void moved();
private slots:
void onIdleTimeout();
};
class ForegroundItem : public AuxItem
{
Q_OBJECT;
size_t m_bookmark;
public:
explicit ForegroundItem();
~ForegroundItem() override {}
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
public slots:
void onBookmarkChanged(size_t index);
void onMoved();
};
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -142,9 +204,10 @@ private:
QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent) QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent)
QPoint m_mouseMovePath; ///< Mouse move path between press and release of any button QPoint m_mouseMovePath; ///< Mouse move path between press and release of any button
Qt::MouseButtons m_mouseButtons; ///< Pressed mouse buttons Qt::MouseButtons m_mouseButtons; ///< Pressed mouse buttons
GraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget GraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget
GraphicsRulerItem* m_selectionItem; ///< Pointer to the GraphicsRulerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget. GraphicsRulerItem* m_selectionItem; ///< Pointer to the GraphicsRulerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget.
GraphicsRulerItem* m_rulerItem; ///< Pointer to the GraphicsRulerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time. GraphicsRulerItem* m_rulerItem; ///< Pointer to the GraphicsRulerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time.
BackgroundItem* m_backgroundItem; ///<
QWidget* m_popupWidget; ///< QWidget* m_popupWidget; ///<
int m_flickerSpeedX; ///< Current flicking speed x int m_flickerSpeedX; ///< Current flicking speed x
int m_flickerSpeedY; ///< Current flicking speed y int m_flickerSpeedY; ///< Current flicking speed y
@ -300,15 +363,19 @@ private:
QTimer m_idleTimer; ///< QTimer m_idleTimer; ///<
uint64_t m_idleTime; ///< uint64_t m_idleTime; ///<
BlocksGraphicsView* m_view; ///< BlocksGraphicsView* m_view; ///<
QGraphicsProxyWidget* m_popupWidget; ///< QWidget* m_popupWidget; ///<
int m_maxLength; ///< int m_maxLength; ///<
const int m_additionalHeight; ///< bool m_bHovered; ///<
char m_padding[3]; ///<
const int m_additionalHeight; ///<
public: public:
explicit ThreadNamesWidget(BlocksGraphicsView* _view, int _additionalHeight, QWidget* _parent = nullptr); explicit ThreadNamesWidget(BlocksGraphicsView* _view, int _additionalHeight, QWidget* _parent = nullptr);
~ThreadNamesWidget() override; ~ThreadNamesWidget() override;
void enterEvent(QEvent* _event) override;
void leaveEvent(QEvent* _event) override;
void mousePressEvent(QMouseEvent* _event) override; void mousePressEvent(QMouseEvent* _event) override;
void mouseDoubleClickEvent(QMouseEvent* _event) override; void mouseDoubleClickEvent(QMouseEvent* _event) override;
void mouseReleaseEvent(QMouseEvent* _event) override; void mouseReleaseEvent(QMouseEvent* _event) override;
@ -328,7 +395,7 @@ public:
private: private:
void removePopup(bool _removeFromScene = false); void removePopup();
private slots: private slots:

View File

@ -415,6 +415,13 @@ void BlocksTreeWidget::onIdleTimeout()
if (item->hasToolTip(column)) if (item->hasToolTip(column))
return; return;
auto focusWidget = qApp->focusWidget();
while (focusWidget != nullptr && !focusWidget->property("stayVisible").toBool())
focusWidget = focusWidget->parentWidget();
if (focusWidget != nullptr)
return;
m_valueTooltip = new ArbitraryValueToolTip(itemUnderCursor->text(COL_NAME), block, this); m_valueTooltip = new ArbitraryValueToolTip(itemUnderCursor->text(COL_NAME), block, this);
m_valueTooltip->move(QCursor::pos()); m_valueTooltip->move(QCursor::pos());
m_valueTooltip->show(); m_valueTooltip->show();

View File

@ -0,0 +1,188 @@
/************************************************************************
* file name : bookmarks_editor.cpp
* ----------------- :
* creation time : 2018/06/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of BookmarkEditor.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#include "bookmarks_editor.h"
#include "globals.h"
#include "window_header.h"
#include <easy/reader.h>
#include <QColorDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QStyle>
#include <QTextEdit>
BookmarkEditor::BookmarkEditor(size_t bookmarkIndex, bool isNew, QWidget* parent)
: Parent(parent)
, m_textEdit(nullptr)
, m_colorButton(nullptr)
, m_bookmarkIndex(bookmarkIndex)
, m_isNewBookmark(isNew)
{
setAttribute(Qt::WA_DeleteOnClose, true);
setModal(true);
const auto& bookmark = EASY_GLOBALS.bookmarks[m_bookmarkIndex];
auto saveButton = new QPushButton("Save");
connect(saveButton, &QPushButton::clicked, this, &This::onSaveClicked);
auto deleteButton = new QPushButton("Delete");
connect(deleteButton, &QPushButton::clicked, this, &This::onDeleteClicked);
deleteButton->setVisible(!isNew);
deleteButton->setEnabled(!isNew);
auto cancelButton = new QPushButton("Cancel");
connect(cancelButton, &QPushButton::clicked, this, &Parent::reject);
auto buttonBox = new QWidget();
buttonBox->setObjectName(QStringLiteral("BookmarkEditor_ButtonBox"));
auto buttonBoxLayout = new QHBoxLayout(buttonBox);
buttonBoxLayout->addStretch(1);
buttonBoxLayout->addWidget(saveButton);
buttonBoxLayout->addWidget(deleteButton);
buttonBoxLayout->addWidget(cancelButton);
m_textEdit = new QTextEdit();
m_textEdit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
m_textEdit->setText(QString::fromStdString(bookmark.text));
m_colorButton = new QPushButton();
m_colorButton->setObjectName(QStringLiteral("BookmarkEditor_ColorButton"));
m_colorButton->setAutoFillBackground(true);
connect(m_colorButton, &QPushButton::clicked, this, &This::onColorButtonClicked);
auto palette = m_colorButton->palette();
palette.setBrush(QPalette::Background, QBrush(QColor::fromRgb(bookmark.color)));
m_colorButton->setPalette(palette);
m_colorButton->setStyleSheet(QString("background-color: %1;").arg(QColor::fromRgb(bookmark.color).name()));
auto colorBox = new QWidget();
colorBox->setObjectName(QStringLiteral("BookmarkEditor_ColorBox"));
auto colorBoxLayout = new QHBoxLayout(colorBox);
colorBoxLayout->setContentsMargins(1, 0, 0, 2);
colorBoxLayout->addWidget(new QLabel("Description"), 0, Qt::AlignLeft | Qt::AlignVCenter);
colorBoxLayout->addStretch(1);
colorBoxLayout->addWidget(new QLabel("Color"), 0, Qt::AlignRight | Qt::AlignVCenter);
colorBoxLayout->addWidget(m_colorButton, 0, Qt::AlignRight | Qt::AlignVCenter);
auto content = new QWidget();
content->setObjectName(QStringLiteral("BookmarkEditor_Content"));
auto contentLayout = new QVBoxLayout(content);
contentLayout->setSpacing(0);
contentLayout->addWidget(colorBox);
contentLayout->addWidget(m_textEdit, 1);
const WindowHeader::Buttons buttons {WindowHeader::MaximizeButton | WindowHeader::CloseButton};
auto header = new WindowHeader(isNew ? "New bookmark" : "Edit bookmark", buttons, this);
auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(1, 1, 1, 1);
mainLayout->setSpacing(0);
mainLayout->addWidget(header, 0, Qt::AlignTop);
mainLayout->addWidget(content, 1);
mainLayout->addWidget(buttonBox, 0, Qt::AlignBottom);
connect(this, &QDialog::rejected, this, &This::onReject);
}
BookmarkEditor::~BookmarkEditor()
{
}
void BookmarkEditor::onSaveClicked(bool)
{
auto& bookmark = EASY_GLOBALS.bookmarks[m_bookmarkIndex];
bookmark.text = m_textEdit->toPlainText().toStdString();
bookmark.color = m_colorButton->palette().brush(QPalette::Background).color().rgb();
EASY_GLOBALS.bookmark_default_color = bookmark.color;
EASY_GLOBALS.has_local_changes = true;
accept();
}
void BookmarkEditor::onDeleteClicked(bool)
{
EASY_GLOBALS.has_local_changes = true;
EASY_GLOBALS.bookmarks.erase(EASY_GLOBALS.bookmarks.begin() + m_bookmarkIndex);
emit bookmarkRemoved(m_bookmarkIndex);
reject();
}
void BookmarkEditor::onColorButtonClicked(bool)
{
auto palette = m_colorButton->palette();
QColorDialog colorDialog(palette.brush(QPalette::Background).color(), this);
colorDialog.exec();
palette.setBrush(QPalette::Background, QBrush(colorDialog.currentColor()));
m_colorButton->setPalette(palette);
m_colorButton->setStyleSheet(QString("background-color: %1;").arg(colorDialog.currentColor().name()));
m_colorButton->style()->unpolish(m_colorButton);
m_colorButton->style()->polish(m_colorButton);
m_colorButton->update();
}
void BookmarkEditor::onReject()
{
if (m_isNewBookmark)
{
EASY_GLOBALS.bookmarks.erase(EASY_GLOBALS.bookmarks.begin() + m_bookmarkIndex);
emit bookmarkRemoved(m_bookmarkIndex);
}
}

View File

@ -0,0 +1,86 @@
/************************************************************************
* file name : bookmarks_editor.h
* ----------------- :
* creation time : 2018/06/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of BookmarkEditor.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#ifndef EASY_PROFILER_BOOKMARKS_EDITOR_H
#define EASY_PROFILER_BOOKMARKS_EDITOR_H
#include <QDialog>
class BookmarkEditor : public QDialog
{
Q_OBJECT;
using This = BookmarkEditor;
using Parent = QDialog;
class QTextEdit* m_textEdit;
class QPushButton* m_colorButton;
const size_t m_bookmarkIndex;
const bool m_isNewBookmark;
public:
explicit BookmarkEditor(size_t bookmarkIndex, bool isNew, QWidget* parent = nullptr);
~BookmarkEditor() override;
signals:
void bookmarkRemoved(size_t index);
private slots:
void onSaveClicked(bool);
void onDeleteClicked(bool);
void onColorButtonClicked(bool);
void onReject();
}; // class BookmarkEditor.
#endif // EASY_PROFILER_BOOKMARKS_EDITOR_H

View File

@ -58,16 +58,17 @@
#include <QRgb> #include <QRgb>
#include <QString> #include <QString>
#include <QFont> #include <QFont>
#include <stdlib.h>
#include <type_traits> #include <type_traits>
#include "common_types.h" #include "common_types.h"
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define PROF_MICROSECONDS(timestamp) ((timestamp) * 1e-3) #define PROF_MICROSECONDS(timestamp) (qreal(timestamp) * 1e-3)
//#define PROF_MICROSECONDS(timestamp) (timestamp) //#define PROF_MICROSECONDS(timestamp) (timestamp)
#define PROF_FROM_MICROSECONDS(to_timestamp) ((to_timestamp) * 1e3) #define PROF_FROM_MICROSECONDS(to_timestamp) static_cast<profiler::timestamp_t>((to_timestamp) * 1e3)
//#define PROF_FROM_MICROSECONDS(to_timestamp) (to_timestamp) //#define PROF_FROM_MICROSECONDS(to_timestamp) (to_timestamp)
#define PROF_MILLISECONDS(timestamp) ((timestamp) * 1e-6) #define PROF_MILLISECONDS(timestamp) ((timestamp) * 1e-6)
@ -76,7 +77,7 @@
#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e6) #define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e6)
//#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e3) //#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e3)
#define PROF_NANOSECONDS(timestamp) (timestamp) #define PROF_NANOSECONDS(timestamp) static_cast<profiler::timestamp_t>(timestamp)
//#define PROF_NANOSECONDS(timestamp) ((timestamp) * 1000) //#define PROF_NANOSECONDS(timestamp) ((timestamp) * 1000)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -167,6 +168,14 @@ inline EASY_CONSTEXPR_FCN ::profiler::color_t textColorForRgb(::profiler::color_
return isLightColor(_color) ? ::profiler::colors::Dark : ::profiler::colors::CreamWhite; return isLightColor(_color) ? ::profiler::colors::Dark : ::profiler::colors::CreamWhite;
} }
inline uint32_t rand255() {
return static_cast<uint32_t>(rand() % 255);
}
inline ::profiler::color_t randomColor() {
return toRgb(rand255(), rand255(), rand255());
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
qreal timeFactor(qreal _interval); qreal timeFactor(qreal _interval);

351
profiler_gui/dialog.cpp Normal file
View File

@ -0,0 +1,351 @@
/************************************************************************
* file name : dialog.cpp
* ----------------- :
* creation time : 2018/06/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of Dialog.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#include "dialog.h"
#include "window_header.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QPushButton>
#include <QSizePolicy>
#include <QStyle>
#include <QVBoxLayout>
Dialog::Dialog(QWidget* parent, const QString& title, QWidget* content, WindowHeader::Buttons headerButtons,
QMessageBox::StandardButtons buttons)
: QDialog(parent)
, m_buttonBox(new QWidget())
, m_header(nullptr)
, m_rejectRoleButton(QMessageBox::NoButton)
, m_acceptRoleButton(QMessageBox::NoButton)
{
setSizeGripEnabled(true);
m_header = new WindowHeader(title, headerButtons, this);
auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(1, 1, 1, 1);
mainLayout->setSpacing(0);
mainLayout->addWidget(m_header, 0, Qt::AlignTop);
mainLayout->addWidget(content, 1);
auto buttonsLayout = new QHBoxLayout(m_buttonBox);
if (buttons != QMessageBox::NoButton)
{
buttonsLayout->addStretch(1);
createButtons(buttonsLayout, buttons);
mainLayout->addWidget(m_buttonBox, 0, Qt::AlignBottom);
}
}
Dialog::Dialog(QWidget* parent, const QString& title, QWidget* content, QMessageBox::StandardButtons buttons)
: Dialog(parent, title, content, WindowHeader::CloseButton, buttons)
{
}
Dialog::Dialog(QWidget* parent, QMessageBox::Icon icon, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons)
: Dialog(parent, title, Dialog::messageBoxContent(icon, text), WindowHeader::CloseButton, buttons)
{
setSizeGripEnabled(false);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFixedSize(sizeHint());
}
Dialog::~Dialog()
{
}
void Dialog::setWindowTitle(const QString& title)
{
m_header->setTitle(title);
QDialog::setWindowTitle(title);
}
void Dialog::setWindowIcon(const QIcon& icon)
{
m_header->setWindowIcon(icon);
QDialog::setWindowIcon(icon);
}
void Dialog::addButton(class QAbstractButton* button, QDialogButtonBox::ButtonRole role)
{
button->setProperty("id", 0);
button->setProperty("role", static_cast<int>(role));
connect(button, &QAbstractButton::clicked, this, &Dialog::onButtonClicked);
m_buttonBox->layout()->addWidget(button);
}
void Dialog::addButton(class QAbstractButton* button, QMessageBox::ButtonRole role)
{
addButton(button, static_cast<QDialogButtonBox::ButtonRole>(role));
}
bool Dialog::isPositiveRole(QDialogButtonBox::ButtonRole role) const
{
return role == QDialogButtonBox::AcceptRole ||
role == QDialogButtonBox::ApplyRole ||
role == QDialogButtonBox::YesRole ||
role == QDialogButtonBox::NoRole;
}
bool Dialog::isNegativeRole(QDialogButtonBox::ButtonRole role) const
{
return role == QDialogButtonBox::RejectRole ||
role == QDialogButtonBox::DestructiveRole ||
role == QDialogButtonBox::ResetRole;
}
void Dialog::createButtons(class QHBoxLayout* buttonBoxLayout, QMessageBox::StandardButtons buttons)
{
for (int i = QMessageBox::FirstButton; i <= QMessageBox::LastButton; ++i)
{
const auto id = static_cast<QMessageBox::Button>(i);
if (buttons.testFlag(id))
{
auto button = createStandardButton(id);
if (button != nullptr)
buttonBoxLayout->addWidget(button);
}
}
}
QPushButton* Dialog::createStandardButton(QMessageBox::StandardButton id)
{
QString text;
auto role = QDialogButtonBox::RejectRole;
switch (id)
{
case QMessageBox::Ok:
text = "OK"; role = QDialogButtonBox::AcceptRole;
break;
case QMessageBox::Open:
text = "Open"; role = QDialogButtonBox::AcceptRole;
break;
case QMessageBox::Save:
text = "Save"; role = QDialogButtonBox::AcceptRole;
break;
case QMessageBox::Cancel:
text = "Cancel"; role = QDialogButtonBox::RejectRole;
break;
case QMessageBox::Close:
text = "Close"; role = QDialogButtonBox::RejectRole;
break;
case QMessageBox::Discard:
text = "Discard"; role = QDialogButtonBox::DestructiveRole;
break;
case QMessageBox::Apply:
text = "Apply"; role = QDialogButtonBox::ApplyRole;
break;
case QMessageBox::Reset:
text = "Reset"; role = QDialogButtonBox::ResetRole;
break;
case QMessageBox::RestoreDefaults:
text = "Restore defaults"; role = QDialogButtonBox::ResetRole;
break;
case QMessageBox::Help:
text = "Help"; role = QDialogButtonBox::HelpRole;
break;
case QMessageBox::SaveAll:
text = "Save all"; role = QDialogButtonBox::AcceptRole;
break;
case QMessageBox::Yes:
text = "Yes"; role = QDialogButtonBox::YesRole;
break;
case QMessageBox::YesToAll:
text = "Yes to all"; role = QDialogButtonBox::YesRole;
break;
case QMessageBox::No:
text = "No"; role = QDialogButtonBox::NoRole;
break;
case QMessageBox::NoToAll:
text = "No to all"; role = QDialogButtonBox::NoRole;
break;
case QMessageBox::Abort:
text = "Abort"; role = QDialogButtonBox::RejectRole;
break;
case QMessageBox::Retry:
text = "Retry"; role = QDialogButtonBox::AcceptRole;
break;
case QMessageBox::Ignore:
text = "Ignore"; role = QDialogButtonBox::AcceptRole;
break;
default:
return nullptr;
}
if (isPositiveRole(role) && m_acceptRoleButton == QMessageBox::NoButton)
m_acceptRoleButton = id;
else if (isNegativeRole(role) && m_rejectRoleButton == QMessageBox::NoButton)
m_rejectRoleButton = id;
auto button = new QPushButton(text);
button->setProperty("id", static_cast<int>(id));
button->setProperty("role", static_cast<int>(role));
connect(button, &QPushButton::clicked, this, &Dialog::onButtonClicked);
return button;
}
QMessageBox::StandardButton Dialog::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
{
Dialog dialog(parent, QMessageBox::Question, title, text, buttons);
return static_cast<QMessageBox::StandardButton>(dialog.exec());
}
QMessageBox::StandardButton Dialog::information(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
{
Dialog dialog(parent, QMessageBox::Information, title, text, buttons);
return static_cast<QMessageBox::StandardButton>(dialog.exec());
}
QMessageBox::StandardButton Dialog::warning(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
{
Dialog dialog(parent, QMessageBox::Warning, title, text, buttons);
return static_cast<QMessageBox::StandardButton>(dialog.exec());
}
QMessageBox::StandardButton Dialog::critical(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
{
Dialog dialog(parent, QMessageBox::Critical, title, text, buttons);
return static_cast<QMessageBox::StandardButton>(dialog.exec());
}
QWidget* Dialog::messageBoxContent(QMessageBox::Icon icon, const QString& text)
{
auto iconLabel = new QLabel();
auto style = QApplication::style();
const int size = style->pixelMetric(QStyle::PM_MessageBoxIconSize);
switch (icon)
{
case QMessageBox::Question:
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxQuestion).pixmap(size, size));
break;
case QMessageBox::Information:
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(size, size));
break;
case QMessageBox::Warning:
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(size, size));
break;
case QMessageBox::Critical:
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(size, size));
break;
default:
{
delete iconLabel;
iconLabel = nullptr;
break;
}
}
auto content = new QWidget();
auto layout = new QHBoxLayout(content);
if (iconLabel != nullptr)
{
layout->addWidget(iconLabel, 0, Qt::AlignTop);
layout->addSpacing(size / 4);
}
layout->addWidget(new QLabel(text), 1, Qt::AlignTop);
return content;
}
void Dialog::onButtonClicked(bool)
{
auto button = sender();
const auto id = static_cast<QMessageBox::Button>(button->property("id").toInt());
const auto role = static_cast<QMessageBox::ButtonRole>(button->property("role").toInt());
if (id == QMessageBox::NoButton)
QDialog::done(role);
else
QDialog::done(id);
}
void Dialog::done(int result)
{
if (result == QDialog::Rejected)
QDialog::done(m_rejectRoleButton);
else if (result == QDialog::Accepted)
QDialog::done(m_acceptRoleButton);
else
QDialog::done(result);
}

119
profiler_gui/dialog.h Normal file
View File

@ -0,0 +1,119 @@
/************************************************************************
* file name : dialog.h
* ----------------- :
* creation time : 2018/06/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of Dialog - a preferred base class
* : for all dialogs in the application.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#ifndef EASY_PROFILER_DIALOG_H
#define EASY_PROFILER_DIALOG_H
#include "window_header.h"
#include <QDialog>
#include <QDialogButtonBox>
#include <QMessageBox>
class Dialog : public QDialog
{
Q_OBJECT;
QWidget* m_buttonBox;
WindowHeader* m_header;
QMessageBox::StandardButton m_rejectRoleButton;
QMessageBox::StandardButton m_acceptRoleButton;
public:
explicit Dialog(QWidget* parent,
const QString& title,
QWidget* content,
QMessageBox::StandardButtons buttons = QMessageBox::Close);
explicit Dialog(QWidget* parent,
const QString& title,
QWidget* content,
WindowHeader::Buttons headerButtons,
QMessageBox::StandardButtons buttons = QMessageBox::Close);
explicit Dialog(QWidget* parent,
QMessageBox::Icon icon,
const QString& title,
const QString& text,
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
~Dialog() override;
static QMessageBox::StandardButton question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No);
static QMessageBox::StandardButton information(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok);
static QMessageBox::StandardButton warning(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Close);
static QMessageBox::StandardButton critical(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Close);
void addButton(class QAbstractButton* button, QDialogButtonBox::ButtonRole role);
void addButton(class QAbstractButton* button, QMessageBox::ButtonRole role);
void setWindowTitle(const QString& title);
void setWindowIcon(const QIcon& icon);
void done(int result) override;
private slots:
void onButtonClicked(bool);
private:
bool isPositiveRole(QDialogButtonBox::ButtonRole role) const;
bool isNegativeRole(QDialogButtonBox::ButtonRole role) const;
void createButtons(class QHBoxLayout* buttonBoxLayout, QMessageBox::StandardButtons buttons);
class QPushButton* createStandardButton(QMessageBox::StandardButton id);
static QWidget* messageBoxContent(QMessageBox::Icon icon, const QString& text);
}; // end of class Dialog.
#endif // EASY_PROFILER_DIALOG_H

View File

@ -92,9 +92,13 @@ namespace profiler_gui {
, max_fps_history(90) , max_fps_history(90)
, fps_timer_interval(500) , fps_timer_interval(500)
, fps_widget_line_width(2) , fps_widget_line_width(2)
, bookmark_default_color(0)
, chrono_text_position(RulerTextPosition_Top) , chrono_text_position(RulerTextPosition_Top)
, time_units(TimeUnits_ms) , time_units(TimeUnits_ms)
, connected(false) , connected(false)
, has_local_changes(false)
, use_custom_window_header(true)
, is_right_window_header_controls(true)
, fps_enabled(true) , fps_enabled(true)
, use_decorated_thread_name(false) , use_decorated_thread_name(false)
, hex_thread_id(false) , hex_thread_id(false)

View File

@ -196,6 +196,7 @@ namespace profiler_gui {
GlobalSignals events; ///< Global signals GlobalSignals events; ///< Global signals
::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file ::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file
::profiler::descriptors_list_t descriptors; ///< Profiler block descriptors list ::profiler::descriptors_list_t descriptors; ///< Profiler block descriptors list
::profiler::bookmarks_t bookmarks; ///< User bookmarks
EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
QString theme; ///< Current UI theme name QString theme; ///< Current UI theme name
@ -210,6 +211,7 @@ namespace profiler_gui {
::profiler::block_index_t selected_block; ///< Current selected profiler block index ::profiler::block_index_t selected_block; ///< Current selected profiler block index
::profiler::block_id_t selected_block_id; ///< Current selected profiler block id ::profiler::block_id_t selected_block_id; ///< Current selected profiler block id
uint32_t version; ///< Opened file version (files may have different format) uint32_t version; ///< Opened file version (files may have different format)
float frame_time; ///< Expected frame time value in microseconds to be displayed at minimap on graphics scrollbar float frame_time; ///< Expected frame time value in microseconds to be displayed at minimap on graphics scrollbar
int blocks_spacing; ///< Minimum blocks spacing on diagram int blocks_spacing; ///< Minimum blocks spacing on diagram
int blocks_size_min; ///< Minimum blocks size on diagram int blocks_size_min; ///< Minimum blocks size on diagram
@ -217,9 +219,16 @@ namespace profiler_gui {
int max_fps_history; ///< Max frames history displayed in FPS Monitor int max_fps_history; ///< Max frames history displayed in FPS Monitor
int fps_timer_interval; ///< Interval in milliseconds for sending network requests to the profiled application (used by FPS Monitor) int fps_timer_interval; ///< Interval in milliseconds for sending network requests to the profiled application (used by FPS Monitor)
int fps_widget_line_width; ///< Line width in pixels of FPS lines for FPS Monitor int fps_widget_line_width; ///< Line width in pixels of FPS lines for FPS Monitor
RulerTextPosition chrono_text_position; ///< Selected interval text position ::profiler::color_t bookmark_default_color; ///<
RulerTextPosition chrono_text_position; ///< Selected interval text position
TimeUnits time_units; ///< Units type for time (milliseconds, microseconds, nanoseconds or auto-definition) TimeUnits time_units; ///< Units type for time (milliseconds, microseconds, nanoseconds or auto-definition)
bool connected; ///< Is connected to source (to be able to capture profiling information) bool connected; ///< Is connected to source (to be able to capture profiling information)
bool has_local_changes; ///<
bool use_custom_window_header; ///<
bool is_right_window_header_controls; ///<
bool fps_enabled; ///< Is FPS Monitor enabled bool fps_enabled; ///< Is FPS Monitor enabled
bool use_decorated_thread_name; ///< Add "Thread" to the name of each thread (if there is no one) bool use_decorated_thread_name; ///< Add "Thread" to the name of each thread (if there is no one)
bool hex_thread_id; ///< Use hex view for thread-id instead of decimal bool hex_thread_id; ///< Use hex view for thread-id instead of decimal
@ -302,8 +311,12 @@ inline QSize applicationIconsSize() {
return QSize(EASY_GLOBALS.size.icon_size, EASY_GLOBALS.size.icon_size); return QSize(EASY_GLOBALS.size.icon_size, EASY_GLOBALS.size.icon_size);
} }
inline qreal pxf(int pixels) {
return pixels * EASY_GLOBALS.size.pixelRatio;
}
inline int px(int pixels) { inline int px(int pixels) {
return static_cast<int>(pixels * EASY_GLOBALS.size.pixelRatio + 0.5); return static_cast<int>(pxf(pixels) + 0.5);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -107,6 +107,9 @@ namespace profiler_gui {
void selectValue(::profiler::thread_id_t _thread_id, uint32_t _value_index, const ::profiler::ArbitraryValue& _value); void selectValue(::profiler::thread_id_t _thread_id, uint32_t _value_index, const ::profiler::ArbitraryValue& _value);
void customWindowHeaderChanged();
void windowHeaderPositionChanged();
}; // END of class GlobalSignals. }; // END of class GlobalSignals.
} // END of namespace profiler_gui. } // END of namespace profiler_gui.

View File

@ -1,9 +1,57 @@
/************************************************************************
* file name : graphics_image_item.cpp
* ----------------- :
* creation time : 2018/01/20
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of GraphicsImageItem.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QPainter> #include <QPainter>
#include "graphics_image_item.h" #include "graphics_image_item.h"
#include "graphics_slider_area.h" #include "graphics_slider_area.h"
#include "globals.h"
EASY_CONSTEXPR int TimerInterval = 40; EASY_CONSTEXPR int TimerInterval = 40;
EASY_CONSTEXPR int BoundaryTimerInterval = 100; EASY_CONSTEXPR int BoundaryTimerInterval = 100;

View File

@ -1,4 +1,53 @@
/************************************************************************
* file name : graphics_image_item.h
* ----------------- :
* creation time : 2018/01/20
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of GraphicsImageItem - an item
* : used to display, scroll and zoom QImage on graphics scene.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#ifndef EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H #ifndef EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H
#define EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H #define EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H

View File

@ -29,9 +29,12 @@ default/binoculars.svg - Icon made by Gregor Cresnar from www.flaticon
default/close-white.svg - Icon made by Cole Bemis from www.flaticon.com default/close-white.svg - Icon made by Cole Bemis from www.flaticon.com
default/close-white-hover.svg - Icon made by Cole Bemis from www.flaticon.com default/close-white-hover.svg - Icon made by Cole Bemis from www.flaticon.com
default/close-white-pressed.svg - Icon made by Cole Bemis from www.flaticon.com default/close-white-pressed.svg - Icon made by Cole Bemis from www.flaticon.com
default/close.svg - Icon made by Freepik from www.flaticon.com
default/close-hover.svg - Icon made by Freepik from www.flaticon.com
default/maximize-white.svg - Icon made by Freepik from www.flaticon.com default/maximize-white.svg - Icon made by Freepik from www.flaticon.com
default/maximize-white-hover.svg - Icon made by Freepik from www.flaticon.com default/maximize-white-hover.svg - Icon made by Freepik from www.flaticon.com
default/maximize-white-pressed.svg - Icon made by Freepik from www.flaticon.com default/maximize-white-pressed.svg - Icon made by Freepik from www.flaticon.com
default/minimize.svg - Icon made by Freepik from www.flaticon.com
default/minimize-white.svg - Icon made by Freepik from www.flaticon.com default/minimize-white.svg - Icon made by Freepik from www.flaticon.com
default/minimize-white-pressed.svg - Icon made by Freepik from www.flaticon.com default/minimize-white-pressed.svg - Icon made by Freepik from www.flaticon.com
default/arrow-down.svg - Icon made by Freepik from www.flaticon.com default/arrow-down.svg - Icon made by Freepik from www.flaticon.com
@ -48,4 +51,6 @@ default/crop.svg - Icon made by Freepik from www.flaticon.com
default/yx.svg - Icon made by Freepik from www.flaticon.com default/yx.svg - Icon made by Freepik from www.flaticon.com
default/svg2.svg - Icon made by Freepik from www.flaticon.com default/svg2.svg - Icon made by Freepik from www.flaticon.com
default/svg3.svg - Icon made by Freepik from www.flaticon.com default/svg3.svg - Icon made by Freepik from www.flaticon.com
default/to-fullscreen.svg - Icon made by Freepik from www.flaticon.com
default/to-window.svg - Icon made by Freepik from www.flaticon.com
default/window.svg - Icon made by Freepik from www.flaticon.com default/window.svg - Icon made by Freepik from www.flaticon.com

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<path fill="#ffffff" d="M368.854,347.642l-91.641-91.641l91.641-91.641c5.857-5.858,5.857-15.355-0.001-21.212
c-5.857-5.858-15.355-5.858-21.213,0L256,234.788l-91.641-91.641c-5.857-5.858-15.355-5.858-21.213,0
c-5.858,5.858-5.858,15.355,0,21.213l91.641,91.641l-91.641,91.641c-5.858,5.858-5.858,15.355,0,21.213
c2.929,2.929,6.768,4.393,10.606,4.393c3.839,0,7.678-1.464,10.607-4.393L256,277.214l91.641,91.641
c2.929,2.929,6.768,4.393,10.607,4.393s7.678-1.464,10.606-4.393C374.712,362.997,374.712,353.5,368.854,347.642z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<path fill="#504040" d="M368.854,347.642l-91.641-91.641l91.641-91.641c5.857-5.858,5.857-15.355-0.001-21.212
c-5.857-5.858-15.355-5.858-21.213,0L256,234.788l-91.641-91.641c-5.857-5.858-15.355-5.858-21.213,0
c-5.858,5.858-5.858,15.355,0,21.213l91.641,91.641l-91.641,91.641c-5.858,5.858-5.858,15.355,0,21.213
c2.929,2.929,6.768,4.393,10.606,4.393c3.839,0,7.678-1.464,10.607-4.393L256,277.214l91.641,91.641
c2.929,2.929,6.768,4.393,10.607,4.393s7.678-1.464,10.606-4.393C374.712,362.997,374.712,353.5,368.854,347.642z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<path fill="#504040" d="M400.601,241H111.399c-8.284,0-15,6.716-15,15s6.716,15,15,15H400.6c8.284,0,15-6.716,15-15
C415.601,247.716,408.885,241,400.601,241z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 530 B

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<path fill="#504040" d="M359.277,137.723H152.721c-8.284,0-15,6.716-15,15V359.28c0,8.284,6.716,15,15,15h206.557c8.284,0,15-6.716,15-15V152.723
C374.277,144.439,367.561,137.723,359.277,137.723z M344.278,344.279L344.278,344.279H167.721V167.723h176.557V344.279z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 633 B

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<!--g>
<g>
<path d="M416.667,0H95.333C42.766,0,0,42.767,0,95.334v321.333C0,469.234,42.766,512,95.333,512h321.334
C469.234,512,512,469.234,512,416.667V95.334C512,42.767,469.234,0,416.667,0z M482,416.667C482,452.692,452.692,482,416.667,482
H95.333C59.308,482,30,452.692,30,416.667V95.334C30,59.309,59.308,30,95.333,30h321.334C452.692,30,482,59.309,482,95.334
V416.667z"/>
</g>
</g-->
<g>
<path fill="#504040" d="M400.601,96.4H207.8c-8.284,0-15,6.716-15,15v81.4h-81.4c-8.284,0-15,6.716-15,15v192.801c0,8.284,6.716,15,15,15h192.8
c8.284,0,15-6.716,15-15v-81.4h81.4c8.284,0,15-6.716,15-15V111.4C415.601,103.116,408.885,96.4,400.601,96.4z M289.2,385.601
H126.4V222.8h162.8V385.601z M385.602,289.2h-0.001h-66.4v-81.4c0-8.284-6.716-15-15-15h-81.4v-66.4h162.801V289.2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -68,7 +68,6 @@
#include <QAction> #include <QAction>
#include <QCloseEvent> #include <QCloseEvent>
#include <QDateTime> #include <QDateTime>
#include <QDialog>
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QDragMoveEvent> #include <QDragMoveEvent>
#include <QDragLeaveEvent> #include <QDragLeaveEvent>
@ -106,6 +105,7 @@
#include "descriptors_tree_widget.h" #include "descriptors_tree_widget.h"
#include "fps_widget.h" #include "fps_widget.h"
#include "globals.h" #include "globals.h"
#include "dialog.h"
#include <easy/easy_net.h> #include <easy/easy_net.h>
#include <easy/profiler.h> #include <easy/profiler.h>
@ -253,9 +253,15 @@ void MainWindow::configureSizes()
EASY_GLOBALS.font.default_font = w.font(); EASY_GLOBALS.font.default_font = w.font();
const QFontMetricsF fm(w.font()); const QFontMetricsF fm(w.font());
#ifdef WIN32
EASY_CONSTEXPR qreal DefaultHeight = 16;
#else
EASY_CONSTEXPR qreal DefaultHeight = 17;
#endif
auto& size = EASY_GLOBALS.size; auto& size = EASY_GLOBALS.size;
size.pixelRatio = qApp->devicePixelRatio();
size.font_height = static_cast<int>(fm.height() + 0.5); size.font_height = static_cast<int>(fm.height() + 0.5);
size.pixelRatio = std::max(fm.height() / DefaultHeight, 1.0);
size.font_line_spacing = static_cast<int>(fm.lineSpacing() + 0.5); size.font_line_spacing = static_cast<int>(fm.lineSpacing() + 0.5);
size.graphics_row_height = size.font_height + px(4); size.graphics_row_height = size.font_height + px(4);
size.graphics_row_spacing = 0; size.graphics_row_spacing = 0;
@ -798,8 +804,40 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
menu->addSeparator(); submenu = menu->addMenu("Appearance");
submenu = menu->addMenu("Theme");
actionGroup = new QActionGroup(this);
actionGroup->setExclusive(true);
action = submenu->addAction("Custom window headers");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.use_custom_window_header);
connect(action, &QAction::triggered, [=] (bool checked)
{
actionGroup->setEnabled(checked);
onCustomWindowHeaderTriggered(checked);
});
action = new QAction("Position: right", actionGroup);
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.is_right_window_header_controls);
connect(action, &QAction::triggered, this, &This::onRightWindowHeaderPosition);
submenu->addAction(action);
action = new QAction("Position: left", actionGroup);
action->setCheckable(true);
action->setChecked(!EASY_GLOBALS.is_right_window_header_controls);
connect(action, &QAction::triggered, this, &This::onLeftWindowHeaderPosition);
submenu->addAction(action);
actionGroup->setEnabled(EASY_GLOBALS.use_custom_window_header);
submenu->addSeparator();
action = submenu->addAction("See viewport info");
connect(action, &QAction::triggered, this, &This::onViewportInfoClicked);
auto submenu2 = submenu->addMenu("Theme");
actionGroup = new QActionGroup(this); actionGroup = new QActionGroup(this);
actionGroup->setExclusive(true); actionGroup->setExclusive(true);
@ -809,16 +847,11 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
action->setCheckable(true); action->setCheckable(true);
action->setChecked(action->text() == EASY_GLOBALS.theme); action->setChecked(action->text() == EASY_GLOBALS.theme);
connect(action, &QAction::triggered, this, &MainWindow::onThemeChange); connect(action, &QAction::triggered, this, &MainWindow::onThemeChange);
submenu->addAction(action); submenu2->addAction(action);
} }
menu->addSeparator();
action = menu->addAction("See viewport info");
connect(action, &QAction::triggered, this, &This::onViewportInfoClicked);
auto tb_height = toolbar->height() + 4; auto tb_height = toolbar->height() + 4;
toolbar = addToolBar("FrameToolbar"); toolbar = addToolBar("FrameToolbar");
toolbar->setIconSize(applicationIconsSize()); toolbar->setIconSize(applicationIconsSize());
@ -906,7 +939,10 @@ void MainWindow::dropEvent(QDropEvent* drop_event)
if (m_bNetworkFileRegime) if (m_bNetworkFileRegime)
{ {
// Warn user about unsaved network information and suggest to save // Warn user about unsaved network information and suggest to save
auto result = QMessageBox::question(this, "Unsaved session", "You have unsaved data!\nSave before opening new file?", QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel); auto result = Dialog::question(this, "Unsaved session"
, "You have unsaved data!\nSave before opening new file?"
, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (result == QMessageBox::Yes) if (result == QMessageBox::Yes)
{ {
onSaveFileClicked(true); onSaveFileClicked(true);
@ -935,7 +971,8 @@ void MainWindow::onThemeChange(bool)
{ {
m_theme = std::move(newTheme); m_theme = std::move(newTheme);
QMessageBox::information(this, "UI theme changed", "You may need to restart the application\nto apply the theme correctly."); Dialog::information(this, "UI theme changed"
, "You may need to restart the application\nto apply the theme correctly.");
loadTheme(m_theme); loadTheme(m_theme);
validateLineEdits(); validateLineEdits();
@ -963,7 +1000,10 @@ void MainWindow::onOpenFileClicked(bool)
if (m_bNetworkFileRegime) if (m_bNetworkFileRegime)
{ {
// Warn user about unsaved network information and suggest to save // Warn user about unsaved network information and suggest to save
auto result = QMessageBox::question(this, "Unsaved session", "You have unsaved data!\nSave before opening new file?", QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel); auto result = Dialog::question(this, "Unsaved session"
, "You have unsaved data!\nSave before opening new file?"
, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (result == QMessageBox::Yes) if (result == QMessageBox::Yes)
{ {
onSaveFileClicked(true); onSaveFileClicked(true);
@ -981,8 +1021,35 @@ void MainWindow::onOpenFileClicked(bool)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void MainWindow::addFileToList(const QString& filename) void MainWindow::addFileToList(const QString& filename, bool changeWindowTitle)
{ {
auto index = m_lastFiles.indexOf(filename, 0);
if (index >= 0)
{
if (index != 0)
{
// This file has been already loaded. Move it to the front.
m_lastFiles.move(index, 0);
auto fileActions = m_loadActionMenu->actions();
auto action = fileActions.at(index);
m_loadActionMenu->removeAction(action);
m_loadActionMenu->insertAction(fileActions.front(), action);
validateLastDir();
}
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
if (changeWindowTitle)
{
if (m_bOpenedCacheFile)
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(filename));
else
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(filename));
}
return;
}
m_lastFiles.push_front(filename); m_lastFiles.push_front(filename);
validateLastDir(); validateLastDir();
@ -1004,10 +1071,13 @@ void MainWindow::addFileToList(const QString& filename)
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE); m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
if (m_bOpenedCacheFile) if (changeWindowTitle)
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(m_lastFiles.front())); {
else if (m_bOpenedCacheFile)
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(m_lastFiles.front())); setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(m_lastFiles.front()));
else
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(m_lastFiles.front()));
}
} }
void MainWindow::loadFile(const QString& filename) void MainWindow::loadFile(const QString& filename)
@ -1063,7 +1133,8 @@ void MainWindow::onSaveFileClicked(bool)
{ {
// Can not open the file! // Can not open the file!
QMessageBox::warning(this, "Warning", "Cannot open source file.\nSaving incomplete.", QMessageBox::Close); Dialog::warning(this, "Warning"
, "Cannot open source file.\nSaving incomplete.", QMessageBox::Close);
m_lastFiles.pop_front(); m_lastFiles.pop_front();
auto action = m_loadActionMenu->actions().front(); auto action = m_loadActionMenu->actions().front();
@ -1084,84 +1155,97 @@ void MainWindow::onSaveFileClicked(bool)
} }
auto filename = QFileDialog::getSaveFileName(this, "Save EasyProfiler File", dir, "EasyProfiler File (*.prof);;All Files (*.*)"); auto filename = QFileDialog::getSaveFileName(this, "Save EasyProfiler File", dir, "EasyProfiler File (*.prof);;All Files (*.*)");
if (!filename.isEmpty()) if (filename.isEmpty())
return;
if (EASY_GLOBALS.has_local_changes)
{ {
// Check if the same file has been selected createProgressDialog(tr("Saving file..."));
m_readerTimer.start();
m_reader.save(filename, m_beginEndTime.beginTime, m_beginEndTime.endTime, m_serializedDescriptors,
EASY_GLOBALS.descriptors, m_descriptorsNumberInFile, EASY_GLOBALS.profiler_blocks,
EASY_GLOBALS.bookmarks, easyBlocksTree, EASY_GLOBALS.pid, false);
return;
}
// Check if the same file has been selected
{
QFileInfo fileInfo1(m_bNetworkFileRegime ? QString(NETWORK_CACHE_FILE) : lastFile), fileInfo2(filename);
if (fileInfo1.exists() && fileInfo2.exists() && fileInfo1 == fileInfo2)
{ {
QFileInfo fileInfo1(m_bNetworkFileRegime ? QString(NETWORK_CACHE_FILE) : lastFile), fileInfo2(filename); // Selected the same file - do nothing
if (fileInfo1.exists() && fileInfo2.exists() && fileInfo1 == fileInfo2) return;
{ }
// Selected the same file - do nothing }
return;
} bool inOk = false, outOk = false;
int8_t retry1 = -1;
while (++retry1 < 4)
{
std::ifstream inFile(m_bNetworkFileRegime ? NETWORK_CACHE_FILE : lastFile.toStdString().c_str(), std::fstream::binary);
if (!inFile.is_open())
{
std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue;
} }
bool inOk = false, outOk = false; inOk = true;
int8_t retry1 = -1;
while (++retry1 < 4) int8_t retry2 = -1;
while (++retry2 < 4)
{ {
std::ifstream inFile(m_bNetworkFileRegime ? NETWORK_CACHE_FILE : lastFile.toStdString().c_str(), std::fstream::binary); std::ofstream outFile(filename.toStdString(), std::fstream::binary);
if (!inFile.is_open()) if (!outFile.is_open())
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue; continue;
} }
inOk = true; outFile << inFile.rdbuf();
outOk = true;
int8_t retry2 = -1;
while (++retry2 < 4)
{
std::ofstream outFile(filename.toStdString(), std::fstream::binary);
if (!outFile.is_open())
{
std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue;
}
outFile << inFile.rdbuf();
outOk = true;
break;
}
break; break;
} }
if (outOk) break;
}
if (outOk)
{
if (m_bNetworkFileRegime)
{ {
if (m_bNetworkFileRegime) // Remove temporary network cahche file
{ QFile::remove(QString(NETWORK_CACHE_FILE));
// Remove temporary network cahche file
QFile::remove(QString(NETWORK_CACHE_FILE));
}
else if (m_bOpenedCacheFile)
{
// Remove old temporary network cahche file
QFile::remove(lastFile.toStdString().c_str());
m_lastFiles.pop_front();
auto action = m_loadActionMenu->actions().front();
m_loadActionMenu->removeAction(action);
delete action;
validateLastDir();
}
addFileToList(filename);
m_bNetworkFileRegime = false;
} }
else if (inOk) else if (m_bOpenedCacheFile)
{ {
QMessageBox::warning(this, "Warning", "Cannot open destination file.\nSaving incomplete.", QMessageBox::Close); // Remove old temporary network cahche file
QFile::remove(lastFile.toStdString().c_str());
m_lastFiles.pop_front();
auto action = m_loadActionMenu->actions().front();
m_loadActionMenu->removeAction(action);
delete action;
validateLastDir();
} }
addFileToList(filename);
m_bNetworkFileRegime = false;
}
else if (inOk)
{
Dialog::warning(this, "Warning"
, "Cannot open destination file.\nSaving incomplete.", QMessageBox::Close);
}
else
{
if (m_bNetworkFileRegime)
Dialog::warning(this, "Warning"
, "Cannot open network cache file.\nSaving incomplete.", QMessageBox::Close);
else else
{ Dialog::warning(this, "Warning"
if (m_bNetworkFileRegime) , "Cannot open source file.\nSaving incomplete.", QMessageBox::Close);
QMessageBox::warning(this, "Warning", "Cannot open network cache file.\nSaving incomplete.", QMessageBox::Close);
else
QMessageBox::warning(this, "Warning", "Cannot open source file.\nSaving incomplete.", QMessageBox::Close);
}
} }
} }
@ -1206,7 +1290,9 @@ void MainWindow::onDeleteClicked(bool)
{ {
int button = QMessageBox::Yes; int button = QMessageBox::Yes;
if (m_bNetworkFileRegime) if (m_bNetworkFileRegime)
button = QMessageBox::question(this, "Clear all profiled data", "All profiled data and network cache file\nare going to be deleted!\nContinue?", QMessageBox::Yes, QMessageBox::No); button = Dialog::question(this, "Clear all profiled data"
, "All profiled data and network cache file\nare going to be deleted!\nContinue?"
, QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) if (button == QMessageBox::Yes)
clear(); clear();
@ -1325,7 +1411,7 @@ void MainWindow::onViewportInfoClicked(bool)
.arg(size.pixelRatio).arg(size.font_height).arg(size.font_line_spacing) .arg(size.pixelRatio).arg(size.font_height).arg(size.font_line_spacing)
.arg(size.graphics_row_height).arg(size.threads_row_spacing).arg(size.icon_size); .arg(size.graphics_row_height).arg(size.threads_row_spacing).arg(size.icon_size);
QMessageBox::information(this, "Viewport info", contents); Dialog::information(this, "Viewport info", contents);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -1378,21 +1464,19 @@ void MainWindow::onEditBlocksClicked(bool)
if (m_descTreeDialog.ptr != nullptr) if (m_descTreeDialog.ptr != nullptr)
{ {
m_descTreeDialog.ptr->raise(); m_descTreeDialog.ptr->raise();
m_descTreeDialog.ptr->setFocus();
return; return;
} }
m_descTreeDialog.create(); m_dialogDescTree = new BlockDescriptorsWidget();
m_descTreeDialog.create(m_dialogDescTree);
connect(m_descTreeDialog.ptr, &QDialog::finished, this, &This::onDescTreeDialogClose); connect(m_descTreeDialog.ptr, &QDialog::finished, this, &This::onDescTreeDialogClose);
m_dialogDescTree = new BlockDescriptorsWidget(m_descTreeDialog.ptr);
auto lay = new QVBoxLayout(m_descTreeDialog.ptr);
lay->addWidget(m_dialogDescTree);
m_dialogDescTree->build(); m_dialogDescTree->build();
m_descTreeDialog.restoreGeometry(); m_descTreeDialog.restoreGeometry();
m_descTreeDialog.ptr->show(); m_descTreeDialog.ptr->show();
m_descTreeDialog.ptr->setFocus();
} }
void MainWindow::onDescTreeDialogClose(int) void MainWindow::onDescTreeDialogClose(int)
@ -1423,13 +1507,21 @@ void MainWindow::showEvent(QShowEvent* show_event)
void MainWindow::closeEvent(QCloseEvent* close_event) void MainWindow::closeEvent(QCloseEvent* close_event)
{ {
if (m_bNetworkFileRegime) if (m_bNetworkFileRegime || EASY_GLOBALS.has_local_changes)
{ {
// Warn user about unsaved network information and suggest to save // Warn user about unsaved network information and suggest to save
if (QMessageBox::Yes == QMessageBox::question(this, "Unsaved session", "You have unsaved data!\nSave before exit?", QMessageBox::Yes, QMessageBox::No)) const auto result = Dialog::question(this, "Unsaved session"
, "You have unsaved data!\nSave before exit?", QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (result == QMessageBox::Yes)
{ {
onSaveFileClicked(true); onSaveFileClicked(true);
} }
else if (result == QMessageBox::Cancel)
{
close_event->ignore();
return;
}
} }
emit EASY_GLOBALS.events.closeEvent(); emit EASY_GLOBALS.events.closeEvent();
@ -1595,6 +1687,14 @@ void MainWindow::loadSettings()
m_theme = EASY_GLOBALS.theme; m_theme = EASY_GLOBALS.theme;
} }
flag = settings.value("use_custom_window_header");
if (!flag.isNull())
EASY_GLOBALS.use_custom_window_header = flag.toBool();
flag = settings.value("is_right_window_header_controls");
if (!flag.isNull())
EASY_GLOBALS.is_right_window_header_controls = flag.toBool();
settings.endGroup(); settings.endGroup();
} }
@ -1671,6 +1771,8 @@ void MainWindow::saveSettingsAndGeometry()
settings.setValue("fps_timer_interval", EASY_GLOBALS.fps_timer_interval); settings.setValue("fps_timer_interval", EASY_GLOBALS.fps_timer_interval);
settings.setValue("max_fps_history", EASY_GLOBALS.max_fps_history); settings.setValue("max_fps_history", EASY_GLOBALS.max_fps_history);
settings.setValue("fps_widget_line_width", EASY_GLOBALS.fps_widget_line_width); settings.setValue("fps_widget_line_width", EASY_GLOBALS.fps_widget_line_width);
settings.setValue("use_custom_window_header", EASY_GLOBALS.use_custom_window_header);
settings.setValue("is_right_window_header_controls", EASY_GLOBALS.is_right_window_header_controls);
settings.setValue("encoding", QTextCodec::codecForLocale()->name()); settings.setValue("encoding", QTextCodec::codecForLocale()->name());
settings.setValue("theme", m_theme); settings.setValue("theme", m_theme);
@ -1707,7 +1809,7 @@ void MainWindow::setDisconnected(bool _showMessage)
m_fpsRequestTimer.stop(); m_fpsRequestTimer.stop();
if (_showMessage) if (_showMessage)
QMessageBox::warning(this, "Warning", "Connection was lost", QMessageBox::Close); Dialog::warning(this, "Warning", "Connection was lost", QMessageBox::Close);
EASY_GLOBALS.connected = false; EASY_GLOBALS.connected = false;
m_captureAction->setEnabled(false); m_captureAction->setEnabled(false);
@ -1807,8 +1909,8 @@ void MainWindow::onListenerDialogClose(int _result)
{ {
case ListenerRegime::Capture: case ListenerRegime::Capture:
{ {
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Receiving data...", m_listenerDialog = new Dialog(this, QMessageBox::Information, "Receiving data...",
"This process may take some time.", QMessageBox::Cancel, this); "This process may take some time.", QMessageBox::Cancel);
m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true); m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true);
m_listenerDialog->show(); m_listenerDialog->show();
@ -1834,8 +1936,8 @@ void MainWindow::onListenerDialogClose(int _result)
{ {
if (_result == QDialog::Accepted) if (_result == QDialog::Accepted)
{ {
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Receiving data...", m_listenerDialog = new Dialog(this, QMessageBox::Information, "Receiving data...",
"This process may take some time.", QMessageBox::Cancel, this); "This process may take some time.", QMessageBox::Cancel);
connect(m_listenerDialog, &QDialog::finished, this, &This::onListenerDialogClose); connect(m_listenerDialog, &QDialog::finished, this, &This::onListenerDialogClose);
m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true); m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true);
m_listenerDialog->show(); m_listenerDialog->show();
@ -1922,58 +2024,41 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
if (_nblocks != 0) if (_nblocks != 0)
{ {
emit EASY_GLOBALS.events.allDataGoingToBeDeleted(); emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
EASY_GLOBALS.has_local_changes = false;
profiler::SerializedData serialized_blocks; profiler::SerializedData serialized_blocks;
profiler::SerializedData serialized_descriptors; profiler::SerializedData serialized_descriptors;
profiler::descriptors_list_t descriptors; profiler::descriptors_list_t descriptors;
profiler::blocks_t blocks; profiler::blocks_t blocks;
profiler::thread_blocks_tree_t threads_map; profiler::thread_blocks_tree_t threads_map;
profiler::bookmarks_t bookmarks;
profiler::BeginEndTime beginEndTime;
QString filename; QString filename;
uint32_t descriptorsNumberInFile = 0; uint32_t descriptorsNumberInFile = 0;
uint32_t version = 0; uint32_t version = 0;
profiler::processid_t pid = 0; profiler::processid_t pid = 0;
m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map, m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map,
descriptorsNumberInFile, version, pid, filename); bookmarks, beginEndTime, descriptorsNumberInFile, version, pid, filename);
if (threads_map.size() > 0xff) if (threads_map.size() > 0xff)
{ {
QString message;
if (m_reader.isFile()) if (m_reader.isFile())
qWarning() << "Warning: file " << filename << " contains " << threads_map.size() << " threads!"; message = QString("File %1 contains %2 threads!").arg(filename).arg(threads_map.size());
else else
qWarning() << "Warning: input stream contains " << threads_map.size() << " threads!"; message = QString("Input stream contains %1 threads!").arg(threads_map.size());
qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed.";
Dialog::warning(this, "Warning",
QString("%1\nCurrently, maximum number of displayed threads is 255!"
"\nSome threads will not be displayed.").arg(message), QMessageBox::Close);
} }
m_bNetworkFileRegime = !m_reader.isFile(); m_bNetworkFileRegime = !m_reader.isFile();
if (!m_bNetworkFileRegime) if (!m_bNetworkFileRegime)
{ {
auto index = m_lastFiles.indexOf(filename, 0); addFileToList(filename);
if (index == -1)
{
// This file is totally new. Add it to the list.
addFileToList(filename);
}
else
{
if (index != 0)
{
// This file has been already loaded. Move it to the front.
m_lastFiles.move(index, 0);
auto fileActions = m_loadActionMenu->actions();
auto action = fileActions.at(index);
m_loadActionMenu->removeAction(action);
m_loadActionMenu->insertAction(fileActions.front(), action);
validateLastDir();
}
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
if (m_bOpenedCacheFile)
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(filename));
else
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(filename));
}
} }
else else
{ {
@ -1984,6 +2069,7 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
m_serializedBlocks = std::move(serialized_blocks); m_serializedBlocks = std::move(serialized_blocks);
m_serializedDescriptors = std::move(serialized_descriptors); m_serializedDescriptors = std::move(serialized_descriptors);
m_descriptorsNumberInFile = descriptorsNumberInFile; m_descriptorsNumberInFile = descriptorsNumberInFile;
m_beginEndTime = beginEndTime;
EASY_GLOBALS.selected_thread = 0; EASY_GLOBALS.selected_thread = 0;
EASY_GLOBALS.version = version; EASY_GLOBALS.version = version;
EASY_GLOBALS.pid = pid; EASY_GLOBALS.pid = pid;
@ -1991,6 +2077,7 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
profiler_gui::set_max(EASY_GLOBALS.selected_block_id); profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
EASY_GLOBALS.profiler_blocks.swap(threads_map); EASY_GLOBALS.profiler_blocks.swap(threads_map);
EASY_GLOBALS.descriptors.swap(descriptors); EASY_GLOBALS.descriptors.swap(descriptors);
EASY_GLOBALS.bookmarks.swap(bookmarks);
EASY_GLOBALS.gui_blocks.clear(); EASY_GLOBALS.gui_blocks.clear();
EASY_GLOBALS.gui_blocks.resize(_nblocks); EASY_GLOBALS.gui_blocks.resize(_nblocks);
@ -2010,7 +2097,7 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
} }
else else
{ {
QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1") Dialog::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1")
.arg(m_reader.getError()), QMessageBox::Close); .arg(m_reader.getError()), QMessageBox::Close);
if (m_reader.isFile()) if (m_reader.isFile())
@ -2034,9 +2121,14 @@ void MainWindow::onSavingFinish()
const auto errorMessage = m_reader.getError(); const auto errorMessage = m_reader.getError();
if (!errorMessage.isEmpty()) if (!errorMessage.isEmpty())
{ {
QMessageBox::warning(this, "Warning", QString("Cannot save profiled blocks.\n\nReason:\n%1") Dialog::warning(this, "Warning", QString("Cannot save profiled blocks.\n\nReason:\n%1")
.arg(errorMessage), QMessageBox::Close); .arg(errorMessage), QMessageBox::Close);
} }
else
{
EASY_GLOBALS.has_local_changes = false;
addFileToList(m_reader.filename(), !m_reader.isSnapshot());
}
} }
void MainWindow::onFileReaderTimeout() void MainWindow::onFileReaderTimeout()
@ -2107,6 +2199,11 @@ const bool FileReader::isLoading() const
return m_jobType == JobType::Loading; return m_jobType == JobType::Loading;
} }
const bool FileReader::isSnapshot() const
{
return m_isSnapshot;
}
bool FileReader::done() const bool FileReader::done() const
{ {
return m_bDone.load(std::memory_order_acquire); return m_bDone.load(std::memory_order_acquire);
@ -2133,14 +2230,15 @@ void FileReader::load(const QString& _filename)
m_jobType = JobType::Loading; m_jobType = JobType::Loading;
m_isFile = true; m_isFile = true;
m_isSnapshot = false;
m_filename = _filename; m_filename = _filename;
m_thread = std::thread([this](bool _enableStatistics) m_thread = std::thread([this](bool _enableStatistics)
{ {
m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_beginEndTime, m_serializedBlocks,
m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree,
m_descriptorsNumberInFile, m_version, m_pid, _enableStatistics, m_bookmarks, m_descriptorsNumberInFile, m_version, m_pid,
m_errorMessage), std::memory_order_release); _enableStatistics, m_errorMessage), std::memory_order_release);
m_progress.store(100, std::memory_order_release); m_progress.store(100, std::memory_order_release);
m_bDone.store(true, std::memory_order_release); m_bDone.store(true, std::memory_order_release);
@ -2154,6 +2252,7 @@ void FileReader::load(std::stringstream& _stream)
m_jobType = JobType::Loading; m_jobType = JobType::Loading;
m_isFile = false; m_isFile = false;
m_isSnapshot = false;
m_filename.clear(); m_filename.clear();
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__llvm__) #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__llvm__)
@ -2175,8 +2274,8 @@ void FileReader::load(std::stringstream& _stream)
cache_file.close(); cache_file.close();
} }
m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors, m_size.store(fillTreesFromStream(m_progress, m_stream, m_beginEndTime, m_serializedBlocks, m_serializedDescriptors,
m_descriptors, m_blocks, m_blocksTree, m_descriptorsNumberInFile, m_descriptors, m_blocks, m_blocksTree, m_bookmarks, m_descriptorsNumberInFile,
m_version, m_pid, _enableStatistics, m_errorMessage), std::memory_order_release); m_version, m_pid, _enableStatistics, m_errorMessage), std::memory_order_release);
m_progress.store(100, std::memory_order_release); m_progress.store(100, std::memory_order_release);
@ -2188,26 +2287,28 @@ void FileReader::load(std::stringstream& _stream)
void FileReader::save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime, void FileReader::save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
const profiler::SerializedData& _serializedDescriptors, const profiler::SerializedData& _serializedDescriptors,
const profiler::descriptors_list_t& _descriptors, profiler::block_id_t descriptors_count, const profiler::descriptors_list_t& _descriptors, profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& _trees, profiler::block_getter_fn block_getter, const profiler::thread_blocks_tree_t& _trees, const profiler::bookmarks_t& bookmarks,
profiler::processid_t _pid) profiler::block_getter_fn block_getter, profiler::processid_t _pid, bool snapshotMode)
{ {
interrupt(); interrupt();
m_jobType = JobType::Saving; m_jobType = JobType::Saving;
m_isFile = true; m_isFile = true;
m_isSnapshot = snapshotMode;
m_filename = _filename; m_filename = _filename;
auto serializedDescriptors = std::ref(_serializedDescriptors); auto serializedDescriptors = std::ref(_serializedDescriptors);
auto descriptors = std::ref(_descriptors); auto descriptors = std::ref(_descriptors);
auto trees = std::ref(_trees); auto trees = std::ref(_trees);
auto bookmarksRef = std::ref(bookmarks);
m_thread = std::thread([=] (profiler::block_getter_fn getter) m_thread = std::thread([=] (profiler::block_getter_fn getter)
{ {
const QString tmpFile = m_filename + ".tmp"; const QString tmpFile = m_filename + ".tmp";
const auto result = writeTreesToFile(m_progress, tmpFile.toStdString().c_str(), serializedDescriptors, const auto result = writeTreesToFile(m_progress, tmpFile.toStdString().c_str(), serializedDescriptors,
descriptors, descriptors_count, trees, getter, _beginTime, _endTime, descriptors, descriptors_count, trees, bookmarksRef, getter,
_pid, m_errorMessage); _beginTime, _endTime, _pid, m_errorMessage);
if (result == 0 || !m_errorMessage.str().empty()) if (result == 0 || !m_errorMessage.str().empty())
{ {
@ -2243,10 +2344,12 @@ void FileReader::interrupt()
m_descriptors.clear(); m_descriptors.clear();
m_blocks.clear(); m_blocks.clear();
m_blocksTree.clear(); m_blocksTree.clear();
m_bookmarks.clear();
m_descriptorsNumberInFile = 0; m_descriptorsNumberInFile = 0;
m_version = 0; m_version = 0;
m_pid = 0; m_pid = 0;
m_jobType = JobType::Idle; m_jobType = JobType::Idle;
m_isSnapshot = false;
clear_stream(m_stream); clear_stream(m_stream);
clear_stream(m_errorMessage); clear_stream(m_errorMessage);
@ -2254,7 +2357,8 @@ void FileReader::interrupt()
void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors, void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& _trees, uint32_t& _descriptorsNumberInFile, uint32_t& _version, profiler::thread_blocks_tree_t& _trees, profiler::bookmarks_t& bookmarks,
profiler::BeginEndTime& beginEndTime, uint32_t& _descriptorsNumberInFile, uint32_t& _version,
profiler::processid_t& _pid, QString& _filename) profiler::processid_t& _pid, QString& _filename)
{ {
if (done()) if (done())
@ -2264,7 +2368,9 @@ void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::Seri
profiler::descriptors_list_t(std::move(m_descriptors)).swap(_descriptors); profiler::descriptors_list_t(std::move(m_descriptors)).swap(_descriptors);
m_blocks.swap(_blocks); m_blocks.swap(_blocks);
m_blocksTree.swap(_trees); m_blocksTree.swap(_trees);
m_bookmarks.swap(bookmarks);
m_filename.swap(_filename); m_filename.swap(_filename);
beginEndTime = m_beginEndTime;
_descriptorsNumberInFile = m_descriptorsNumberInFile; _descriptorsNumberInFile = m_descriptorsNumberInFile;
_version = m_version; _version = m_version;
_pid = m_pid; _pid = m_pid;
@ -2353,7 +2459,34 @@ void MainWindow::onSnapshotClicked(bool)
m_readerTimer.start(); m_readerTimer.start();
m_reader.save(filename, beginTime, endTime, m_serializedDescriptors, EASY_GLOBALS.descriptors, m_reader.save(filename, beginTime, endTime, m_serializedDescriptors, EASY_GLOBALS.descriptors,
m_descriptorsNumberInFile, EASY_GLOBALS.profiler_blocks, easyBlocksTree, EASY_GLOBALS.pid); m_descriptorsNumberInFile, EASY_GLOBALS.profiler_blocks, EASY_GLOBALS.bookmarks,
easyBlocksTree, EASY_GLOBALS.pid, true);
}
//////////////////////////////////////////////////////////////////////////
void MainWindow::onCustomWindowHeaderTriggered(bool _checked)
{
EASY_GLOBALS.use_custom_window_header = _checked;
emit EASY_GLOBALS.events.customWindowHeaderChanged();
}
void MainWindow::onRightWindowHeaderPosition(bool _checked)
{
if (!_checked)
return;
EASY_GLOBALS.is_right_window_header_controls = true;
emit EASY_GLOBALS.events.windowHeaderPositionChanged();
}
void MainWindow::onLeftWindowHeaderPosition(bool _checked)
{
if (!_checked)
return;
EASY_GLOBALS.is_right_window_header_controls = false;
emit EASY_GLOBALS.events.windowHeaderPositionChanged();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -2377,7 +2510,7 @@ void MainWindow::onConnectClicked(bool)
profiler::net::EasyProfilerStatus reply(false, false, false); profiler::net::EasyProfilerStatus reply(false, false, false);
if (!m_listener.connect(address.toStdString().c_str(), port, reply)) if (!m_listener.connect(address.toStdString().c_str(), port, reply))
{ {
QMessageBox::warning(this, "Warning", QString("Cannot connect to %1").arg(address), QMessageBox::Close); Dialog::warning(this, "Warning", QString("Cannot connect to %1").arg(address), QMessageBox::Close);
if (EASY_GLOBALS.connected) if (EASY_GLOBALS.connected)
{ {
m_listener.closeSocket(); m_listener.closeSocket();
@ -2437,7 +2570,7 @@ void MainWindow::onCaptureClicked(bool)
{ {
if (!EASY_GLOBALS.connected) if (!EASY_GLOBALS.connected)
{ {
QMessageBox::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close); Dialog::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close);
return; return;
} }
@ -2445,12 +2578,12 @@ void MainWindow::onCaptureClicked(bool)
{ {
if (m_listener.regime() == ListenerRegime::Capture || m_listener.regime() == ListenerRegime::Capture_Receive) if (m_listener.regime() == ListenerRegime::Capture || m_listener.regime() == ListenerRegime::Capture_Receive)
{ {
QMessageBox::warning(this, "Warning", Dialog::warning(this, "Warning",
"Already capturing frames.\nFinish old capturing session first.", QMessageBox::Close); "Already capturing frames.\nFinish old capturing session first.", QMessageBox::Close);
} }
else else
{ {
QMessageBox::warning(this, "Warning", Dialog::warning(this, "Warning",
"Capturing blocks description.\nFinish old capturing session first.", QMessageBox::Close); "Capturing blocks description.\nFinish old capturing session first.", QMessageBox::Close);
} }
@ -2479,7 +2612,8 @@ void MainWindow::onCaptureClicked(bool)
m_listenerTimer.start(250); m_listenerTimer.start(250);
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Capturing frames...", "Close this dialog to stop capturing.", QMessageBox::NoButton, this); m_listenerDialog = new Dialog(this, QMessageBox::Information, "Capturing frames..."
, "Close this dialog to stop capturing.", QMessageBox::NoButton);
auto button = new QToolButton(m_listenerDialog); auto button = new QToolButton(m_listenerDialog);
button->setAutoRaise(true); button->setAutoRaise(true);
@ -2498,7 +2632,7 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
{ {
if (!EASY_GLOBALS.connected) if (!EASY_GLOBALS.connected)
{ {
QMessageBox::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close); Dialog::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close);
return; return;
} }
@ -2506,20 +2640,20 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
{ {
if (m_listener.regime() == ListenerRegime::Descriptors) if (m_listener.regime() == ListenerRegime::Descriptors)
{ {
QMessageBox::warning(this, "Warning", Dialog::warning(this, "Warning",
"Already capturing blocks description.\nFinish old capturing session first.", QMessageBox::Close); "Already capturing blocks description.\nFinish old capturing session first.", QMessageBox::Close);
} }
else else
{ {
QMessageBox::warning(this, "Warning", Dialog::warning(this, "Warning",
"Already capturing frames.\nFinish old capturing session first.", QMessageBox::Close); "Already capturing frames.\nFinish old capturing session first.", QMessageBox::Close);
} }
return; return;
} }
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Waiting for blocks...", m_listenerDialog = new Dialog(this, QMessageBox::Information, "Waiting for blocks...",
"This may take some time.", QMessageBox::NoButton, this); "This may take some time.", QMessageBox::NoButton);
m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true); m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true);
m_listenerDialog->show(); m_listenerDialog->show();
@ -2543,11 +2677,11 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
const bool doFlush = m_descriptorsNumberInFile > descriptors.size(); const bool doFlush = m_descriptorsNumberInFile > descriptors.size();
if (doFlush && !m_serializedBlocks.empty()) if (doFlush && !m_serializedBlocks.empty())
{ {
auto button = QMessageBox::question(this, "Information", auto button = Dialog::question(this, "Information",
QString("New blocks description number = %1\nis less than the old one = %2.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?") QString("New blocks description number = %1\nis less than the old one = %2.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?")
.arg(descriptors.size()) .arg(descriptors.size())
.arg(m_descriptorsNumberInFile), .arg(m_descriptorsNumberInFile),
QMessageBox::Yes, QMessageBox::No); QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) if (button == QMessageBox::Yes)
clear(); // Clear all contents because new descriptors list conflicts with old one clear(); // Clear all contents because new descriptors list conflicts with old one
@ -2584,9 +2718,9 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
descriptors.resize(newnumber); descriptors.resize(newnumber);
// clear all profiled data to avoid conflicts // clear all profiled data to avoid conflicts
auto button = QMessageBox::question(this, "Information", auto button = Dialog::question(this, "Information",
"There are errors while merging block descriptions lists.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?", "There are errors while merging block descriptions lists.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?",
QMessageBox::Yes, QMessageBox::No); QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) if (button == QMessageBox::Yes)
clear(); // Clear all contents because new descriptors list conflicts with old one clear(); // Clear all contents because new descriptors list conflicts with old one
@ -2619,6 +2753,7 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
#endif #endif
m_dialogDescTree->build(); m_dialogDescTree->build();
m_descTreeDialog.ptr->raise(); m_descTreeDialog.ptr->raise();
m_descTreeDialog.ptr->setFocus();
} }
else else
{ {
@ -2629,7 +2764,9 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
} }
else else
{ {
QMessageBox::warning(this, "Warning", QString("Cannot read blocks description from stream.\n\nReason:\n%1").arg(errorMessage.str().c_str()), QMessageBox::Close); Dialog::warning(this, "Warning",
QString("Cannot read blocks description from stream.\n\nReason:\n%1")
.arg(errorMessage.str().c_str()), QMessageBox::Close);
} }
m_listener.clearData(); m_listener.clearData();
@ -2656,11 +2793,16 @@ void MainWindow::onSelectValue(profiler::thread_id_t _thread_id, uint32_t _value
m_dialogDescTree->dataViewer()->rebuild(_thread_id, _value_index, _value.id()); m_dialogDescTree->dataViewer()->rebuild(_thread_id, _value_index, _value.id());
} }
void DialogWithGeometry::create() void DialogWithGeometry::create(QWidget* content, QWidget* parent)
{ {
ptr = new QDialog(); #ifdef WIN32
const WindowHeader::Buttons buttons = WindowHeader::AllButtons;
#else
const WindowHeader::Buttons buttons {WindowHeader::MaximizeButton | WindowHeader::CloseButton};
#endif
ptr = new Dialog(parent, EASY_DEFAULT_WINDOW_TITLE, content, buttons, QMessageBox::NoButton);
ptr->setProperty("stayVisible", true);
ptr->setAttribute(Qt::WA_DeleteOnClose, true); ptr->setAttribute(Qt::WA_DeleteOnClose, true);
ptr->setWindowTitle(EASY_DEFAULT_WINDOW_TITLE);
} }
void DialogWithGeometry::saveGeometry() void DialogWithGeometry::saveGeometry()

View File

@ -96,7 +96,9 @@ class FileReader Q_DECL_FINAL
profiler::SerializedData m_serializedDescriptors; ///< profiler::SerializedData m_serializedDescriptors; ///<
profiler::descriptors_list_t m_descriptors; ///< profiler::descriptors_list_t m_descriptors; ///<
profiler::blocks_t m_blocks; ///< profiler::blocks_t m_blocks; ///<
profiler::thread_blocks_tree_t m_blocksTree; ///< profiler::thread_blocks_tree_t m_blocksTree; ///<
profiler::bookmarks_t m_bookmarks; ///<
profiler::BeginEndTime m_beginEndTime; ///<
std::stringstream m_stream; ///< std::stringstream m_stream; ///<
std::stringstream m_errorMessage; ///< std::stringstream m_errorMessage; ///<
QString m_filename; ///< QString m_filename; ///<
@ -109,6 +111,7 @@ class FileReader Q_DECL_FINAL
std::atomic<unsigned int> m_size; ///< std::atomic<unsigned int> m_size; ///<
JobType m_jobType = JobType::Idle; ///< JobType m_jobType = JobType::Idle; ///<
bool m_isFile = false; ///< bool m_isFile = false; ///<
bool m_isSnapshot = false; ///<
public: public:
@ -118,6 +121,7 @@ public:
const bool isFile() const; const bool isFile() const;
const bool isSaving() const; const bool isSaving() const;
const bool isLoading() const; const bool isLoading() const;
const bool isSnapshot() const;
bool done() const; bool done() const;
int progress() const; int progress() const;
@ -132,12 +136,14 @@ public:
void save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime, void save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
const profiler::SerializedData& _serializedDescriptors, const profiler::descriptors_list_t& _descriptors, const profiler::SerializedData& _serializedDescriptors, const profiler::descriptors_list_t& _descriptors,
profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& _trees, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& _trees,
profiler::block_getter_fn block_getter, profiler::processid_t _pid); const profiler::bookmarks_t& bookmarks, profiler::block_getter_fn block_getter,
profiler::processid_t _pid, bool snapshotMode);
void interrupt(); void interrupt();
void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors, void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _trees, profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _trees,
uint32_t& _descriptorsNumberInFile, uint32_t& _version, profiler::processid_t& _pid, QString& _filename); profiler::bookmarks_t& bookmarks, profiler::BeginEndTime& beginEndTime, uint32_t& _descriptorsNumberInFile,
uint32_t& _version, profiler::processid_t& _pid, QString& _filename);
void join(); void join();
@ -236,9 +242,9 @@ private slots:
struct DialogWithGeometry EASY_FINAL struct DialogWithGeometry EASY_FINAL
{ {
QByteArray geometry; QByteArray geometry;
class QDialog* ptr = nullptr; class Dialog* ptr = nullptr;
void create(); void create(QWidget* content, QWidget* parent = nullptr);
void saveGeometry(); void saveGeometry();
void restoreGeometry(); void restoreGeometry();
@ -269,12 +275,13 @@ protected:
class QProgressDialog* m_progress = nullptr; class QProgressDialog* m_progress = nullptr;
class BlockDescriptorsWidget* m_dialogDescTree = nullptr; class BlockDescriptorsWidget* m_dialogDescTree = nullptr;
class QMessageBox* m_listenerDialog = nullptr; class Dialog* m_listenerDialog = nullptr;
QTimer m_readerTimer; QTimer m_readerTimer;
QTimer m_listenerTimer; QTimer m_listenerTimer;
QTimer m_fpsRequestTimer; QTimer m_fpsRequestTimer;
profiler::SerializedData m_serializedBlocks; profiler::SerializedData m_serializedBlocks;
profiler::SerializedData m_serializedDescriptors; profiler::SerializedData m_serializedDescriptors;
profiler::BeginEndTime m_beginEndTime;
FileReader m_reader; FileReader m_reader;
SocketListener m_listener; SocketListener m_listener;
@ -349,6 +356,9 @@ protected slots:
void onFrameTimeEditFinish(); void onFrameTimeEditFinish();
void onFrameTimeChanged(); void onFrameTimeChanged();
void onSnapshotClicked(bool); void onSnapshotClicked(bool);
void onCustomWindowHeaderTriggered(bool _checked);
void onRightWindowHeaderPosition(bool _checked);
void onLeftWindowHeaderPosition(bool _checked);
void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status); void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
@ -372,7 +382,7 @@ private:
void refreshDiagram(); void refreshDiagram();
void addFileToList(const QString& filename); void addFileToList(const QString& filename, bool changeWindowTitle = true);
void loadFile(const QString& filename); void loadFile(const QString& filename);
void readStream(std::stringstream& data); void readStream(std::stringstream& data);

View File

@ -7,12 +7,17 @@
</qresource> </qresource>
<qresource prefix="/images/default"> <qresource prefix="/images/default">
<file alias="binoculars">images/default/binoculars.svg</file> <file alias="binoculars">images/default/binoculars.svg</file>
<file alias="close">images/default/close.svg</file>
<file alias="close-hover">images/default/close-hover.svg</file>
<file alias="crop">images/default/crop.svg</file> <file alias="crop">images/default/crop.svg</file>
<file alias="exit">images/default/off.svg</file> <file alias="exit">images/default/off.svg</file>
<file alias="open">images/default/open-folder2.svg</file> <file alias="open">images/default/open-folder2.svg</file>
<file alias="reload">images/default/reload.svg</file> <file alias="reload">images/default/reload.svg</file>
<file alias="expand">images/default/expand.svg</file> <file alias="expand">images/default/expand.svg</file>
<file alias="collapse">images/default/collapse.svg</file> <file alias="collapse">images/default/collapse.svg</file>
<file alias="to-fullscreen">images/default/to-fullscreen.svg</file>
<file alias="to-window">images/default/to-window.svg</file>
<file alias="minimize">images/default/minimize.svg</file>
<file alias="save">images/default/save.svg</file> <file alias="save">images/default/save.svg</file>
<file alias="stats">images/default/statistics.svg</file> <file alias="stats">images/default/statistics.svg</file>
<file alias="stats-off">images/default/statistics2.svg</file> <file alias="stats-off">images/default/statistics2.svg</file>

View File

@ -20,7 +20,7 @@ RoundProgressIndicator {
background: transparent; } background: transparent; }
MainWindow, QToolBar, QDialog { MainWindow, QToolBar, QDialog {
background-color: #f8f2f2; } background-color: white; }
QToolTip { QToolTip {
background-color: #ffeccc; background-color: #ffeccc;
@ -393,3 +393,72 @@ QScrollBar::handle:horizontal:hover, QScrollBar::handle:horizontal:pressed {
QScrollBar::add-line, QScrollBar::sub-line { QScrollBar::add-line, QScrollBar::sub-line {
background: none; background: none;
border: none; } border: none; }
WindowHeader {
background-color: white;
height: 24ex;
min-height: 24ex;
max-height: 24ex;
margin: 0;
padding: 0 0 0 6ex;
border: none; }
WindowHeader QPushButton {
margin: 0;
padding: 0;
border: none;
border-bottom: 1px solid transparent; }
WindowHeader QPushButton:hover {
border: none; }
WindowHeader QPushButton#WindowHeader_CloseButton {
image: url(":/images/default/close");
padding: 1ex; }
WindowHeader QPushButton#WindowHeader_CloseButton:hover {
image: url(":/images/default/close-hover");
background-color: #f44336;
border-bottom: 1px solid #f44336; }
WindowHeader QPushButton#WindowHeader_CloseButton:pressed {
background-color: #ea1c0d;
border-bottom: 1px solid #ea1c0d; }
WindowHeader QPushButton#WindowHeader_MinButton {
image: url(":/images/default/minimize");
padding: 2ex; }
WindowHeader QPushButton#WindowHeader_MinButton:hover {
background-color: #d1d1d1;
border-bottom: 1px solid #d1d1d1; }
WindowHeader QPushButton#WindowHeader_MinButton:pressed {
background-color: #c4c4c4;
border-bottom: 1px solid #c4c4c4; }
WindowHeader QPushButton#WindowHeader_MaxButton {
image: url(":/images/default/to-fullscreen");
padding: 1ex; }
WindowHeader QPushButton#WindowHeader_MaxButton[max=true] {
image: url(":/images/default/to-window");
padding: 1ex; }
WindowHeader QPushButton#WindowHeader_MaxButton:hover {
background-color: #d1d1d1;
border-bottom: 1px solid #d1d1d1; }
WindowHeader QPushButton#WindowHeader_MaxButton:pressed {
background-color: #c4c4c4;
border-bottom: 1px solid #c4c4c4; }
WindowHeader[left=true] {
padding: 0; }
BookmarkEditor {
background-color: white;
border: 1px solid #c4c4c4; }
BookmarkEditor QWidget#BookmarkEditor_ColorBox {
margin: 0;
padding: 0; }
BookmarkEditor QWidget#BookmarkEditor_ColorBox QPushButton#BookmarkEditor_ColorButton {
min-width: 15ex;
max-width: 15ex;
width: 15ex;
margin: 0;
padding: 0; }
BookmarkEditor QWidget#BookmarkEditor_ButtonBox {
border: none; }
Dialog {
border: 1px solid #c4c4c4;
background-color: white; }

View File

@ -44,6 +44,7 @@ $FocusBorderColor: $DarkSelectionColor;//#ffbcbc;
$TooltipColor: #ffeccc; $TooltipColor: #ffeccc;
$InputHeight: 15ex; $InputHeight: 15ex;
$WindowHeaderSize: 24ex;
// STYLES ------------------------------------------------- // STYLES -------------------------------------------------
* { * {
@ -63,7 +64,7 @@ RoundProgressIndicator {
} }
MainWindow, QToolBar, QDialog { MainWindow, QToolBar, QDialog {
background-color: #f8f2f2; background-color: $BackgroundColor;
} }
QToolTip { QToolTip {
@ -500,3 +501,106 @@ QScrollBar::add-line, QScrollBar::sub-line {
background: none; background: none;
border: none; border: none;
} }
WindowHeader {
background-color: white;
height: $WindowHeaderSize;
min-height: $WindowHeaderSize;
max-height: $WindowHeaderSize;
margin: 0;
padding: 0 0 0 6ex;
border: none;
QPushButton {
margin: 0;
padding: 0;
border: none;
border-bottom: 1px solid transparent;
}
QPushButton:hover {
border: none;
}
QPushButton#WindowHeader_CloseButton {
image: url(":/images/default/close");
padding: 1ex;
}
QPushButton#WindowHeader_CloseButton:hover {
image: url(":/images/default/close-hover");
background-color: $MainColor;
border-bottom: 1px solid $MainColor;
}
QPushButton#WindowHeader_CloseButton:pressed {
background-color: darken($MainColor, 10%);
border-bottom: 1px solid darken($MainColor, 10%);
}
QPushButton#WindowHeader_MinButton {
image: url(":/images/default/minimize");
padding: 2ex;
}
QPushButton#WindowHeader_MinButton:hover {
background-color: lighten($BorderColor, 5%);
border-bottom: 1px solid lighten($BorderColor, 5%);
}
QPushButton#WindowHeader_MinButton:pressed {
background-color: $BorderColor;
border-bottom: 1px solid $BorderColor;
}
QPushButton#WindowHeader_MaxButton {
image: url(":/images/default/to-fullscreen");
padding: 1ex;
}
QPushButton#WindowHeader_MaxButton[max=true] {
image: url(":/images/default/to-window");
padding: 1ex;
}
QPushButton#WindowHeader_MaxButton:hover {
background-color: lighten($BorderColor, 5%);
border-bottom: 1px solid lighten($BorderColor, 5%);
}
QPushButton#WindowHeader_MaxButton:pressed {
background-color: $BorderColor;
border-bottom: 1px solid $BorderColor;
}
}
WindowHeader[left=true] {
padding: 0;
}
BookmarkEditor {
background-color: white;
border: 1px solid $BorderColor;
QWidget#BookmarkEditor_ColorBox {
margin: 0;
padding: 0;
QPushButton#BookmarkEditor_ColorButton {
min-width: $InputHeight;
max-width: $InputHeight;
width: $InputHeight;
margin: 0;
padding: 0;
}
}
QWidget#BookmarkEditor_ButtonBox {
border: none;
}
}
Dialog {
border: 1px solid $BorderColor;
background-color: white;
}

View File

@ -0,0 +1,343 @@
/************************************************************************
* file name : window_header.cpp
* ----------------- :
* creation time : 2018/06/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of WindowHeader.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#include "globals.h"
#include "window_header.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QMouseEvent>
#include <QPushButton>
#include <QStyle>
static void setButtonSize(QPushButton* button, int size)
{
if (button != nullptr)
button->setFixedSize(size * 5 / 4, size);
}
WindowHeader::WindowHeader(const QString& title, Buttons buttons, QWidget* parent)
: Parent(parent)
, m_minimizeButton(nullptr)
, m_maximizeButton(nullptr)
, m_closeButton(nullptr)
, m_pixmap(new QLabel())
, m_title(new QLabel(title))
, m_isDragging(false)
{
m_title->installEventFilter(this);
m_pixmap->installEventFilter(this);
const auto icon = QApplication::windowIcon();
m_pixmap->setWindowIcon(icon);
m_pixmap->setPixmap(icon.isNull() ? QPixmap() : icon.pixmap(16, 16));
setMouseTracking(true);
if (buttons.testFlag(WindowHeader::MinimizeButton))
{
m_minimizeButton = new QPushButton();
m_minimizeButton->setObjectName("WindowHeader_MinButton");
connect(m_minimizeButton, &QPushButton::clicked, this, &This::onMinimizeClicked);
}
if (buttons.testFlag(WindowHeader::MaximizeButton))
{
m_maximizeButton = new QPushButton();
m_maximizeButton->setProperty("max", parent->isMaximized());
m_maximizeButton->setObjectName("WindowHeader_MaxButton");
connect(m_maximizeButton, &QPushButton::clicked, this, &This::onMaximizeClicked);
}
if (buttons.testFlag(WindowHeader::CloseButton))
{
m_closeButton = new QPushButton();
m_closeButton->setObjectName("WindowHeader_CloseButton");
connect(m_closeButton, &QPushButton::clicked, parent, &QWidget::close);
}
auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(1);
if (EASY_GLOBALS.is_right_window_header_controls)
{
setProperty("left", false);
layout->addWidget(m_pixmap, 0, Qt::AlignVCenter | Qt::AlignLeft);
layout->addSpacing(3);
layout->addWidget(m_title, 0, Qt::AlignVCenter | Qt::AlignLeft);
layout->addStretch(1);
if (m_minimizeButton != nullptr)
layout->addWidget(m_minimizeButton);
if (m_maximizeButton != nullptr)
layout->addWidget(m_maximizeButton);
if (m_closeButton != nullptr)
layout->addWidget(m_closeButton);
}
else
{
setProperty("left", true);
if (m_closeButton != nullptr)
layout->addWidget(m_closeButton);
if (m_maximizeButton != nullptr)
layout->addWidget(m_maximizeButton);
if (m_minimizeButton != nullptr)
layout->addWidget(m_minimizeButton);
layout->addSpacing(3);
layout->addWidget(m_pixmap, 0, Qt::AlignVCenter | Qt::AlignLeft);
layout->addSpacing(3);
layout->addWidget(m_title, 0, Qt::AlignVCenter | Qt::AlignLeft);
layout->addStretch(1);
}
if (m_maximizeButton != nullptr)
parent->installEventFilter(this);
m_pixmap->setVisible(!icon.isNull());
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::customWindowHeaderChanged,
this, &This::onWindowHeaderChanged);
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::windowHeaderPositionChanged,
this, &This::onWindowHeaderPositionChanged);
if (EASY_GLOBALS.use_custom_window_header)
parentWidget()->setWindowFlags(parentWidget()->windowFlags() | Qt::FramelessWindowHint);
else
parentWidget()->setWindowFlags(parentWidget()->windowFlags() & ~Qt::FramelessWindowHint);
setVisible(EASY_GLOBALS.use_custom_window_header);
}
WindowHeader::~WindowHeader()
{
}
void WindowHeader::setTitle(const QString& title)
{
m_title->setText(title);
}
void WindowHeader::setWindowIcon(const QIcon& icon)
{
const int size = std::max(m_title->fontMetrics().height(), 16);
m_pixmap->setWindowIcon(icon);
m_pixmap->setPixmap(icon.isNull() ? QPixmap() : icon.pixmap(size, size));
m_pixmap->setVisible(!icon.isNull());
}
void WindowHeader::onWindowStateChanged()
{
if (m_maximizeButton != nullptr)
{
m_maximizeButton->setProperty("max", parentWidget()->isMaximized());
m_maximizeButton->style()->unpolish(m_maximizeButton);
m_maximizeButton->style()->polish(m_maximizeButton);
m_maximizeButton->update();
setButtonSize(m_maximizeButton, height());
}
}
void WindowHeader::onWindowHeaderChanged()
{
}
void WindowHeader::onWindowHeaderPositionChanged()
{
}
void WindowHeader::mouseDoubleClickEvent(QMouseEvent* /*event*/)
{
if (m_maximizeButton != nullptr)
onMaximizeClicked(true);
}
void WindowHeader::mousePressEvent(QMouseEvent* event)
{
m_mousePressPos = mapFromGlobal(event->globalPos());
}
void WindowHeader::mouseReleaseEvent(QMouseEvent* /*event*/)
{
m_mousePressPos = QPoint();
m_isDragging = false;
}
void WindowHeader::mouseMoveEvent(QMouseEvent* event)
{
if (!event->buttons().testFlag(Qt::LeftButton))
return;
if (m_isDragging)
{
parentWidget()->move(event->globalPos() - m_mousePressPos);
return;
}
if (m_maximizeButton != nullptr && m_maximizeButton->underMouse())
return;
if (m_minimizeButton != nullptr && m_minimizeButton->underMouse())
return;
if (m_closeButton != nullptr && m_closeButton->underMouse())
return;
const auto pos = mapFromGlobal(event->globalPos());
const auto line = m_mousePressPos - pos;
if (line.manhattanLength() > 5)
{
m_isDragging = true;
auto parent = parentWidget();
if (parent->isMaximized())
{
const int w = parent->width();
parent->showNormal();
const auto k = static_cast<qreal>(pos.x()) / static_cast<qreal>(w);
const int xlocal = static_cast<int>(static_cast<qreal>(parent->width()) * k);
const int xglobal = event->globalPos().x() - xlocal;
parent->move(xglobal, parent->y());
m_mousePressPos = QPoint(xlocal, static_cast<int>(pos.y() * k));
}
else
{
m_mousePressPos = pos;
}
}
}
bool WindowHeader::eventFilter(QObject* obj, QEvent* event)
{
if (obj == m_title || obj == m_pixmap)
{
switch (event->type())
{
case QEvent::MouseMove:
{
mouseMoveEvent(static_cast<QMouseEvent*>(event));
return false;
}
case QEvent::MouseButtonPress:
{
mousePressEvent(static_cast<QMouseEvent*>(event));
return false;
}
case QEvent::MouseButtonRelease:
{
mouseReleaseEvent(static_cast<QMouseEvent*>(event));
return false;
}
case QEvent::MouseButtonDblClick:
{
mouseDoubleClickEvent(static_cast<QMouseEvent*>(event));
return false;
}
default:
break;
}
}
else if (obj == parentWidget())
{
if (event->type() == QEvent::WindowStateChange)
onWindowStateChanged();
return false;
}
return Parent::eventFilter(obj, event);
}
void WindowHeader::showEvent(QShowEvent* event)
{
Parent::showEvent(event);
if (!m_pixmap->windowIcon().isNull())
{
const int size = std::max(m_title->fontMetrics().height(), 16);
if (m_pixmap->pixmap()->height() != size)
m_pixmap->setPixmap(m_pixmap->windowIcon().pixmap(size, size));
}
setButtonSize(m_minimizeButton, height());
setButtonSize(m_maximizeButton, height());
setButtonSize(m_closeButton, height());
}
void WindowHeader::onMaximizeClicked(bool)
{
auto parent = parentWidget();
if (parent->isMaximized())
parent->showNormal();
else
parent->showMaximized();
}
void WindowHeader::onMinimizeClicked(bool)
{
parentWidget()->setWindowState(Qt::WindowMinimized);
}

View File

@ -0,0 +1,122 @@
/************************************************************************
* file name : window_header.h
* ----------------- :
* creation time : 2018/06/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of WindowHeader - a replacement
* : for standard system window header.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : 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
* :
* : 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.
************************************************************************/
#ifndef EASY_PROFILER_WINDOW_HEADER_H
#define EASY_PROFILER_WINDOW_HEADER_H
#include <QFrame>
class QPushButton;
class QLabel;
class WindowHeader : public QFrame
{
Q_OBJECT
using This = WindowHeader;
using Parent = QFrame;
QPoint m_mousePressPos;
QPushButton* m_minimizeButton;
QPushButton* m_maximizeButton;
QPushButton* m_closeButton;
QLabel* m_pixmap;
QLabel* m_title;
bool m_isDragging;
public:
enum Button
{
NoButtons = 0,
MinimizeButton = 0x01,
MaximizeButton = 0x02,
CloseButton = 0x04,
AllButtons = MinimizeButton | MaximizeButton | CloseButton
};
Q_DECLARE_FLAGS(Buttons, Button)
Q_FLAG(Buttons)
explicit WindowHeader(const QString& title, Buttons buttons, QWidget* parent);
~WindowHeader() override;
void setTitle(const QString& title);
void setWindowIcon(const QIcon& icon);
void setWindowTitle(const QString& title)
{
setTitle(title);
}
private slots:
void onWindowStateChanged();
void onWindowHeaderChanged();
void onWindowHeaderPositionChanged();
protected:
void mouseDoubleClickEvent(QMouseEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
bool eventFilter(QObject* obj, QEvent* event) override;
void showEvent(QShowEvent* event) override;
private slots:
void onMaximizeClicked(bool);
void onMinimizeClicked(bool);
}; // end of class WindowHeader.
#endif // EASY_PROFILER_WINDOW_HEADER_H

View File

@ -113,12 +113,16 @@ int main(int argc, char* argv[])
profiler::SerializedData serialized_blocks, serialized_descriptors; profiler::SerializedData serialized_blocks, serialized_descriptors;
profiler::descriptors_list_t descriptors; profiler::descriptors_list_t descriptors;
profiler::blocks_t blocks; profiler::blocks_t blocks;
profiler::bookmarks_t bookmarks;
profiler::BeginEndTime beginEndTime;
std::stringstream errorMessage; std::stringstream errorMessage;
uint32_t descriptorsNumberInFile = 0; uint32_t descriptorsNumberInFile = 0;
uint32_t version = 0; uint32_t version = 0;
profiler::processid_t pid = 0; profiler::processid_t pid = 0;
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks,
threaded_trees, descriptorsNumberInFile, version, pid, true, errorMessage); auto blocks_counter = fillTreesFromFile(filename.c_str(), beginEndTime, serialized_blocks, serialized_descriptors,
descriptors, blocks, threaded_trees, bookmarks, descriptorsNumberInFile,
version, pid, true, errorMessage);
if (blocks_counter == 0) if (blocks_counter == 0)
std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str(); std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str();