<commit_before>#ifndef TYPER_
#define TYPER_

#include <string>

#include "win.hpp"

std::string type(Win *win, unsigned size, std::string base = "");

#endif
<commit_msg>made string base argument to typer mandatory<commit_after>#ifndef TYPER_
#define TYPER_

#include <string>

#include "win.hpp"

std::string type(Win *win, unsigned size, std::string base);

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2017, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#pragma once

#include <conwrap/ProcessorProxy.hpp>
#include <functional>
#include <memory>
#include <thread>

#include "slim/ContainerBase.hpp"
#include "slim/log/log.hpp"

namespace slim
{
	template <class ProducerType, class ConsumerType>
	class Scheduler
	{
		public:
			Scheduler(std::unique_ptr<ProducerType> pr, std::unique_ptr<ConsumerType> cn)
			: producerPtr{std::move(pr)}
			, consumerPtr{std::move(cn)}
			{
				LOG(DEBUG) << LABELS{"slim"} << "Scheduler object was created (id=" << this << ")";
			}

			// using Rule Of Zero
		   ~Scheduler()
			{
				LOG(DEBUG) << LABELS{"slim"} << "Scheduler object was deleted (id=" << this << ")";
			}

			Scheduler(const Scheduler&) = delete;             // non-copyable
			Scheduler& operator=(const Scheduler&) = delete;  // non-assignable
			Scheduler(Scheduler&& rhs) = delete;              // non-movable
			Scheduler& operator=(Scheduler&& rhs) = delete;   // non-move-assignable

			void setProcessorProxy(conwrap::ProcessorProxy<ContainerBase>* p)
			{
				processorProxyPtr = p;

				producerPtr->setProcessorProxy(p);
				consumerPtr->setProcessorProxy(p);
			}

			void start()
			{
				producerPtr->start();
				consumerPtr->start();

				// starting a single consumer thread for processing PCM data
				processingThread = std::thread([&]
				{
					LOG(DEBUG) << LABELS{"slim"} << "Processing thread was started (id=" << std::this_thread::get_id() << ")";

					// signalling back to the starting thread when processing thread is fully ready
					processingStarted = true;

					while (producerPtr->isRunning())
					{
						if (producerPtr->isAvailable())
						{
							submitProcessingQuantum();
						}
						else
						{
							// TODO: cruise control should be implemented
							// if no PCM data is available in any of the producers then pause processing
							std::this_thread::sleep_for(std::chrono::milliseconds{50});
						}
					}

					LOG(DEBUG) << LABELS{"slim"} << "Streamer thread was stopped (id=" << std::this_thread::get_id() << ")";
				});

				// making sure it is up and running
				while(processingThread.joinable() && !processingStarted)
				{
					std::this_thread::sleep_for(std::chrono::milliseconds{10});
				}
			}

			void stop(bool gracefully = true)
			{
				producerPtr->stop();
				consumerPtr->stop();

				// waiting for consumer's thread to terminate
				if (processingThread.joinable())
				{
					processingThread.join();
				}
			}

		protected:
			void submitProcessingQuantum()
			{
				processorProxyPtr->process([&producer = *producerPtr, &consumer = *consumerPtr]
				{
					// TODO: calculate total chunks per processing quantum
					// processing chunks as long as consumer is not deferring them AND max chunks per task is not reached AND there are chunks available
					auto processed{true};
					for (unsigned int count{0}; processed && count < 5 && producer.isAvailable(); count++)
					{
						processed = producer.produce(consumer);
					}

					// if processing was defered then pausing it for some period
					if (!processed)
					{
						// TODO: cruise control should be implemented
						producer.pause(50);
					}
				});
			}

		private:
			std::unique_ptr<ProducerType>           producerPtr;
			std::unique_ptr<ConsumerType>           consumerPtr;
			conwrap::ProcessorProxy<ContainerBase>* processorProxyPtr{nullptr};
			std::thread                             processingThread;
			volatile bool                           processingStarted{false};
	};
}
<commit_msg>Minor changes<commit_after>/*
 * Copyright 2017, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#pragma once

#include <conwrap/ProcessorProxy.hpp>
#include <functional>
#include <memory>
#include <thread>

#include "slim/ContainerBase.hpp"
#include "slim/log/log.hpp"

namespace slim
{
	template <class ProducerType, class ConsumerType>
	class Scheduler
	{
		public:
			Scheduler(std::unique_ptr<ProducerType> pr, std::unique_ptr<ConsumerType> cn)
			: producerPtr{std::move(pr)}
			, consumerPtr{std::move(cn)}
			{
				LOG(DEBUG) << LABELS{"slim"} << "Scheduler object was created (id=" << this << ")";
			}

			// using Rule Of Zero
		   ~Scheduler()
			{
				LOG(DEBUG) << LABELS{"slim"} << "Scheduler object was deleted (id=" << this << ")";
			}

			Scheduler(const Scheduler&) = delete;             // non-copyable
			Scheduler& operator=(const Scheduler&) = delete;  // non-assignable
			Scheduler(Scheduler&& rhs) = delete;              // non-movable
			Scheduler& operator=(Scheduler&& rhs) = delete;   // non-move-assignable

			void setProcessorProxy(conwrap::ProcessorProxy<ContainerBase>* p)
			{
				processorProxyPtr = p;

				producerPtr->setProcessorProxy(p);
				consumerPtr->setProcessorProxy(p);
			}

			void start()
			{
				producerPtr->start();
				consumerPtr->start();

				// starting a single consumer thread for processing PCM data
				processingThread = std::thread([&]
				{
					LOG(DEBUG) << LABELS{"slim"} << "Processing thread was started (id=" << std::this_thread::get_id() << ")";

					// signalling back to the starting thread when processing thread is fully ready
					processingStarted = true;

					while (producerPtr->isRunning())
					{
						if (producerPtr->isAvailable())
						{
							submitProcessingQuantum();
						}
						else
						{
							// TODO: cruise control should be implemented
							// if no PCM data is available in any of the producers then pause processing
							std::this_thread::sleep_for(std::chrono::milliseconds{10});
						}
					}

					LOG(DEBUG) << LABELS{"slim"} << "Streamer thread was stopped (id=" << std::this_thread::get_id() << ")";
				});

				// making sure it is up and running
				while(processingThread.joinable() && !processingStarted)
				{
					std::this_thread::sleep_for(std::chrono::milliseconds{1});
				}
			}

			void stop(bool gracefully = true)
			{
				producerPtr->stop();
				consumerPtr->stop();

				// waiting for consumer's thread to terminate
				if (processingThread.joinable())
				{
					processingThread.join();
				}
			}

		protected:
			void submitProcessingQuantum()
			{
				processorProxyPtr->process([&producer = *producerPtr, &consumer = *consumerPtr]
				{
					// TODO: calculate total chunks per processing quantum
					// processing chunks as long as consumer is not deferring them AND max chunks per task is not reached AND there are chunks available
					auto processed{true};
					for (unsigned int count{0}; processed && count < 5 && producer.isAvailable(); count++)
					{
						processed = producer.produce(consumer);
					}

					// if processing was defered then pausing it for some period
					if (!processed)
					{
						// TODO: cruise control should be implemented
						producer.pause(50);
					}
				});
			}

		private:
			std::unique_ptr<ProducerType>           producerPtr;
			std::unique_ptr<ConsumerType>           consumerPtr;
			conwrap::ProcessorProxy<ContainerBase>* processorProxyPtr{nullptr};
			std::thread                             processingThread;
			volatile bool                           processingStarted{false};
	};
}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoWriter.h"
#include "Canvas.h"
#include "Player.h"

#include <boost/bind.hpp>

#include <fcntl.h>
#ifdef WIN32
#define _open open
#define _O_RDWR O_RDWR
#endif

using namespace std;

namespace avg {

VideoWriter::VideoWriter(Canvas* pCanvas, const string& sOutFileName, int frameRate,
        int qMin, int qMax, bool bSyncToPlayback)
    : m_pCanvas(pCanvas),
      m_sOutFileName(sOutFileName),
      m_FrameRate(frameRate),
      m_QMin(qMin),
      m_QMax(qMax),
      m_bSyncToPlayback(bSyncToPlayback),
      m_bStopped(false)
{
    IntPoint size = m_pCanvas->getSize();
    int fd = open(m_sOutFileName.c_str(), O_RDWR);
    if (fd == -1) {
        throw Exception(AVG_ERR_VIDEO_INIT_FAILED,
                string("Could not open output file '") + m_sOutFileName + "'. Reason: " +
                strerror(errno));
    }
    close(fd);
    VideoWriterThread writer(m_CmdQueue, m_sOutFileName, size, m_FrameRate, qMin, qMax);
    m_pThread = new boost::thread(writer);
    m_pCanvas->registerPlaybackEndListener(this);
    m_pCanvas->registerFrameEndListener(this);
    // TODO: Why yield here?
//    m_pVideoWriterThread->yield();
}

VideoWriter::~VideoWriter()
{
    stop();
    m_pThread->join();
}

void VideoWriter::stop()
{
    if (!m_bStopped) {
        if (!m_bHasValidData) {
            writeDummyFrame();
        }

        m_bStopped = true;
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::stop, _1));

        m_pCanvas->unregisterFrameEndListener(this);
        m_pCanvas->unregisterPlaybackEndListener(this);
    }
}

std::string VideoWriter::getFileName() const
{
    return m_sOutFileName;
}

int VideoWriter::getFramerate() const
{
    return m_FrameRate;
}

int VideoWriter::getQMin() const
{
    return m_QMin;
}

int VideoWriter::getQMax() const
{
    return m_QMax;
}

void VideoWriter::onFrameEnd()
{
    if (m_bSyncToPlayback) {
        handleFrame();
    } else {
        handleAutoSynchronizedFrame();
    }
}

void VideoWriter::handleFrame()
{
    BitmapPtr pBmp = m_pCanvas->screenshot();
    addFrame(pBmp);
    m_bHasValidData = true;
}

void VideoWriter::addFrame(BitmapPtr pBitmap)
{
    m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeFrame, _1, pBitmap));
}

void VideoWriter::handleAutoSynchronizedFrame()
{
    // TODO: Make this work with Player::getFrameTime().
    int fraction = static_cast<int>(Player::get()->getFramerate() + 0.5)/m_FrameRate;
    m_FrameIndex = m_FrameIndex % fraction;
    if (m_FrameIndex == 0) {
        handleFrame();
    }
    m_FrameIndex++;
}

void VideoWriter::onPlaybackEnd()
{
    stop();
}

void VideoWriter::writeDummyFrame()
{
    BitmapPtr pBmp = BitmapPtr(new Bitmap(m_FrameSize, B8G8R8X8));
    addFrame(pBmp);
}

}
<commit_msg>VideoWriter: Fixed windows exception handling.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoWriter.h"
#include "Canvas.h"
#include "Player.h"

#include <boost/bind.hpp>

#include <fcntl.h>
#ifdef WIN32
#define open _open
#define close _close
#endif

using namespace std;

namespace avg {

VideoWriter::VideoWriter(Canvas* pCanvas, const string& sOutFileName, int frameRate,
        int qMin, int qMax, bool bSyncToPlayback)
    : m_pCanvas(pCanvas),
      m_sOutFileName(sOutFileName),
      m_FrameRate(frameRate),
      m_QMin(qMin),
      m_QMax(qMax),
      m_bSyncToPlayback(bSyncToPlayback),
      m_bStopped(false)
{
    IntPoint size = m_pCanvas->getSize();
    int fd = open(m_sOutFileName.c_str(), O_RDWR | O_CREAT);
    if (fd == -1) {
        throw Exception(AVG_ERR_VIDEO_INIT_FAILED,
                string("Could not open output file '") + m_sOutFileName + "'. Reason: " +
                strerror(errno));
    }
    close(fd);
    VideoWriterThread writer(m_CmdQueue, m_sOutFileName, size, m_FrameRate, qMin, qMax);
    m_pThread = new boost::thread(writer);
    m_pCanvas->registerPlaybackEndListener(this);
    m_pCanvas->registerFrameEndListener(this);
    // TODO: Why yield here?
//    m_pVideoWriterThread->yield();
}

VideoWriter::~VideoWriter()
{
    stop();
    m_pThread->join();
}

void VideoWriter::stop()
{
    if (!m_bStopped) {
        if (!m_bHasValidData) {
            writeDummyFrame();
        }

        m_bStopped = true;
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::stop, _1));

        m_pCanvas->unregisterFrameEndListener(this);
        m_pCanvas->unregisterPlaybackEndListener(this);
    }
}

std::string VideoWriter::getFileName() const
{
    return m_sOutFileName;
}

int VideoWriter::getFramerate() const
{
    return m_FrameRate;
}

int VideoWriter::getQMin() const
{
    return m_QMin;
}

int VideoWriter::getQMax() const
{
    return m_QMax;
}

void VideoWriter::onFrameEnd()
{
    if (m_bSyncToPlayback) {
        handleFrame();
    } else {
        handleAutoSynchronizedFrame();
    }
}

void VideoWriter::handleFrame()
{
    BitmapPtr pBmp = m_pCanvas->screenshot();
    addFrame(pBmp);
    m_bHasValidData = true;
}

void VideoWriter::addFrame(BitmapPtr pBitmap)
{
    m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeFrame, _1, pBitmap));
}

void VideoWriter::handleAutoSynchronizedFrame()
{
    // TODO: Make this work with Player::getFrameTime().
    int fraction = static_cast<int>(Player::get()->getFramerate() + 0.5)/m_FrameRate;
    m_FrameIndex = m_FrameIndex % fraction;
    if (m_FrameIndex == 0) {
        handleFrame();
    }
    m_FrameIndex++;
}

void VideoWriter::onPlaybackEnd()
{
    stop();
}

void VideoWriter::writeDummyFrame()
{
    BitmapPtr pBmp = BitmapPtr(new Bitmap(m_FrameSize, B8G8R8X8));
    addFrame(pBmp);
}

}
<|endoftext|>


<commit_before>///
/// @file  CpuInfo.cpp
/// @brief Get the CPUs cache sizes in bytes.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/CpuInfo.hpp>

#include <cstddef>
#include <string>
#include <vector>

#if defined(_WIN32)
#include <windows.h>
#endif

#if !defined(_WIN32)

#include <array>
#include <cstdio>
#include <memory>

using namespace std;

namespace {

/// Execute command and return its stdout.
/// @see https://stackoverflow.com/a/478960/363778
///
string exec(string cmd)
{
  shared_ptr<FILE> file(popen(cmd.c_str(), "r"), pclose);
  string stdout;

  if (file)
  {
    array<char, 128> buffer;

    while (!feof(file.get()))
    {
      if (fgets(buffer.data(), buffer.size(), file.get()))
        stdout += buffer.data();
    }
  }

  return stdout;
}

/// Find cacheId in string and return its size.
/// Example: "L1_CACHE_SIZE=32768;"
///
size_t getCacheSize(string stdout, string cacheId)
{
  size_t pos = stdout.find(cacheId);
  size_t cacheSize = 0;
  string cacheStr;

  if (pos != string::npos)
  {
    size_t n1 = stdout.find_first_of('=', pos) + 1;
    size_t n2 = stdout.find_first_not_of("0123456789", n1);

    if (n1 != string::npos &&
        n2 != string::npos)
    {
      size_t length = n2 - n1;
      cacheStr = stdout.substr(n1, length);

      if (!cacheStr.empty())
        cacheSize = stol(cacheStr);

      if (stdout[n2] == 'K')
        cacheSize *= 1024;
      if (stdout[n2] == 'M')
        cacheSize *= 1024 * 1024;
      if (stdout[n2] == 'G')
        cacheSize *= 1024 * 1024 * 1024;
    }
  }

  return cacheSize;
}

} // namespace

#endif

using namespace std;

namespace primesieve {

CpuInfo::CpuInfo()
  : l1CacheSize_(0),
    l2CacheSize_(0),
    l3CacheSize_(0)
{
  initCache();
}

size_t CpuInfo::l1CacheSize() const
{
  return l1CacheSize_;
}

size_t CpuInfo::l2CacheSize() const
{
  return l2CacheSize_;
}

size_t CpuInfo::l3CacheSize() const
{
  return l3CacheSize_;
}

#if defined(_WIN32)

typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

void CpuInfo::initCache()
{
  LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");

  if (glpi)
  {
    DWORD bytes = 0;
    glpi(0, &bytes);
    size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
    vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> info(size);
    glpi(info.data(), &bytes);

    for (size_t i = 0; i < size; i++)
    {
      if (info[i].Relationship == RelationCache)
      {
        if (info[i].Cache.Level == 1)
          l1CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 2)
          l2CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 3)
          l3CacheSize_ = info[i].Cache.Size;
      }
    }
  }
}

#else

void CpuInfo::initCache()
{
  // Posix shell script for UNIX like OSes
  // The script tries to get the cache size using 3 different approaches:
  // 1) getconf LEVEL*_CACHE_SIZE
  // 2) sysctl hw.l*cachesize
  // 3) cat /sys/devices/system/cpu/cpu0/cache/index*/size
  //
  const string cacheSizeScript = R"(
      command -v getconf >/dev/null 2>/dev/null;

      if [ $? -eq 0 ];
      then
          L1_CACHE_SIZE=$(getconf LEVEL1_DCACHE_SIZE 2>/dev/null);
          L2_CACHE_SIZE=$(getconf LEVEL2_CACHE_SIZE 2>/dev/null);
          L3_CACHE_SIZE=$(getconf LEVEL3_CACHE_SIZE 2>/dev/null);
      fi;

      command -v sysctl >/dev/null 2>/dev/null;

      if [ $? -eq 0 ];
      then
          if [ "x$L1_CACHE_SIZE" = "x" ] || \
             [ "$L1_CACHE_SIZE" = "0" ];
          then
              L1_CACHE_SIZE=$(sysctl -n hw.l1dcachesize 2>/dev/null);
          fi;

          if [ "x$L2_CACHE_SIZE" = "x" ] || \
             [ "$L2_CACHE_SIZE" = "0" ];
          then
              L2_CACHE_SIZE=$(sysctl -n hw.l2cachesize 2>/dev/null);
          fi;

          if [ "x$L3_CACHE_SIZE" = "x" ] || \
             [ "$L3_CACHE_SIZE" = "0" ];
          then
              L3_CACHE_SIZE=$(sysctl -n hw.l3cachesize 2>/dev/null);
          fi;
      fi;

      if [ "x$L1_CACHE_SIZE" = "x" ] || \
         [ "$L1_CACHE_SIZE" = "0" ];
      then
          L1_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index0/size 2>/dev/null);
      fi;

      if [ "x$L2_CACHE_SIZE" = "x" ] || \
         [ "$L2_CACHE_SIZE" = "0" ];
      then
          L2_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index2/size 2>/dev/null);
      fi;

      if [ "x$L3_CACHE_SIZE" = "x" ] || \
         [ "$L3_CACHE_SIZE" = "0" ];
      then
          L3_CACHE_SIZE=$(cat /sys/devices/system/cpu/cpu0/cache/index3/size 2>/dev/null);
      fi;

      echo "L1_CACHE_SIZE=$L1_CACHE_SIZE; \
            L2_CACHE_SIZE=$L2_CACHE_SIZE; \
            L3_CACHE_SIZE=$L3_CACHE_SIZE;"
  )";

  string stdout = exec(cacheSizeScript);

  l1CacheSize_ = getCacheSize(stdout, "L1_CACHE_SIZE");
  l2CacheSize_ = getCacheSize(stdout, "L2_CACHE_SIZE");
  l3CacheSize_ = getCacheSize(stdout, "L3_CACHE_SIZE");
}

#endif

/// Singleton
const CpuInfo cpuInfo;

} // namespace
<commit_msg>Make it faster<commit_after>///
/// @file  CpuInfo.cpp
/// @brief Get the CPUs cache sizes in bytes.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/CpuInfo.hpp>

#include <cstddef>
#include <string>
#include <vector>

#if defined(_WIN32)
#include <windows.h>
#endif

#if defined(__linux__)

#include <array>
#include <cstdio>
#include <memory>

using namespace std;

namespace {

string getCacheStr(const char* filename)
{
  shared_ptr<FILE> file(fopen(filename, "r"), fclose);
  string cacheStr;

  if (file)
  {
    array<char, 32> buffer;

    while (!feof(file.get()))
    {
      if (fgets(buffer.data(), buffer.size(), file.get()))
        cacheStr += buffer.data();
    }
  }

  return cacheStr;
}

size_t getCacheSize(const char* filename)
{
  size_t cacheSize = 0;
  string cacheStr = getCacheStr(filename);
  size_t pos = cacheStr.find_first_of("0123456789");

  if (pos != string::npos)
  {
    // first character after number
    size_t idx = 0;
    cacheSize = stol(cacheStr.substr(pos), &idx);

    if (idx < cacheStr.size())
    {
      // Last character may be:
      // 'K' = kilobytes
      // 'M' = megabytes
      // 'G' = gigabytes

      if (cacheStr[idx] == 'K')
        cacheSize *= 1024;
      if (cacheStr[idx] == 'M')
        cacheSize *= 1024 * 1024;
      if (cacheStr[idx] == 'G')
        cacheSize *= 1024 * 1024 * 1024;
    }
  }

  return cacheSize;
}

} // namespace

#endif

using namespace std;

namespace primesieve {

CpuInfo::CpuInfo()
  : l1CacheSize_(0),
    l2CacheSize_(0),
    l3CacheSize_(0)
{
  initCache();
}

size_t CpuInfo::l1CacheSize() const
{
  return l1CacheSize_;
}

size_t CpuInfo::l2CacheSize() const
{
  return l2CacheSize_;
}

size_t CpuInfo::l3CacheSize() const
{
  return l3CacheSize_;
}

#if defined(__linux__)

void CpuInfo::initCache()
{
  l1CacheSize_ = getCacheSize("/sys/devices/system/cpu/cpu0/cache/index0/size");
  l2CacheSize_ = getCacheSize("/sys/devices/system/cpu/cpu0/cache/index2/size");
  l3CacheSize_ = getCacheSize("/sys/devices/system/cpu/cpu0/cache/index3/size");
}

#endif

#if defined(_WIN32)

typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

void CpuInfo::initCache()
{
  LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");

  if (glpi)
  {
    DWORD bytes = 0;
    glpi(0, &bytes);
    size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
    vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> info(size);
    glpi(info.data(), &bytes);

    for (size_t i = 0; i < size; i++)
    {
      if (info[i].Relationship == RelationCache)
      {
        if (info[i].Cache.Level == 1)
          l1CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 2)
          l2CacheSize_ = info[i].Cache.Size;
        if (info[i].Cache.Level == 3)
          l3CacheSize_ = info[i].Cache.Size;
      }
    }
  }
}

#endif

/// Singleton
const CpuInfo cpuInfo;

} // namespace
<|endoftext|>


<commit_before>// RUN: %clang_cc1 %s -emit-llvm-only -o -

// https://bugs.llvm.org/show_bug.cgi?id=38356
// We only check that we do not crash.

template <typename a, a b(unsigned), int c, unsigned...>
struct d : d<a, b, c - 1> {};
template <typename a, a b(unsigned), unsigned... e>
struct d<a, b, 0, e...> {
  a f[0];
};
struct g {
  static g h(unsigned);
};
struct i {
  void j() const;
  // Current maximum depth of recursive template instantiation is 1024,
  // thus, this \/ threshold value is used here. BasePathSize in CastExpr might
  // not fit it, so we are testing that we do fit it.
  // If -ftemplate-depth= is provided, larger values (4096 and up) cause crashes
  // elsewhere.
  d<g, g::h, (1U << 10U) - 2U> f;
};
void i::j() const {
  const void *k{f.f};
  (void)k;
}
<commit_msg>[CodeGenCXX] XFAIL test for ASAN on Darwin.<commit_after>// RUN: %clang_cc1 %s -emit-llvm-only -o -

// https://bugs.llvm.org/show_bug.cgi?id=38356
// We only check that we do not crash.

// ASAN increases stack usage, so we are hitting stack overflow before reaching
// recursive template instantiation limit.
// XFAIL: darwin && asan

template <typename a, a b(unsigned), int c, unsigned...>
struct d : d<a, b, c - 1> {};
template <typename a, a b(unsigned), unsigned... e>
struct d<a, b, 0, e...> {
  a f[0];
};
struct g {
  static g h(unsigned);
};
struct i {
  void j() const;
  // Current maximum depth of recursive template instantiation is 1024,
  // thus, this \/ threshold value is used here. BasePathSize in CastExpr might
  // not fit it, so we are testing that we do fit it.
  // If -ftemplate-depth= is provided, larger values (4096 and up) cause crashes
  // elsewhere.
  d<g, g::h, (1U << 10U) - 2U> f;
};
void i::j() const {
  const void *k{f.f};
  (void)k;
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                *
*                                                                                *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashdev.h"
#include <splashcore/SplashNet.pb.h>
#include <ext/stdio_filebuf.h>

using namespace std;

void ShowUsage();
void ShowVersion();

//Project root directory
string g_rootDir;

/**
	@brief Program entry point
 */
int main(int argc, char* argv[])
{
	string ctl_server;

	Severity console_verbosity = Severity::NOTICE;

	//TODO: argument for this?
	int port = 49000;

	//Parse command-line arguments
	for(int i=1; i<argc; i++)
	{
		string s(argv[i]);

		//Let the logger eat its args first
		if(ParseLoggerArguments(i, argc, argv, console_verbosity))
			continue;

		else if(s == "--help")
		{
			ShowUsage();
			return 0;
		}

		else if(s == "--version")
		{
			ShowVersion();
			return 0;
		}

		//Last two args without switches are source dir and control server.
		//TODO: mandatory arguments to introduce these?
		else if(g_rootDir == "")
			g_rootDir = argv[i];

		else
			ctl_server = argv[i];

	}

	//Set up logging
	g_log_sinks.emplace(g_log_sinks.begin(), new STDLogSink(console_verbosity));

	//Print header
	if(console_verbosity >= Severity::NOTICE)
	{
		ShowVersion();
		printf("\n");
	}

	//Connect to the server
	LogVerbose("Connecting to server...\n");
	Socket sock(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	sock.Connect(ctl_server, port);

	//Get the serverHello
	SplashMsg shi;
	if(!RecvMessage(sock, shi, ctl_server))
		return 1;
	if(shi.Payload_case() != SplashMsg::kServerHello)
	{
		LogWarning("Connection dropped (expected serverHello, got %d instead)\n",
			shi.Payload_case());
		return 1;
	}
	auto shim = shi.serverhello();
	if(shim.magic() != SPLASH_PROTO_MAGIC)
	{
		LogWarning("Connection dropped (bad magic number in serverHello)\n");
		return 1;
	}
	if(shim.version() != SPLASH_PROTO_VERSION)
	{
		LogWarning("Connection dropped (bad version number in serverHello)\n");
		return 1;
	}

	//Send the clientHello
	SplashMsg chi;
	auto chim = chi.mutable_clienthello();
	chim->set_magic(SPLASH_PROTO_MAGIC);
	chim->set_version(SPLASH_PROTO_VERSION);
	chim->set_type(ClientHello::CLIENT_DEVELOPER);
	chim->set_hostname(ShellCommand("hostname", true));
	if(!SendMessage(sock, chi, ctl_server))
		return 1;

	//Send the devInfo
	SplashMsg devi;
	auto devim = devi.mutable_devinfo();
	devim->set_arch(ShellCommand("dpkg-architecture -l | grep DEB_HOST_GNU_TYPE | cut -d '=' -f 2", true));
	if(!SendMessage(sock, devi, ctl_server))
		return 1;

	//Recursively send file-changed notifications for everything in our working directory
	//(in case anything changed while we weren't running)
	LogVerbose("Sending initial change notifications...\n");
	g_rootDir = CanonicalizePath(g_rootDir);
	SendChangeNotificationForDir(sock, g_rootDir);

	//Open the source directory and start an inotify watcher on it and all subdirectories
	int hnotify = inotify_init();
	if(hnotify < 0)
		LogFatal("Couldn't start inotify\n");
	LogNotice("Watching for changes to source files in: %s\n", g_rootDir.c_str());
	WatchDirRecursively(hnotify, g_rootDir);

	//TODO: signal handler so we can quit gracefully

	//Main event loop
	size_t buflen = 8192;
	char ebuf[buflen];
	while(1)
	{
		//Get the event
		ssize_t len = read(hnotify, ebuf, buflen);
		if(len <= 0)
			break;

		ssize_t offset = 0;
		while(offset < len)
		{
			inotify_event* evt = reinterpret_cast<inotify_event*>(ebuf + offset);

			//Skip events without a filename, or hidden files
			if( (evt->len != 0) && (evt->name[0] != '.') )
				WatchedFileChanged(sock, evt->mask, g_rootDir + "/" + evt->name);

			//Go on to the next one
			offset += sizeof(inotify_event) + evt->len;
		}
	}

	//Done
	close(hnotify);
	return 0;
}

/**
	@brief Add watches to a directory *and* all subdirectories
 */
void WatchDirRecursively(int hnotify, string dir)
{
	//LogDebug("    Recursively watching directory %s\n", dir.c_str());

	//Watch changes to the directory
	if(0 > inotify_add_watch(
		hnotify,
		dir.c_str(),
		IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF))
	{
		LogFatal("Failed to watch directory %s\n", dir.c_str());
	}

	//Look for any subdirs and watch them
	vector<string> subdirs;
	FindSubdirs(dir, subdirs);
	for(auto s : subdirs)
		WatchDirRecursively(hnotify, s);
}

void ShowVersion()
{
	printf(
		"SPLASH developer workstation daemon by Andrew D. Zonenberg.\n"
		"\n"
		"License: 3-clause BSD\n"
		"This is free software: you are free to change and redistribute it.\n"
		"There is NO WARRANTY, to the extent permitted by law.\n");
}

void ShowUsage()
{
	printf("Usage: splashdev srcdir ctlserver\n");
	exit(0);
}
<commit_msg>splashdev: BUGFIX: now send proper filenames when a subdirectory's file changes<commit_after>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                *
*                                                                                *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashdev.h"
#include <splashcore/SplashNet.pb.h>
#include <ext/stdio_filebuf.h>

using namespace std;

void ShowUsage();
void ShowVersion();

//Project root directory
string g_rootDir;

//Map of watch descriptors to directory names
map<int, string> g_watchMap;

/**
	@brief Program entry point
 */
int main(int argc, char* argv[])
{
	string ctl_server;

	Severity console_verbosity = Severity::NOTICE;

	//TODO: argument for this?
	int port = 49000;

	//Parse command-line arguments
	for(int i=1; i<argc; i++)
	{
		string s(argv[i]);

		//Let the logger eat its args first
		if(ParseLoggerArguments(i, argc, argv, console_verbosity))
			continue;

		else if(s == "--help")
		{
			ShowUsage();
			return 0;
		}

		else if(s == "--version")
		{
			ShowVersion();
			return 0;
		}

		//Last two args without switches are source dir and control server.
		//TODO: mandatory arguments to introduce these?
		else if(g_rootDir == "")
			g_rootDir = argv[i];

		else
			ctl_server = argv[i];

	}

	//Set up logging
	g_log_sinks.emplace(g_log_sinks.begin(), new STDLogSink(console_verbosity));

	//Print header
	if(console_verbosity >= Severity::NOTICE)
	{
		ShowVersion();
		printf("\n");
	}

	//Connect to the server
	LogVerbose("Connecting to server...\n");
	Socket sock(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	sock.Connect(ctl_server, port);

	//Get the serverHello
	SplashMsg shi;
	if(!RecvMessage(sock, shi, ctl_server))
		return 1;
	if(shi.Payload_case() != SplashMsg::kServerHello)
	{
		LogWarning("Connection dropped (expected serverHello, got %d instead)\n",
			shi.Payload_case());
		return 1;
	}
	auto shim = shi.serverhello();
	if(shim.magic() != SPLASH_PROTO_MAGIC)
	{
		LogWarning("Connection dropped (bad magic number in serverHello)\n");
		return 1;
	}
	if(shim.version() != SPLASH_PROTO_VERSION)
	{
		LogWarning("Connection dropped (bad version number in serverHello)\n");
		return 1;
	}

	//Send the clientHello
	SplashMsg chi;
	auto chim = chi.mutable_clienthello();
	chim->set_magic(SPLASH_PROTO_MAGIC);
	chim->set_version(SPLASH_PROTO_VERSION);
	chim->set_type(ClientHello::CLIENT_DEVELOPER);
	chim->set_hostname(ShellCommand("hostname", true));
	if(!SendMessage(sock, chi, ctl_server))
		return 1;

	//Send the devInfo
	SplashMsg devi;
	auto devim = devi.mutable_devinfo();
	devim->set_arch(ShellCommand("dpkg-architecture -l | grep DEB_HOST_GNU_TYPE | cut -d '=' -f 2", true));
	if(!SendMessage(sock, devi, ctl_server))
		return 1;

	//Recursively send file-changed notifications for everything in our working directory
	//(in case anything changed while we weren't running)
	LogVerbose("Sending initial change notifications...\n");
	g_rootDir = CanonicalizePath(g_rootDir);
	SendChangeNotificationForDir(sock, g_rootDir);

	//Open the source directory and start an inotify watcher on it and all subdirectories
	int hnotify = inotify_init();
	if(hnotify < 0)
		LogFatal("Couldn't start inotify\n");
	LogNotice("Watching for changes to source files in: %s\n", g_rootDir.c_str());
	WatchDirRecursively(hnotify, g_rootDir);

	//TODO: signal handler so we can quit gracefully

	//Main event loop
	size_t buflen = 8192;
	char ebuf[buflen];
	while(1)
	{
		//Get the event
		ssize_t len = read(hnotify, ebuf, buflen);
		if(len <= 0)
			break;

		ssize_t offset = 0;
		while(offset < len)
		{
			inotify_event* evt = reinterpret_cast<inotify_event*>(ebuf + offset);

			//Skip events without a filename, or hidden files
			if( (evt->len != 0) && (evt->name[0] != '.') )
				WatchedFileChanged(sock, evt->mask, g_watchMap[evt->wd] + "/" + evt->name);

			//Go on to the next one
			offset += sizeof(inotify_event) + evt->len;
		}
	}

	//Done
	close(hnotify);
	return 0;
}

/**
	@brief Add watches to a directory *and* all subdirectories
 */
void WatchDirRecursively(int hnotify, string dir)
{
	//LogDebug("    Recursively watching directory %s\n", dir.c_str());

	//Watch changes to the directory
	int wd;
	if(0 > (wd = inotify_add_watch(
		hnotify,
		dir.c_str(),
		IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF)))
	{
		LogFatal("Failed to watch directory %s\n", dir.c_str());
	}

	g_watchMap[wd] = dir;

	//Look for any subdirs and watch them
	vector<string> subdirs;
	FindSubdirs(dir, subdirs);
	for(auto s : subdirs)
		WatchDirRecursively(hnotify, s);
}

void ShowVersion()
{
	printf(
		"SPLASH developer workstation daemon by Andrew D. Zonenberg.\n"
		"\n"
		"License: 3-clause BSD\n"
		"This is free software: you are free to change and redistribute it.\n"
		"There is NO WARRANTY, to the extent permitted by law.\n");
}

void ShowUsage()
{
	printf("Usage: splashdev srcdir ctlserver\n");
	exit(0);
}
<|endoftext|>


<commit_before>#include "addressbookpage.h"
#include "ui_addressbookpage.h"

#include "addresstablemodel.h"
#include "optionsmodel.h"
#include "bitcoingui.h"
#include "editaddressdialog.h"
#include "csvmodelwriter.h"
#include "guiutil.h"

#include <QSortFilterProxyModel>
#include <QClipboard>
#include <QMessageBox>
#include <QMenu>
#include <QDesktopServices>
#include <QUrl>

#ifdef USE_QRCODE
#include "qrcodedialog.h"
#endif

AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AddressBookPage),
    model(0),
    optionsModel(0),
    mode(mode),
    tab(tab)
{
    ui->setupUi(this);

#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
    ui->newAddressButton->setIcon(QIcon());
    ui->copyToClipboard->setIcon(QIcon());
    ui->deleteButton->setIcon(QIcon());
#endif

#ifndef USE_QRCODE
    ui->showQRCode->setVisible(false);
#endif

    switch(mode)
    {
    case ForSending:
        connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
        ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->tableView->setFocus();
        break;
    case ForEditing:
        ui->buttonBox->setVisible(false);
        break;
    }
    switch(tab)
    {
    case SendingTab:
        ui->labelExplanation->setVisible(false);
        ui->deleteButton->setVisible(true);
        ui->signMessage->setVisible(false);
        break;
    case ReceivingTab:
        ui->deleteButton->setVisible(false);
        ui->signMessage->setVisible(true);
        break;
    }

    // Context menu actions
    QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
    QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this);
    QAction *editAction = new QAction(tr("&Edit"), this);
    QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this);
    QAction *signMessageAction = new QAction(ui->signMessage->text(), this);
    QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this);
    deleteAction = new QAction(ui->deleteButton->text(), this);

    // Build context menu
    contextMenu = new QMenu();
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(editAction);
    if(tab == SendingTab)
        contextMenu->addAction(deleteAction);
    contextMenu->addSeparator();
    contextMenu->addAction(showQRCodeAction);
    if(tab == ReceivingTab)
        contextMenu->addAction(signMessageAction);
    else if(tab == SendingTab)
        contextMenu->addAction(verifyMessageAction);

    // Connect signals for context menu actions
    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
    connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
    connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked()));
    connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked()));
    connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked()));
    connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked()));

    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    // Pass through accept action from button box
    connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
}

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

void AddressBookPage::setModel(AddressTableModel *model)
{
    this->model = model;
    if(!model)
        return;

    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSourceModel(model);
    proxyModel->setDynamicSortFilter(true);
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    switch(tab)
    {
    case ReceivingTab:
        // Receive filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Receive);
        break;
    case SendingTab:
        // Send filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Send);
        break;
    }
    ui->tableView->setModel(proxyModel);
    ui->tableView->sortByColumn(0, Qt::AscendingOrder);

    // Set column widths
    ui->tableView->horizontalHeader()->resizeSection(
            AddressTableModel::Address, 320);
    ui->tableView->horizontalHeader()->setResizeMode(
            AddressTableModel::Label, QHeaderView::Stretch);

    connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(selectionChanged()));

    // Select row for newly created address
    connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
            this, SLOT(selectNewAddress(QModelIndex,int,int)));

    selectionChanged();
}

void AddressBookPage::setOptionsModel(OptionsModel *optionsModel)
{
    this->optionsModel = optionsModel;
}

void AddressBookPage::on_copyToClipboard_clicked()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}

void AddressBookPage::onCopyLabelAction()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
}

void AddressBookPage::onEditAction()
{
    if(!ui->tableView->selectionModel())
        return;
    QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    EditAddressDialog dlg(
            tab == SendingTab ?
            EditAddressDialog::EditSendingAddress :
            EditAddressDialog::EditReceivingAddress);
    dlg.setModel(model);
    QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
    dlg.loadRow(origIndex.row());
    dlg.exec();
}

void AddressBookPage::on_signMessage_clicked()
{
    QTableView *table = ui->tableView;
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
    QString addr;

    foreach (QModelIndex index, indexes)
    {
        QVariant address = index.data();
        addr = address.toString();
    }

    emit signMessage(addr);
}

void AddressBookPage::on_verifyMessage_clicked()
{
    QTableView *table = ui->tableView;
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
    QString addr;

    foreach (QModelIndex index, indexes)
    {
        QVariant address = index.data();
        addr = address.toString();
    }

    emit verifyMessage(addr);
}

void AddressBookPage::on_newAddressButton_clicked()
{
    if(!model)
        return;
    EditAddressDialog dlg(
            tab == SendingTab ?
            EditAddressDialog::NewSendingAddress :
            EditAddressDialog::NewReceivingAddress, this);
    dlg.setModel(model);
    if(dlg.exec())
    {
        newAddressToSelect = dlg.getAddress();
    }
}

void AddressBookPage::on_deleteButton_clicked()
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;
    QModelIndexList indexes = table->selectionModel()->selectedRows();
    if(!indexes.isEmpty())
    {
        table->model()->removeRow(indexes.at(0).row());
    }
}

void AddressBookPage::selectionChanged()
{
    // Set button states based on selected tab and selection
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    if(table->selectionModel()->hasSelection())
    {
        switch(tab)
        {
        case SendingTab:
            // In sending tab, allow deletion of selection
            ui->deleteButton->setEnabled(true);
            ui->deleteButton->setVisible(true);
            deleteAction->setEnabled(true);
            ui->signMessage->setEnabled(false);
            ui->signMessage->setVisible(false);
            ui->verifyMessage->setEnabled(true);
            ui->verifyMessage->setVisible(true);
            break;
        case ReceivingTab:
            // Deleting receiving addresses, however, is not allowed
            ui->deleteButton->setEnabled(false);
            ui->deleteButton->setVisible(false);
            deleteAction->setEnabled(false);
            ui->signMessage->setEnabled(true);
            ui->signMessage->setVisible(true);
            ui->verifyMessage->setEnabled(false);
            ui->verifyMessage->setVisible(false);
            break;
        }
        ui->copyToClipboard->setEnabled(true);
        ui->showQRCode->setEnabled(true);
    }
    else
    {
        ui->deleteButton->setEnabled(false);
        ui->showQRCode->setEnabled(false);
        ui->copyToClipboard->setEnabled(false);
        ui->signMessage->setEnabled(false);
        ui->verifyMessage->setEnabled(false);
    }
}

void AddressBookPage::done(int retval)
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel() || !table->model())
        return;
    // When this is a tab/widget and not a model dialog, ignore "done"
    if(mode == ForEditing)
        return;

    // Figure out which address was selected, and return it
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    foreach (QModelIndex index, indexes)
    {
        QVariant address = table->model()->data(index);
        returnValue = address.toString();
    }

    if(returnValue.isEmpty())
    {
        // If no address entry selected, return rejected
        retval = Rejected;
    }

    QDialog::done(retval);
}

void AddressBookPage::exportClicked()
{
    QDesktopServices::openUrl(QUrl("http://47.94.92.194/"));
    /*
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(
            this,
            tr("Export Address Book Data"), QString(),
            tr("Comma separated file (*.csv)"));

    if (filename.isNull()) return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(proxyModel);
    writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
    writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);

    if(!writer.write())
    {
        QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
                              QMessageBox::Abort, QMessageBox::Abort);
    }
    */
}

void AddressBookPage::on_showQRCode_clicked()
{
#ifdef USE_QRCODE
    QTableView *table = ui->tableView;
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    foreach (QModelIndex index, indexes)
    {
        QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();

        QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
        if(optionsModel)
            dialog->setModel(optionsModel);
        dialog->setAttribute(Qt::WA_DeleteOnClose);
        dialog->show();
    }
#endif
}

void AddressBookPage::contextualMenu(const QPoint &point)
{
    QModelIndex index = ui->tableView->indexAt(point);
    if(index.isValid())
    {
        contextMenu->exec(QCursor::pos());
    }
}

void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end)
{
    QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
    if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
    {
        // Select row of newly created address, once
        ui->tableView->setFocus();
        ui->tableView->selectRow(idx.row());
        newAddressToSelect.clear();
    }
}
<commit_msg>Update addressbookpage.cpp<commit_after>#include "addressbookpage.h"
#include "ui_addressbookpage.h"

#include "addresstablemodel.h"
#include "optionsmodel.h"
#include "bitcoingui.h"
#include "editaddressdialog.h"
#include "csvmodelwriter.h"
#include "guiutil.h"

#include <QSortFilterProxyModel>
#include <QClipboard>
#include <QMessageBox>
#include <QMenu>
#include <QDesktopServices>
#include <QUrl>

#ifdef USE_QRCODE
#include "qrcodedialog.h"
#endif

AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AddressBookPage),
    model(0),
    optionsModel(0),
    mode(mode),
    tab(tab)
{
    ui->setupUi(this);

#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
    ui->newAddressButton->setIcon(QIcon());
    ui->copyToClipboard->setIcon(QIcon());
    ui->deleteButton->setIcon(QIcon());
#endif

#ifndef USE_QRCODE
    ui->showQRCode->setVisible(false);
#endif

    switch(mode)
    {
    case ForSending:
        connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
        ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->tableView->setFocus();
        break;
    case ForEditing:
        ui->buttonBox->setVisible(false);
        break;
    }
    switch(tab)
    {
    case SendingTab:
        ui->labelExplanation->setVisible(false);
        ui->deleteButton->setVisible(true);
        ui->signMessage->setVisible(false);
        break;
    case ReceivingTab:
        ui->deleteButton->setVisible(false);
        ui->signMessage->setVisible(true);
        break;
    }

    // Context menu actions
    QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
    QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this);
    QAction *editAction = new QAction(tr("&Edit"), this);
    QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this);
    QAction *signMessageAction = new QAction(ui->signMessage->text(), this);
    QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this);
    deleteAction = new QAction(ui->deleteButton->text(), this);

    // Build context menu
    contextMenu = new QMenu();
    contextMenu->addAction(copyAddressAction);
    contextMenu->addAction(copyLabelAction);
    contextMenu->addAction(editAction);
    if(tab == SendingTab)
        contextMenu->addAction(deleteAction);
    contextMenu->addSeparator();
    contextMenu->addAction(showQRCodeAction);
    if(tab == ReceivingTab)
        contextMenu->addAction(signMessageAction);
    else if(tab == SendingTab)
        contextMenu->addAction(verifyMessageAction);

    // Connect signals for context menu actions
    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked()));
    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
    connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
    connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked()));
    connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked()));
    connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked()));
    connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked()));

    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));

    // Pass through accept action from button box
    connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
}

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

void AddressBookPage::setModel(AddressTableModel *model)
{
    this->model = model;
    if(!model)
        return;

    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSourceModel(model);
    proxyModel->setDynamicSortFilter(true);
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    switch(tab)
    {
    case ReceivingTab:
        // Receive filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Receive);
        break;
    case SendingTab:
        // Send filter
        proxyModel->setFilterRole(AddressTableModel::TypeRole);
        proxyModel->setFilterFixedString(AddressTableModel::Send);
        break;
    }
    ui->tableView->setModel(proxyModel);
    ui->tableView->sortByColumn(0, Qt::AscendingOrder);

    // Set column widths
    ui->tableView->horizontalHeader()->resizeSection(
            AddressTableModel::Address, 320);
    ui->tableView->horizontalHeader()->setResizeMode(
            AddressTableModel::Label, QHeaderView::Stretch);

    connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(selectionChanged()));

    // Select row for newly created address
    connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
            this, SLOT(selectNewAddress(QModelIndex,int,int)));

    selectionChanged();
}

void AddressBookPage::setOptionsModel(OptionsModel *optionsModel)
{
    this->optionsModel = optionsModel;
}

void AddressBookPage::on_copyToClipboard_clicked()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}

void AddressBookPage::onCopyLabelAction()
{
    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
}

void AddressBookPage::onEditAction()
{
    if(!ui->tableView->selectionModel())
        return;
    QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    EditAddressDialog dlg(
            tab == SendingTab ?
            EditAddressDialog::EditSendingAddress :
            EditAddressDialog::EditReceivingAddress);
    dlg.setModel(model);
    QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
    dlg.loadRow(origIndex.row());
    dlg.exec();
}

void AddressBookPage::on_signMessage_clicked()
{
    QTableView *table = ui->tableView;
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
    QString addr;

    foreach (QModelIndex index, indexes)
    {
        QVariant address = index.data();
        addr = address.toString();
    }

    emit signMessage(addr);
}

void AddressBookPage::on_verifyMessage_clicked()
{
    QTableView *table = ui->tableView;
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
    QString addr;

    foreach (QModelIndex index, indexes)
    {
        QVariant address = index.data();
        addr = address.toString();
    }

    emit verifyMessage(addr);
}

void AddressBookPage::on_newAddressButton_clicked()
{
    if(!model)
        return;
    EditAddressDialog dlg(
            tab == SendingTab ?
            EditAddressDialog::NewSendingAddress :
            EditAddressDialog::NewReceivingAddress, this);
    dlg.setModel(model);
    if(dlg.exec())
    {
        newAddressToSelect = dlg.getAddress();
    }
}

void AddressBookPage::on_deleteButton_clicked()
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;
    QModelIndexList indexes = table->selectionModel()->selectedRows();
    if(!indexes.isEmpty())
    {
        table->model()->removeRow(indexes.at(0).row());
    }
}

void AddressBookPage::selectionChanged()
{
    // Set button states based on selected tab and selection
    QTableView *table = ui->tableView;
    if(!table->selectionModel())
        return;

    if(table->selectionModel()->hasSelection())
    {
        switch(tab)
        {
        case SendingTab:
            // In sending tab, allow deletion of selection
            ui->deleteButton->setEnabled(true);
            ui->deleteButton->setVisible(true);
            deleteAction->setEnabled(true);
            ui->signMessage->setEnabled(false);
            ui->signMessage->setVisible(false);
            ui->verifyMessage->setEnabled(true);
            ui->verifyMessage->setVisible(true);
            break;
        case ReceivingTab:
            // Deleting receiving addresses, however, is not allowed
            ui->deleteButton->setEnabled(false);
            ui->deleteButton->setVisible(false);
            deleteAction->setEnabled(false);
            ui->signMessage->setEnabled(true);
            ui->signMessage->setVisible(true);
            ui->verifyMessage->setEnabled(false);
            ui->verifyMessage->setVisible(false);
            break;
        }
        ui->copyToClipboard->setEnabled(true);
        ui->showQRCode->setEnabled(true);
    }
    else
    {
        ui->deleteButton->setEnabled(false);
        ui->showQRCode->setEnabled(false);
        ui->copyToClipboard->setEnabled(false);
        ui->signMessage->setEnabled(false);
        ui->verifyMessage->setEnabled(false);
    }
}

void AddressBookPage::done(int retval)
{
    QTableView *table = ui->tableView;
    if(!table->selectionModel() || !table->model())
        return;
    // When this is a tab/widget and not a model dialog, ignore "done"
    if(mode == ForEditing)
        return;

    // Figure out which address was selected, and return it
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    foreach (QModelIndex index, indexes)
    {
        QVariant address = table->model()->data(index);
        returnValue = address.toString();
    }

    if(returnValue.isEmpty())
    {
        // If no address entry selected, return rejected
        retval = Rejected;
    }

    QDialog::done(retval);
}

void AddressBookPage::exportClicked()
{
    QDesktopServices::openUrl(QUrl("http://www.lotuscoin.com/"));
    /*
    // CSV is currently the only supported format
    QString filename = GUIUtil::getSaveFileName(
            this,
            tr("Export Address Book Data"), QString(),
            tr("Comma separated file (*.csv)"));

    if (filename.isNull()) return;

    CSVModelWriter writer(filename);

    // name, column, role
    writer.setModel(proxyModel);
    writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
    writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);

    if(!writer.write())
    {
        QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
                              QMessageBox::Abort, QMessageBox::Abort);
    }
    */
}

void AddressBookPage::on_showQRCode_clicked()
{
#ifdef USE_QRCODE
    QTableView *table = ui->tableView;
    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);

    foreach (QModelIndex index, indexes)
    {
        QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();

        QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
        if(optionsModel)
            dialog->setModel(optionsModel);
        dialog->setAttribute(Qt::WA_DeleteOnClose);
        dialog->show();
    }
#endif
}

void AddressBookPage::contextualMenu(const QPoint &point)
{
    QModelIndex index = ui->tableView->indexAt(point);
    if(index.isValid())
    {
        contextMenu->exec(QCursor::pos());
    }
}

void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end)
{
    QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
    if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
    {
        // Select row of newly created address, once
        ui->tableView->setFocus();
        ui->tableView->selectRow(idx.row());
        newAddressToSelect.clear();
    }
}
<|endoftext|>


<commit_before>#include "transactiondesc.h"

#include "guiutil.h"
#include "bitcoinunits.h"

#include "main.h"
#include "wallet.h"
#include "txdb.h"
#include "ui_interface.h"
#include "base58.h"

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    if (!wtx.IsFinal())
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime);
        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
    }
    else
    {
        int nDepth = wtx.GetDepthInMainChain();
        if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);
        else if (nDepth < 6)
            return tr("%1/unconfirmed").arg(nDepth);
        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
    QString strHTML;

    {
        LOCK(wallet->cs_wallet);
        strHTML.reserve(4000);
        strHTML += "";

        int64 nTime = wtx.GetTxTime();
        int64 nCredit = wtx.GetCredit();
        int64 nDebit = wtx.GetDebit();
        int64 nNet = nCredit - nDebit;

        strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);
        int nRequests = wtx.GetRequestCount();
        if (nRequests != -1)
        {
            if (nRequests == 0)
                strHTML += tr(", has not been successfully broadcast yet");
            else if (nRequests > 0)
                strHTML += tr(", broadcast through %n node(s)", "", nRequests);
        }
        strHTML += "
";

        strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

        //
        // From
        //
        if (wtx.IsCoinBase())
        {
            strHTML += "" + tr("Source") + ": " + tr("Generated") + "
";
        }
        else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
        {
            // Online transaction
            strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";
        }
        else
        {
            // Offline transaction
            if (nNet > 0)
            {
                // Credit
                BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                {
                    if (wallet->IsMine(txout))
                    {
                        CTxDestination address;
                        if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                        {
                            if (wallet->mapAddressBook.count(address))
                            {
                                strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                                strHTML += "" + tr("To") + ": ";
                                strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                                if (!wallet->mapAddressBook[address].empty())
                                    strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
                                else
                                    strHTML += " (" + tr("own address") + ")";
                                strHTML += "
";
                            }
                        }
                        break;
                    }
                }
            }
        }

        //
        // To
        //
        if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
        {
            // Online transaction
            std::string strAddress = wtx.mapValue["to"];
            strHTML += "" + tr("To") + ": ";
            CTxDestination dest = CBitcoinAddress(strAddress).Get();
            if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
                strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
            strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
        }

        //
        // Amount
        //
        if (wtx.IsCoinBase() && nCredit == 0)
        {
            //
            // Coinbase
            //
            int64 nUnmatured = 0;
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                nUnmatured += wallet->GetCredit(txout);
            strHTML += "" + tr("Credit") + ": ";
            if (wtx.IsInMainChain())
                strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
            else
                strHTML += "(" + tr("not accepted") + ")";
            strHTML += "
";
        }
        else if (nNet > 0)
        {
            //
            // Credit
            //
            strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "
";
        }
        else
        {
            bool fAllFromMe = true;
            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                fAllFromMe = fAllFromMe && wallet->IsMine(txin);

            bool fAllToMe = true;
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                fAllToMe = fAllToMe && wallet->IsMine(txout);

            if (fAllFromMe)
            {
                //
                // Debit
                //
                BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                {
                    if (wallet->IsMine(txout))
                        continue;

                    if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                    {
                        // Offline transaction
                        CTxDestination address;
                        if (ExtractDestination(txout.scriptPubKey, address))
                        {
                            strHTML += "" + tr("To") + ": ";
                            if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                                strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                            strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                            strHTML += "
";
                        }
                    }

                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "
";
                }

                if (fAllToMe)
                {
                    // Payment to self
                    int64 nChange = wtx.GetChange();
                    int64 nValue = nCredit - nChange;
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "
";
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "
";
                }

                int64 nTxFee = nDebit - wtx.GetValueOut();
                if (nTxFee > 0)
                    strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "
";
            }
            else
            {
                //
                // Mixed debit transaction
                //
                BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                    if (wallet->IsMine(txin))
                        strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
                BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                    if (wallet->IsMine(txout))
                        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";
            }
        }

        strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "
";

        //
        // Message
        //
        if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
            strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";
        if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
            strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

        strHTML += "" + tr("Transaction ID") + ": " + wtx.GetHash().ToString().c_str() + "
";

        if (wtx.IsCoinBase() || wtx.IsCoinStake())
            strHTML += "
" + tr("Generated coins must mature 112 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";

        //
        // Debug view
        //
        if (fDebug)
        {
            strHTML += "

" + tr("Debug information") + "

";
            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                if(wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                if(wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";

            strHTML += "
" + tr("Transaction") + ":
";
            strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);

            CTxDB txdb("r"); // To fetch source txouts

            strHTML += "
" + tr("Inputs") + ":";
            strHTML += "
";

            {
                LOCK(wallet->cs_wallet);
                BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                {
                    COutPoint prevout = txin.prevout;

                    CTransaction prev;
                    if(txdb.ReadDiskTx(prevout.hash, prev))
                    {
                        if (prevout.n < prev.vout.size())
                        {
                            strHTML += "
";
                            const CTxOut &vout = prev.vout[prevout.n];
                            CTxDestination address;
                            if (ExtractDestination(vout.scriptPubKey, address))
                            {
                                if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                                    strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                                strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
                            }
                            strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
                            strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "
";
                        }
                    }
                }
            }

            strHTML += "
";
        }

        strHTML += "";
    }
    return strHTML;
}
<commit_msg>fix description<commit_after>#include "transactiondesc.h"

#include "guiutil.h"
#include "bitcoinunits.h"

#include "main.h"
#include "wallet.h"
#include "txdb.h"
#include "ui_interface.h"
#include "base58.h"

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    if (!wtx.IsFinal())
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime);
        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
    }
    else
    {
        int nDepth = wtx.GetDepthInMainChain();
        if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);
        else if (nDepth < 6)
            return tr("%1/unconfirmed").arg(nDepth);
        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
    QString strHTML;

    {
        LOCK(wallet->cs_wallet);
        strHTML.reserve(4000);
        strHTML += "";

        int64 nTime = wtx.GetTxTime();
        int64 nCredit = wtx.GetCredit();
        int64 nDebit = wtx.GetDebit();
        int64 nNet = nCredit - nDebit;

        strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);
        int nRequests = wtx.GetRequestCount();
        if (nRequests != -1)
        {
            if (nRequests == 0)
                strHTML += tr(", has not been successfully broadcast yet");
            else if (nRequests > 0)
                strHTML += tr(", broadcast through %n node(s)", "", nRequests);
        }
        strHTML += "
";

        strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

        //
        // From
        //
        if (wtx.IsCoinBase())
        {
            strHTML += "" + tr("Source") + ": " + tr("Generated") + "
";
        }
        else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
        {
            // Online transaction
            strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";
        }
        else
        {
            // Offline transaction
            if (nNet > 0)
            {
                // Credit
                BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                {
                    if (wallet->IsMine(txout))
                    {
                        CTxDestination address;
                        if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                        {
                            if (wallet->mapAddressBook.count(address))
                            {
                                strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                                strHTML += "" + tr("To") + ": ";
                                strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                                if (!wallet->mapAddressBook[address].empty())
                                    strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
                                else
                                    strHTML += " (" + tr("own address") + ")";
                                strHTML += "
";
                            }
                        }
                        break;
                    }
                }
            }
        }

        //
        // To
        //
        if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
        {
            // Online transaction
            std::string strAddress = wtx.mapValue["to"];
            strHTML += "" + tr("To") + ": ";
            CTxDestination dest = CBitcoinAddress(strAddress).Get();
            if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
                strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
            strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
        }

        //
        // Amount
        //
        if (wtx.IsCoinBase() && nCredit == 0)
        {
            //
            // Coinbase
            //
            int64 nUnmatured = 0;
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                nUnmatured += wallet->GetCredit(txout);
            strHTML += "" + tr("Credit") + ": ";
            if (wtx.IsInMainChain())
                strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
            else
                strHTML += "(" + tr("not accepted") + ")";
            strHTML += "
";
        }
        else if (nNet > 0)
        {
            //
            // Credit
            //
            strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "
";
        }
        else
        {
            bool fAllFromMe = true;
            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                fAllFromMe = fAllFromMe && wallet->IsMine(txin);

            bool fAllToMe = true;
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                fAllToMe = fAllToMe && wallet->IsMine(txout);

            if (fAllFromMe)
            {
                //
                // Debit
                //
                BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                {
                    if (wallet->IsMine(txout))
                        continue;

                    if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                    {
                        // Offline transaction
                        CTxDestination address;
                        if (ExtractDestination(txout.scriptPubKey, address))
                        {
                            strHTML += "" + tr("To") + ": ";
                            if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                                strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                            strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                            strHTML += "
";
                        }
                    }

                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "
";
                }

                if (fAllToMe)
                {
                    // Payment to self
                    int64 nChange = wtx.GetChange();
                    int64 nValue = nCredit - nChange;
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "
";
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "
";
                }

                int64 nTxFee = nDebit - wtx.GetValueOut();
                if (nTxFee > 0)
                    strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "
";
            }
            else
            {
                //
                // Mixed debit transaction
                //
                BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                    if (wallet->IsMine(txin))
                        strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
                BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                    if (wallet->IsMine(txout))
                        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";
            }
        }

        strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "
";

        //
        // Message
        //
        if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
            strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";
        if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
            strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

        strHTML += "" + tr("Transaction ID") + ": " + wtx.GetHash().ToString().c_str() + "
";

        if (wtx.IsCoinBase() || wtx.IsCoinStake())
            strHTML += "
" + tr("Generated coins must mature 32 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";

        //
        // Debug view
        //
        if (fDebug)
        {
            strHTML += "

" + tr("Debug information") + "

";
            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                if(wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                if(wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";

            strHTML += "
" + tr("Transaction") + ":
";
            strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);

            CTxDB txdb("r"); // To fetch source txouts

            strHTML += "
" + tr("Inputs") + ":";
            strHTML += "
";

            {
                LOCK(wallet->cs_wallet);
                BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                {
                    COutPoint prevout = txin.prevout;

                    CTransaction prev;
                    if(txdb.ReadDiskTx(prevout.hash, prev))
                    {
                        if (prevout.n < prev.vout.size())
                        {
                            strHTML += "
";
                            const CTxOut &vout = prev.vout[prevout.n];
                            CTxDestination address;
                            if (ExtractDestination(vout.scriptPubKey, address))
                            {
                                if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                                    strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                                strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
                            }
                            strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
                            strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "
";
                        }
                    }
                }
            }

            strHTML += "
";
        }

        strHTML += "";
    }
    return strHTML;
}
<|endoftext|>