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

  SamplePlayer.cpp
  Author:  Daniel Lindenfelser

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

#include "Player.h"

Player::Player(int index, const File &audioFile, AudioFormatManager *formatManager, AudioThumbnailCache *thumbnailCache)
                                : playerIndex(index),
                                  timeSliceThread("Player: " + audioFile.getFileNameWithoutExtension()), title(audioFile.getFileNameWithoutExtension()),
                                  playerState(Ready),
                                  fadeGain(1.0f),
                                  fadeGainBackup(1.0f),
                                  fadeGainSteps(0.1f),
                                  fadeSeconds(6),
                                  fadeOut(false),
                                  fadeIn(false),
                                  process(0.0f),
                                  audioFormatManager(formatManager),
                                  thumbnailCache(thumbnailCache),
                                  thumbnail(nullptr),
                                  transportSource(new AudioTransportSource())
{
    timeSliceThread.startThread(3);
    audioSourcePlayer.setSource(transportSource);
    loadFileIntoTransport(audioFile);
    startTimer(UpdateTimerId, 50);
    startTimer(FadeTimerId, 100);
}

Player::~Player()
{
    removeAllChangeListeners();
    thumbnail->removeAllChangeListeners();
    thumbnail->clear();
    removeAllChangeListeners();
    stopTimer(UpdateTimerId);
    stopTimer(FadeTimerId);
    thumbnail->setSource(nullptr);
    thumbnail = nullptr;
    transportSource->setSource(nullptr);
    audioSourcePlayer.setSource(nullptr);
    transportSource->removeAllChangeListeners();
    transportSource = nullptr;
}

void Player::loadFileIntoTransport(const File &audioFile)
{
    transportSource->stop();
    transportSource->setSource(nullptr);
    currentAudioFileSource = nullptr;

    auto reader = audioFormatManager->createReaderFor(audioFile);

    if (reader != nullptr)
    {
        currentAudioFileSource = new AudioFormatReaderSource(reader, true);

        transportSource->setSource(currentAudioFileSource, 32768, &timeSliceThread, reader->sampleRate);

        thumbnail = new AudioThumbnail(1024, *audioFormatManager, *thumbnailCache);
        thumbnail->setSource(new FileInputSource(audioFile));
        playerState = Stopped;
    }
    else
    {
        playerState = Error;
    }
}

AudioThumbnail *Player::getThumbnail()
{
    return thumbnail;
}

void Player::update()
{
    process = static_cast<float>(transportSource->getCurrentPosition() / transportSource->getLengthInSeconds());
    if (isPlaying()) {
        sendChangeMessage();
    }

    if (process >= 1.0f) {
        process = 1.0f;
        transportSource->stop();
        transportSource->setPosition(0);
        playerState = Played;
        sendChangeMessage();
    }
    if (isFading()) {
        if (!isPlaying()) {
            cancelFading();
        }
    }
}

void Player::timerCallback(int timerID)
{
    if (timerID == UpdateTimerId)
    {
        update();
        return;
    }
    if (timerID == FadeTimerId)
    {
        if (isFading()) {
            if (fadeOut) {
                fadeGain = fadeGain - fadeGainSteps;
                if (fadeGain <= 0) {
                    fadeOut = false;
                    pause();
                    fadeGain = fadeGainBackup;
                    transportSource->setGain(fadeGainBackup);
                    update();
                    sendChangeMessage();
                    return;
                }
                transportSource->setGain(fadeGain);
            } else if (fadeIn) {
                fadeGain = fadeGain + fadeGainSteps;
                if (fadeGain >= fadeGainBackup) {
                    fadeIn = false;
                    playerState = Playing;
                    fadeGain = fadeGainBackup;
                    transportSource->setGain(fadeGainBackup);
                    update();
                    sendChangeMessage();
                    return;
                }
                transportSource->setGain(fadeGain);
            }
            update();
            sendChangeMessage();
        }
    }
}

void Player::startFadeOut()
{
    if (isPlaying())
    {
        fadeOut           = true;
        fadeGainBackup = transportSource->getGain();
        fadeGain = transportSource->getGain();
        fadeGainSteps = fadeGainBackup / fadeSeconds / 10.0f;
    }
}

void Player::startFadeIn()
{
    if (!isPlaying())
    {
        fadeIn           = true;
        fadeGainBackup = transportSource->getGain();
        fadeGain = 0;
        fadeGainSteps = fadeGainBackup / fadeSeconds / 10.0f;
        transportSource->setGain(fadeGain);
        transportSource->setPosition(transportSource->getCurrentPosition());
        play();
    }
}

void Player::stop()
{
    cancelFading();
    transportSource->stop();
    transportSource->setPosition(0);
    playerState = Stopped;
    update();
    sendChangeMessage();
}

void Player::play()
{
    if (!fadeOut)
    {
        transportSource->start();
        playerState = Playing;
    }
}

void Player::pause()
{
    if (!fadeOut)
    {
        transportSource->stop();
        playerState = Paused;
    }
}

float Player::getProgress()
{
    return process;
}

void Player::setFadeTime(int seconds)
{
    fadeSeconds = seconds;
}

bool Player::isLooping()
{
    return currentAudioFileSource->isLooping();
}

void Player::setLooping(bool value)
{
    if (isPlaying() && !value)
    {
        auto nextReadPosition = transportSource->getNextReadPosition();
        currentAudioFileSource->setLooping(false);
        transportSource->setNextReadPosition(nextReadPosition);
        return;
    }
    currentAudioFileSource->setLooping(value);
    sendChangeMessage();
}

String Player::getTitle()
{
    return title;
}

String Player::getProgressString(bool remaining)
{
    if (!remaining)
    {
        Time time(1971, 0, 0, 0, 0, static_cast<int>(transportSource->getCurrentPosition()));
        return time.toString(false, true, true, true);
    }
    Time time(1971, 0, 0, 0, 0, static_cast<int>(transportSource->getLengthInSeconds() - transportSource->getCurrentPosition()));
    return "-" + time.toString(false, true, true, true);
}

float Player::getGain()
{
    return transportSource->getGain();
}

void Player::setGain(float newGain)
{
    transportSource->setGain(newGain);
}

Player::PlayerState Player::getState()
{
    return playerState;
}

AudioSource *Player::getAudioSource()
{
    return transportSource;
}

bool Player::isStopped()
{
    return playerState == Stopped;
}

bool Player::isPlayed()
{
    return playerState == Played;
}

bool Player::isPlaying()
{
    return playerState == Playing;
}

bool Player::isPaused()
{
    return playerState == Paused;
}

bool Player::isFadingOut()
{
    return fadeOut;
}

void Player::setIndex(int value)
{
    playerIndex = value;
}

int Player::getIndex()
{
    return playerIndex;
}

#if JUCE_UNIT_TESTS
class PlayerTest : public UnitTest {
public:
    PlayerTest() : UnitTest ("Ultraschall: Player") {}

	void initialise() {
        formatManager = new AudioFormatManager();
        thumbnailCache = new AudioThumbnailCache(thumbnailCacheSize);

        formatManager->registerBasicFormats();
	}

	void shutdown() {
        formatManager = nullptr;
        thumbnailCache = nullptr;
	}

    void initPlayerTest() {
        beginTest("init player");
//        ScopedPointer<File> dummy = new File();
//        ScopedPointer<Player> player = new Player(1, *dummy, formatManager, thumbnailCache);
//        player = nullptr;
//        dummy = nullptr;
        expect(false, "internal crash");
    }

    void loadFileTest() {
        beginTest("load file");
        expect(false, "Not implemented");
    }

    void playTest() {
        beginTest("play player");
        expect(false, "Not implemented");
    }

    void pauseTest() {
        beginTest("pause player");
        expect(false, "Not implemented");
    }

    void stopTest() {
        beginTest("stop player");
        expect(false, "Not implemented");
    }

	void runTest() {
//		initPlayerTest();
//
//        loadFileTest();
//
//        playTest();
//        pauseTest();
//        stopTest();
	}

private:
    ScopedPointer<AudioFormatManager> formatManager;
    ScopedPointer<AudioThumbnailCache> thumbnailCache;
    const int thumbnailCacheSize = 5;
};

static PlayerTest playerTest;
#endif

bool Player::isFadingIn() {
    return fadeIn;
}

bool Player::isFading() {
    return fadeOut || fadeIn;
}

void Player::cancelFading() {
    if (isFading())
    {
        fadeOut     = false;
        fadeIn      = false;
        fadeGain = fadeGainBackup;
        transportSource->setGain(fadeGain);
    }
}
<commit_msg>maximum fadetime = sample time<commit_after>/*
  ==============================================================================

  SamplePlayer.cpp
  Author:  Daniel Lindenfelser

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

#include "Player.h"

Player::Player(int index, const File &audioFile, AudioFormatManager *formatManager, AudioThumbnailCache *thumbnailCache)
                                : playerIndex(index),
                                  timeSliceThread("Player: " + audioFile.getFileNameWithoutExtension()), title(audioFile.getFileNameWithoutExtension()),
                                  playerState(Ready),
                                  fadeGain(1.0f),
                                  fadeGainBackup(1.0f),
                                  fadeGainSteps(0.1f),
                                  fadeSeconds(6),
                                  fadeOut(false),
                                  fadeIn(false),
                                  process(0.0f),
                                  audioFormatManager(formatManager),
                                  thumbnailCache(thumbnailCache),
                                  thumbnail(nullptr),
                                  transportSource(new AudioTransportSource())
{
    timeSliceThread.startThread(3);
    audioSourcePlayer.setSource(transportSource);
    loadFileIntoTransport(audioFile);
    startTimer(UpdateTimerId, 50);
    startTimer(FadeTimerId, 100);
}

Player::~Player()
{
    removeAllChangeListeners();
    thumbnail->removeAllChangeListeners();
    thumbnail->clear();
    removeAllChangeListeners();
    stopTimer(UpdateTimerId);
    stopTimer(FadeTimerId);
    thumbnail->setSource(nullptr);
    thumbnail = nullptr;
    transportSource->setSource(nullptr);
    audioSourcePlayer.setSource(nullptr);
    transportSource->removeAllChangeListeners();
    transportSource = nullptr;
}

void Player::loadFileIntoTransport(const File &audioFile)
{
    transportSource->stop();
    transportSource->setSource(nullptr);
    currentAudioFileSource = nullptr;

    auto reader = audioFormatManager->createReaderFor(audioFile);

    if (reader != nullptr)
    {
        currentAudioFileSource = new AudioFormatReaderSource(reader, true);

        transportSource->setSource(currentAudioFileSource, 32768, &timeSliceThread, reader->sampleRate);

        thumbnail = new AudioThumbnail(1024, *audioFormatManager, *thumbnailCache);
        thumbnail->setSource(new FileInputSource(audioFile));
        playerState = Stopped;
    }
    else
    {
        playerState = Error;
    }
}

AudioThumbnail *Player::getThumbnail()
{
    return thumbnail;
}

void Player::update()
{
    process = static_cast<float>(transportSource->getCurrentPosition() / transportSource->getLengthInSeconds());
    if (isPlaying()) {
        sendChangeMessage();
    }

    if (process >= 1.0f) {
        process = 1.0f;
        transportSource->stop();
        transportSource->setPosition(0);
        playerState = Played;
        sendChangeMessage();
    }
    if (isFading()) {
        if (!isPlaying()) {
            cancelFading();
        }
    }
}

void Player::timerCallback(int timerID)
{
    if (timerID == UpdateTimerId)
    {
        update();
        return;
    }
    if (timerID == FadeTimerId)
    {
        if (isFading()) {
            if (fadeOut) {
                fadeGain = fadeGain - fadeGainSteps;
                if (fadeGain <= 0) {
                    fadeOut = false;
                    pause();
                    fadeGain = fadeGainBackup;
                    transportSource->setGain(fadeGainBackup);
                    update();
                    sendChangeMessage();
                    return;
                }
                transportSource->setGain(fadeGain);
            } else if (fadeIn) {
                fadeGain = fadeGain + fadeGainSteps;
                if (fadeGain >= fadeGainBackup) {
                    fadeIn = false;
                    playerState = Playing;
                    fadeGain = fadeGainBackup;
                    transportSource->setGain(fadeGainBackup);
                    update();
                    sendChangeMessage();
                    return;
                }
                transportSource->setGain(fadeGain);
            }
            update();
            sendChangeMessage();
        }
    }
}

void Player::startFadeOut()
{
    if (isPlaying())
    {
        fadeOut           = true;
        fadeGainBackup = transportSource->getGain();
        fadeGain = transportSource->getGain();
        fadeGainSteps = fadeGainBackup / fadeSeconds / 10.0f;
    }
}

void Player::startFadeIn()
{
    if (!isPlaying())
    {
        fadeIn           = true;
        fadeGainBackup = transportSource->getGain();
        fadeGain = 0;
        float fade = fadeSeconds;
        if (transportSource->getLengthInSeconds() < fade) {
            fade = float(transportSource->getLengthInSeconds());
            if (fade <= 0) {
                fade = 0.1f;
            }
        }
        fadeGainSteps = fadeGainBackup / fade / 10.0f;
        transportSource->setGain(fadeGain);
        play();
    }
}

void Player::stop()
{
    cancelFading();
    transportSource->stop();
    transportSource->setPosition(0);
    playerState = Stopped;
    update();
    sendChangeMessage();
}

void Player::play()
{
    if (!fadeOut)
    {
        transportSource->start();
        playerState = Playing;
    }
}

void Player::pause()
{
    if (!fadeOut)
    {
        transportSource->stop();
        playerState = Paused;
    }
}

float Player::getProgress()
{
    return process;
}

void Player::setFadeTime(int seconds)
{
    fadeSeconds = seconds;
}

bool Player::isLooping()
{
    return currentAudioFileSource->isLooping();
}

void Player::setLooping(bool value)
{
    if (isPlaying() && !value)
    {
        auto nextReadPosition = transportSource->getNextReadPosition();
        currentAudioFileSource->setLooping(false);
        transportSource->setNextReadPosition(nextReadPosition);
        return;
    }
    currentAudioFileSource->setLooping(value);
    sendChangeMessage();
}

String Player::getTitle()
{
    return title;
}

String Player::getProgressString(bool remaining)
{
    if (!remaining)
    {
        Time time(1971, 0, 0, 0, 0, static_cast<int>(transportSource->getCurrentPosition()));
        return time.toString(false, true, true, true);
    }
    Time time(1971, 0, 0, 0, 0, static_cast<int>(transportSource->getLengthInSeconds() - transportSource->getCurrentPosition()));
    return "-" + time.toString(false, true, true, true);
}

float Player::getGain()
{
    return transportSource->getGain();
}

void Player::setGain(float newGain)
{
    transportSource->setGain(newGain);
}

Player::PlayerState Player::getState()
{
    return playerState;
}

AudioSource *Player::getAudioSource()
{
    return transportSource;
}

bool Player::isStopped()
{
    return playerState == Stopped;
}

bool Player::isPlayed()
{
    return playerState == Played;
}

bool Player::isPlaying()
{
    return playerState == Playing;
}

bool Player::isPaused()
{
    return playerState == Paused;
}

bool Player::isFadingOut()
{
    return fadeOut;
}

void Player::setIndex(int value)
{
    playerIndex = value;
}

int Player::getIndex()
{
    return playerIndex;
}

#if JUCE_UNIT_TESTS
class PlayerTest : public UnitTest {
public:
    PlayerTest() : UnitTest ("Ultraschall: Player") {}

	void initialise() {
        formatManager = new AudioFormatManager();
        thumbnailCache = new AudioThumbnailCache(thumbnailCacheSize);

        formatManager->registerBasicFormats();
	}

	void shutdown() {
        formatManager = nullptr;
        thumbnailCache = nullptr;
	}

    void initPlayerTest() {
        beginTest("init player");
//        ScopedPointer<File> dummy = new File();
//        ScopedPointer<Player> player = new Player(1, *dummy, formatManager, thumbnailCache);
//        player = nullptr;
//        dummy = nullptr;
        expect(false, "internal crash");
    }

    void loadFileTest() {
        beginTest("load file");
        expect(false, "Not implemented");
    }

    void playTest() {
        beginTest("play player");
        expect(false, "Not implemented");
    }

    void pauseTest() {
        beginTest("pause player");
        expect(false, "Not implemented");
    }

    void stopTest() {
        beginTest("stop player");
        expect(false, "Not implemented");
    }

	void runTest() {
//		initPlayerTest();
//
//        loadFileTest();
//
//        playTest();
//        pauseTest();
//        stopTest();
	}

private:
    ScopedPointer<AudioFormatManager> formatManager;
    ScopedPointer<AudioThumbnailCache> thumbnailCache;
    const int thumbnailCacheSize = 5;
};

static PlayerTest playerTest;
#endif

bool Player::isFadingIn() {
    return fadeIn;
}

bool Player::isFading() {
    return fadeOut || fadeIn;
}

void Player::cancelFading() {
    if (isFading())
    {
        fadeOut     = false;
        fadeIn      = false;
        fadeGain = fadeGainBackup;
        transportSource->setGain(fadeGain);
        update();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/app_modal_dialog_queue.h"

#include "chrome/browser/browser_list.h"

void AppModalDialogQueue::AddDialog(AppModalDialog* dialog) {
  if (!active_dialog_) {
    ShowModalDialog(dialog);
    return;
  }
  app_modal_dialog_queue_.push(dialog);
}

void AppModalDialogQueue::ShowNextDialog() {
  AppModalDialog* dialog = GetNextDialog();
  if (dialog)
    ShowModalDialog(dialog);
  else
    active_dialog_ = NULL;
}

void AppModalDialogQueue::ActivateModalDialog() {
  if (showing_modal_dialog_) {
    // As part of showing a modal dialog we may end up back in this method
    // (showing a dialog activates the TabContents, which can trigger a call
    // to ActivateModalDialog). We ignore such a request as after the call to
    // activate the tab contents the dialog is shown.
    return;
  }
  if (active_dialog_)
    active_dialog_->ActivateModalDialog();
}

void AppModalDialogQueue::ShowModalDialog(AppModalDialog* dialog) {
  // Be sure and set the active_dialog_ field first, otherwise if
  // ShowModalDialog triggers a call back to the queue they'll get the old
  // dialog. Also, if the dialog calls |ShowNextDialog()| before returning, that
  // would write NULL into |active_dialog_| and this function would then undo
  // that.
  active_dialog_ = dialog;
  showing_modal_dialog_ = true;
  dialog->ShowModalDialog();
  showing_modal_dialog_ = false;
}

AppModalDialog* AppModalDialogQueue::GetNextDialog() {
  while (!app_modal_dialog_queue_.empty()) {
    AppModalDialog* dialog = app_modal_dialog_queue_.front();
    app_modal_dialog_queue_.pop();
    if (dialog->IsValid())
      return dialog;
    delete dialog;
  }
  return NULL;
}
<commit_msg>Copyright change to force builders to rebuild.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/app_modal_dialog_queue.h"

#include "chrome/browser/browser_list.h"

void AppModalDialogQueue::AddDialog(AppModalDialog* dialog) {
  if (!active_dialog_) {
    ShowModalDialog(dialog);
    return;
  }
  app_modal_dialog_queue_.push(dialog);
}

void AppModalDialogQueue::ShowNextDialog() {
  AppModalDialog* dialog = GetNextDialog();
  if (dialog)
    ShowModalDialog(dialog);
  else
    active_dialog_ = NULL;
}

void AppModalDialogQueue::ActivateModalDialog() {
  if (showing_modal_dialog_) {
    // As part of showing a modal dialog we may end up back in this method
    // (showing a dialog activates the TabContents, which can trigger a call
    // to ActivateModalDialog). We ignore such a request as after the call to
    // activate the tab contents the dialog is shown.
    return;
  }
  if (active_dialog_)
    active_dialog_->ActivateModalDialog();
}

void AppModalDialogQueue::ShowModalDialog(AppModalDialog* dialog) {
  // Be sure and set the active_dialog_ field first, otherwise if
  // ShowModalDialog triggers a call back to the queue they'll get the old
  // dialog. Also, if the dialog calls |ShowNextDialog()| before returning, that
  // would write NULL into |active_dialog_| and this function would then undo
  // that.
  active_dialog_ = dialog;
  showing_modal_dialog_ = true;
  dialog->ShowModalDialog();
  showing_modal_dialog_ = false;
}

AppModalDialog* AppModalDialogQueue::GetNextDialog() {
  while (!app_modal_dialog_queue_.empty()) {
    AppModalDialog* dialog = app_modal_dialog_queue_.front();
    app_modal_dialog_queue_.pop();
    if (dialog->IsValid())
      return dialog;
    delete dialog;
  }
  return NULL;
}
<|endoftext|>


<commit_before>#include "downloader/image-downloader.h"
#include <QUuid>
#include "extension-rotator.h"
#include "file-downloader.h"
#include "functions.h"
#include "logger.h"
#include "models/filename.h"
#include "models/image.h"
#include "models/profile.h"
#include "models/site.h"
#include "models/source.h"

ImageDownloader::ImageDownloader(QSharedPointer<Image> img, QString filename, QString path, int count, bool addMd5, bool startCommands, QObject *parent, bool loadTags, bool rotate, bool force)
	: QObject(parent), m_image(std::move(img)), m_fileDownloader(false, this), m_filename(std::move(filename)), m_path(std::move(path)), m_loadTags(loadTags), m_count(count), m_addMd5(addMd5), m_startCommands(startCommands), m_writeError(false), m_rotate(rotate), m_force(force)
{}

ImageDownloader::ImageDownloader(QSharedPointer<Image> img, QStringList paths, int count, bool addMd5, bool startCommands, QObject *parent, bool rotate, bool force)
	: QObject(parent), m_image(std::move(img)), m_fileDownloader(false, this), m_loadTags(false), m_paths(std::move(paths)), m_count(count), m_addMd5(addMd5), m_startCommands(startCommands), m_writeError(false), m_rotate(rotate), m_force(force)
{}

ImageDownloader::~ImageDownloader()
{
	if (m_reply != nullptr)
		m_reply->deleteLater();
}

bool ImageDownloader::isRunning() const
{
	return m_reply != nullptr && m_reply->isRunning();
}

void ImageDownloader::save()
{
	// If we use direct saving or don't want to load tags, we directly save the image
	if (!m_loadTags || !m_paths.isEmpty() || Filename(m_filename).needExactTags(m_image->parentSite()) == 0)
	{
		loadedSave();
		return;
	}

	connect(m_image.data(), &Image::finishedLoadingTags, this, &ImageDownloader::loadedSave);
	m_image->loadDetails();
}

void ImageDownloader::abort()
{
	if (m_reply != nullptr && m_reply->isRunning())
		m_reply->abort();
}

void ImageDownloader::loadedSave()
{
	// Get the download path from the image if possible
	if (m_paths.isEmpty())
	{
		m_paths = m_image->path(m_filename, m_path, m_count, true, false, true, true, true);

		// Use a random temporary file if we need the MD5 or equivalent
		Profile *profile = m_image->parentSite()->getSource()->getProfile();
		if (Filename(m_filename).needTemporaryFile(m_image->tokens(profile)))
		{
			const QString tmpDir = !m_path.isEmpty() ? m_path : QDir::tempPath();
			m_temporaryPath = tmpDir + "/" + QUuid::createUuid().toString().mid(1, 36) + ".tmp";
		}
	}

	// Directly use the image path as temporary file  if possible
	if (m_temporaryPath.isEmpty())
	{ m_temporaryPath = m_paths.first() + ".tmp"; }

	// Try to save the image if it's already loaded or exists somewhere else on disk
	if (!m_force)
	{
		Image::SaveResult res = m_image->preSave(m_temporaryPath);

		// If we don't need any loading, we can return already
		if (res != Image::SaveResult::NotLoaded)
		{
			QMap<QString, Image::SaveResult> result {{ m_temporaryPath, res }};

			if (res == Image::SaveResult::Saved || res == Image::SaveResult::Copied || res == Image::SaveResult::Moved)
			{ result = postSaving(res); }

			emit saved(m_image, result);
			return;
		}
	}

	m_url = m_image->url(Image::Size::Full);
	loadImage();
}

void ImageDownloader::loadImage()
{
	connect(&m_fileDownloader, &FileDownloader::success, this, &ImageDownloader::success, Qt::UniqueConnection);
	connect(&m_fileDownloader, &FileDownloader::networkError, this, &ImageDownloader::networkError, Qt::UniqueConnection);
	connect(&m_fileDownloader, &FileDownloader::writeError, this, &ImageDownloader::writeError, Qt::UniqueConnection);

	// Delete previous replies for retries
	if (m_reply != nullptr)
	{ m_reply->deleteLater(); }

	// Load the image directly on the disk
	log(QStringLiteral("Loading and saving image in %1").arg(m_paths.first()));
	Site *site = m_image->parentSite();
	m_reply = site->get(site->fixUrl(m_url.toString()), m_image->page(), QStringLiteral("image"), m_image.data());
	m_reply->setParent(this);
	connect(m_reply, &QNetworkReply::downloadProgress, this, &ImageDownloader::downloadProgressImage);

	// Create download root directory
	const QString rootDir = m_temporaryPath.section(QDir::separator(), 0, -2);
	if (!QDir(rootDir).exists() && !QDir().mkpath(rootDir))
	{
		log(QStringLiteral("Impossible to create the destination folder: %1.").arg(rootDir), Logger::Error);
		emit saved(m_image, makeMap(m_paths, Image::SaveResult::Error));
		return;
	}

	// If we can't start writing for some reason, return an error
	if (!m_fileDownloader.start(m_reply, QStringList() << m_temporaryPath))
	{
		log(QStringLiteral("Unable to open file"), Logger::Error);
		emit saved(m_image, makeMap(m_paths, Image::SaveResult::Error));
		return;
	}
}

void ImageDownloader::downloadProgressImage(qint64 v1, qint64 v2)
{
	if (m_image->fileSize() == 0 || m_image->fileSize() < v2 / 2)
		m_image->setFileSize(v2);

	emit downloadProgress(m_image, v1, v2);
}

QMap<QString, Image::SaveResult> ImageDownloader::makeMap(const QStringList &keys, Image::SaveResult value)
{
	QMap<QString, Image::SaveResult> res;
	for (const QString &key : keys)
		res.insert(key, value);
	return res;
}

void ImageDownloader::writeError()
{
	emit saved(m_image, makeMap(m_paths, Image::SaveResult::Error));
}

void ImageDownloader::networkError(QNetworkReply::NetworkError error, const QString &msg)
{
	if (error == QNetworkReply::ContentNotFoundError)
	{
		QSettings *settings = m_image->parentSite()->getSource()->getProfile()->getSettings();
		ExtensionRotator *extensionRotator = m_image->extensionRotator();

		const bool sampleFallback = settings->value("Save/samplefallback", true).toBool();
		QString newext = extensionRotator != nullptr ? extensionRotator->next() : QString();

		const bool shouldFallback = sampleFallback && !m_image->url(Image::Size::Sample).isEmpty();
		const bool isLast = newext.isEmpty() || (shouldFallback && m_tryingSample);

		if (m_rotate && (!isLast || (shouldFallback && !m_tryingSample)))
		{
			if (isLast)
			{
				m_url = m_image->url(Image::Size::Sample);
				m_tryingSample = true;
				log(QStringLiteral("Image not found. New try with its sample..."));
			}
			else
			{
				m_url = setExtension(m_image->url(Image::Size::Full), newext);
				log(QStringLiteral("Image not found. New try with extension %1 (%2)...").arg(newext, m_url.toString()));
			}

			m_image->setUrl(m_url);
			loadImage();
		}
		else
		{
			log(QStringLiteral("Image not found."));
			emit saved(m_image, makeMap(m_paths, Image::SaveResult::NotFound));
		}
	}
	else if (error != QNetworkReply::OperationCanceledError)
	{
		log(QStringLiteral("Network error for the image: %1: %2 (%3)").arg(m_image->url().toString().toHtmlEscaped()).arg(error).arg(msg), Logger::Error);
		emit saved(m_image, makeMap(m_paths, Image::SaveResult::NetworkError));
	}
}

void ImageDownloader::success()
{
	// Handle network redirects
	QUrl redir = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
	if (!redir.isEmpty())
	{
		m_url = redir;
		loadImage();
		return;
	}

	emit saved(m_image, postSaving());
}

QMap<QString, Image::SaveResult> ImageDownloader::postSaving(Image::SaveResult saveResult)
{
	m_image->setSavePath(m_temporaryPath);

	if (!m_filename.isEmpty())
	{ m_paths = m_image->path(m_filename, m_path, m_count, true, false, true, true, true); }

	QFile tmp(m_temporaryPath);
	bool moved = false;

	QMap<QString, Image::SaveResult> result;
	for (int i = 0; i < m_paths.count(); ++i)
	{
		const QString &path = m_paths[i];

		QFile f(path);
		if (f.exists())
		{
			result[path] = Image::SaveResult::AlreadyExists;
			continue;
		}

		if (!moved)
		{
			const QString dir = path.section(QDir::separator(), 0, -2);
			if (!QDir(dir).exists() && !QDir().mkpath(dir))
			{
				log(QStringLiteral("Impossible to create the destination folder: %1.").arg(dir), Logger::Error);
				result[path] = Image::SaveResult::Error;
				continue;
			}

			tmp.rename(path);
			moved = true;
		}
		else
		{ tmp.copy(path); }

		if (!result.contains(path))
		{ result[path] = saveResult; }

		m_image->postSave(path, result[path], m_addMd5, m_startCommands, m_count);
	}

	if (!moved)
	{ tmp.remove(); }

	return result;
}
<commit_msg>Don't re-log destination in imagedownloader for each redirect<commit_after>#include "downloader/image-downloader.h"
#include <QUuid>
#include "extension-rotator.h"
#include "file-downloader.h"
#include "functions.h"
#include "logger.h"
#include "models/filename.h"
#include "models/image.h"
#include "models/profile.h"
#include "models/site.h"
#include "models/source.h"

ImageDownloader::ImageDownloader(QSharedPointer<Image> img, QString filename, QString path, int count, bool addMd5, bool startCommands, QObject *parent, bool loadTags, bool rotate, bool force)
	: QObject(parent), m_image(std::move(img)), m_fileDownloader(false, this), m_filename(std::move(filename)), m_path(std::move(path)), m_loadTags(loadTags), m_count(count), m_addMd5(addMd5), m_startCommands(startCommands), m_writeError(false), m_rotate(rotate), m_force(force)
{}

ImageDownloader::ImageDownloader(QSharedPointer<Image> img, QStringList paths, int count, bool addMd5, bool startCommands, QObject *parent, bool rotate, bool force)
	: QObject(parent), m_image(std::move(img)), m_fileDownloader(false, this), m_loadTags(false), m_paths(std::move(paths)), m_count(count), m_addMd5(addMd5), m_startCommands(startCommands), m_writeError(false), m_rotate(rotate), m_force(force)
{}

ImageDownloader::~ImageDownloader()
{
	if (m_reply != nullptr)
		m_reply->deleteLater();
}

bool ImageDownloader::isRunning() const
{
	return m_reply != nullptr && m_reply->isRunning();
}

void ImageDownloader::save()
{
	// If we use direct saving or don't want to load tags, we directly save the image
	if (!m_loadTags || !m_paths.isEmpty() || Filename(m_filename).needExactTags(m_image->parentSite()) == 0)
	{
		loadedSave();
		return;
	}

	connect(m_image.data(), &Image::finishedLoadingTags, this, &ImageDownloader::loadedSave);
	m_image->loadDetails();
}

void ImageDownloader::abort()
{
	if (m_reply != nullptr && m_reply->isRunning())
		m_reply->abort();
}

void ImageDownloader::loadedSave()
{
	// Get the download path from the image if possible
	if (m_paths.isEmpty())
	{
		m_paths = m_image->path(m_filename, m_path, m_count, true, false, true, true, true);

		// Use a random temporary file if we need the MD5 or equivalent
		Profile *profile = m_image->parentSite()->getSource()->getProfile();
		if (Filename(m_filename).needTemporaryFile(m_image->tokens(profile)))
		{
			const QString tmpDir = !m_path.isEmpty() ? m_path : QDir::tempPath();
			m_temporaryPath = tmpDir + "/" + QUuid::createUuid().toString().mid(1, 36) + ".tmp";
		}
	}

	// Directly use the image path as temporary file  if possible
	if (m_temporaryPath.isEmpty())
	{ m_temporaryPath = m_paths.first() + ".tmp"; }

	// Try to save the image if it's already loaded or exists somewhere else on disk
	if (!m_force)
	{
		Image::SaveResult res = m_image->preSave(m_temporaryPath);

		// If we don't need any loading, we can return already
		if (res != Image::SaveResult::NotLoaded)
		{
			QMap<QString, Image::SaveResult> result {{ m_temporaryPath, res }};

			if (res == Image::SaveResult::Saved || res == Image::SaveResult::Copied || res == Image::SaveResult::Moved)
			{ result = postSaving(res); }

			emit saved(m_image, result);
			return;
		}
	}

	m_url = m_image->url(Image::Size::Full);
	log(QStringLiteral("Loading and saving image in %1").arg(m_paths.first()));
	loadImage();
}

void ImageDownloader::loadImage()
{
	connect(&m_fileDownloader, &FileDownloader::success, this, &ImageDownloader::success, Qt::UniqueConnection);
	connect(&m_fileDownloader, &FileDownloader::networkError, this, &ImageDownloader::networkError, Qt::UniqueConnection);
	connect(&m_fileDownloader, &FileDownloader::writeError, this, &ImageDownloader::writeError, Qt::UniqueConnection);

	// Delete previous replies for retries
	if (m_reply != nullptr)
	{ m_reply->deleteLater(); }

	// Load the image directly on the disk
	Site *site = m_image->parentSite();
	m_reply = site->get(site->fixUrl(m_url.toString()), m_image->page(), QStringLiteral("image"), m_image.data());
	m_reply->setParent(this);
	connect(m_reply, &QNetworkReply::downloadProgress, this, &ImageDownloader::downloadProgressImage);

	// Create download root directory
	const QString rootDir = m_temporaryPath.section(QDir::separator(), 0, -2);
	if (!QDir(rootDir).exists() && !QDir().mkpath(rootDir))
	{
		log(QStringLiteral("Impossible to create the destination folder: %1.").arg(rootDir), Logger::Error);
		emit saved(m_image, makeMap(m_paths, Image::SaveResult::Error));
		return;
	}

	// If we can't start writing for some reason, return an error
	if (!m_fileDownloader.start(m_reply, QStringList() << m_temporaryPath))
	{
		log(QStringLiteral("Unable to open file"), Logger::Error);
		emit saved(m_image, makeMap(m_paths, Image::SaveResult::Error));
		return;
	}
}

void ImageDownloader::downloadProgressImage(qint64 v1, qint64 v2)
{
	if (m_image->fileSize() == 0 || m_image->fileSize() < v2 / 2)
		m_image->setFileSize(v2);

	emit downloadProgress(m_image, v1, v2);
}

QMap<QString, Image::SaveResult> ImageDownloader::makeMap(const QStringList &keys, Image::SaveResult value)
{
	QMap<QString, Image::SaveResult> res;
	for (const QString &key : keys)
		res.insert(key, value);
	return res;
}

void ImageDownloader::writeError()
{
	emit saved(m_image, makeMap(m_paths, Image::SaveResult::Error));
}

void ImageDownloader::networkError(QNetworkReply::NetworkError error, const QString &msg)
{
	if (error == QNetworkReply::ContentNotFoundError)
	{
		QSettings *settings = m_image->parentSite()->getSource()->getProfile()->getSettings();
		ExtensionRotator *extensionRotator = m_image->extensionRotator();

		const bool sampleFallback = settings->value("Save/samplefallback", true).toBool();
		QString newext = extensionRotator != nullptr ? extensionRotator->next() : QString();

		const bool shouldFallback = sampleFallback && !m_image->url(Image::Size::Sample).isEmpty();
		const bool isLast = newext.isEmpty() || (shouldFallback && m_tryingSample);

		if (m_rotate && (!isLast || (shouldFallback && !m_tryingSample)))
		{
			if (isLast)
			{
				m_url = m_image->url(Image::Size::Sample);
				m_tryingSample = true;
				log(QStringLiteral("Image not found. New try with its sample..."));
			}
			else
			{
				m_url = setExtension(m_image->url(Image::Size::Full), newext);
				log(QStringLiteral("Image not found. New try with extension %1 (%2)...").arg(newext, m_url.toString()));
			}

			m_image->setUrl(m_url);
			loadImage();
		}
		else
		{
			log(QStringLiteral("Image not found."));
			emit saved(m_image, makeMap(m_paths, Image::SaveResult::NotFound));
		}
	}
	else if (error != QNetworkReply::OperationCanceledError)
	{
		log(QStringLiteral("Network error for the image: %1: %2 (%3)").arg(m_image->url().toString().toHtmlEscaped()).arg(error).arg(msg), Logger::Error);
		emit saved(m_image, makeMap(m_paths, Image::SaveResult::NetworkError));
	}
}

void ImageDownloader::success()
{
	// Handle network redirects
	QUrl redir = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
	if (!redir.isEmpty())
	{
		m_url = redir;
		loadImage();
		return;
	}

	emit saved(m_image, postSaving());
}

QMap<QString, Image::SaveResult> ImageDownloader::postSaving(Image::SaveResult saveResult)
{
	m_image->setSavePath(m_temporaryPath);

	if (!m_filename.isEmpty())
	{ m_paths = m_image->path(m_filename, m_path, m_count, true, false, true, true, true); }

	QFile tmp(m_temporaryPath);
	bool moved = false;

	QMap<QString, Image::SaveResult> result;
	for (int i = 0; i < m_paths.count(); ++i)
	{
		const QString &path = m_paths[i];

		QFile f(path);
		if (f.exists())
		{
			result[path] = Image::SaveResult::AlreadyExists;
			continue;
		}

		if (!moved)
		{
			const QString dir = path.section(QDir::separator(), 0, -2);
			if (!QDir(dir).exists() && !QDir().mkpath(dir))
			{
				log(QStringLiteral("Impossible to create the destination folder: %1.").arg(dir), Logger::Error);
				result[path] = Image::SaveResult::Error;
				continue;
			}

			tmp.rename(path);
			moved = true;
		}
		else
		{ tmp.copy(path); }

		if (!result.contains(path))
		{ result[path] = saveResult; }

		m_image->postSave(path, result[path], m_addMd5, m_startCommands, m_count);
	}

	if (!moved)
	{ tmp.remove(); }

	return result;
}
<|endoftext|>


<commit_before>/*
 * CommandGet.cpp
 *
 *  Created on: Feb 5, 2014
 *      Author: tim
 */
#include "boost/filesystem/operations.hpp"
#include <inttypes.h>
#include <sstream>
#include <fstream>
#include <string.h>

#include "CommandGet.h"
#include "../Settings.h"

namespace fs = boost::filesystem;

CommandGet::CommandGet(){
	file = "";
}

CommandGet::~CommandGet(){

}

void CommandGet::read(char* c){
	file = string(c);
}

bool CommandGet::execute(){
	string root = Settings::getInstance().getCwd();
	string filePath = string(root).append(file);

	// GET requested file does not exist.
	if(!fs::exists(filePath) || !fs::is_regular_file(filePath)) {
		sock->writeline("1");
		return true;
	}

	sock->writeline("0");

	int buffSize = 10240;
	long fzCounter = 0;  // counts if we reached the filesize
	ifstream filestream(filePath.c_str(), ios::binary);

	// get filesize
	ostringstream stream;
	long filesize = fs::file_size(filePath);

	if(filestream.is_open()) {
		char* defaultBuffer = new char[buffSize];

		ofstream ostr("/tmp/foto.png" , ios::binary);
		ostr.seekp(0);

		while(fzCounter != filesize) {

			if((filesize-fzCounter) >= buffSize) {
				filestream.read(defaultBuffer, sizeof(defaultBuffer));
				ostr << filestream.rdbuf();
				//sock->write(defaultBuffer);
				fzCounter += buffSize;
			}else{
				int remainder = filesize-fzCounter;

				// create small buffer
				char* smallBuff = new char[remainder];

				filestream.read(smallBuff, sizeof(smallBuff));
				ostr << filestream.rdbuf();
				//sock->write(smallBuff);
				fzCounter += remainder;

				ostr.close();
				delete [] smallBuff;
			}

			filestream.clear();
		}

		delete [] defaultBuffer;
		filestream.close();
		ostr.close();
		sock->writeline("0");

		return true;
	}else{
		filestream.close();
		sock->writeline("10");

		return true;
	}

}
<commit_msg>fstream fix<commit_after>/*
 * CommandGet.cpp
 *
 *  Created on: Feb 5, 2014
 *      Author: tim
 */
#include "boost/filesystem/operations.hpp"
#include <inttypes.h>
#include <sstream>
#include <fstream>
#include <string.h>

#include "CommandGet.h"
#include "../Settings.h"

namespace fs = boost::filesystem;

CommandGet::CommandGet(){
	file = "";
}

CommandGet::~CommandGet(){

}

void CommandGet::read(char* c){
	file = string(c);
}

bool CommandGet::execute(){
	string root = Settings::getInstance().getCwd();
	string filePath = string(root).append(file);

	// GET requested file does not exist.
	if(!fs::exists(filePath) || !fs::is_regular_file(filePath)) {
		sock->writeline("1");
		return true;
	}

	sock->writeline("0");

	int buffSize = 10240;
	long fzCounter = 0;  // counts if we reached the filesize
	ifstream filestream(filePath.c_str(), ios::binary);

	// create stream
	ostringstream stream;
	long filesize = fs::file_size(filePath);

	if(filestream.is_open()) {
		char* defaultBuffer = new char[buffSize];

		filestream.seekg(filestream.beg);

		while(fzCounter != filesize) {

			if((filesize-fzCounter) >= buffSize) {
				// Chunk is large enough, use default buffer
				filestream.read(defaultBuffer, buffSize);
				sock->write(defaultBuffer, buffSize);

				fzCounter += buffSize;
			}else{
				// Chunk is too small, create a tiny buffer
				int remainder = filesize-fzCounter;

				// create small buffer
				char* smallBuff = new char[remainder];

				filestream.read(smallBuff, remainder);
				sock->write(smallBuff, remainder);

				fzCounter += remainder;

				delete [] smallBuff;
			}

		}

		delete [] defaultBuffer;

		filestream.close();
		sock->writeline("0");

		return true;
	}else{
		filestream.close();
		sock->writeline("10");

		return true;
	}

}
<|endoftext|>


<commit_before>/* This file is part of the KDE project
   Copyright (C) 2004 Stephan Möres <Erdling@gmx.net>
   Copyright (C) 2008 Jakob Petsovits <jpetso@gmx.at>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "katesnippetswidget.h"
#include "katesnippetswidget.moc"

#include <ktexteditor/view.h>
#include <ktexteditor/document.h>

#include <klocale.h>

#include <q3listview.h>
#include <qregexp.h>
#include <qtoolbutton.h>
#include <q3textedit.h>

#include <QDate>
#include <QTime>

KateSnippetsWidget::KateSnippetsWidget( Kate::MainWindow *mainWindow, QWidget* parent, const char* name, Qt::WFlags fl)
    : KateSnippetsWidgetBase( parent, name, fl ), m_mainWin( mainWindow )
{
  connect(
    lvSnippets, SIGNAL( selectionChanged(Q3ListViewItem *) ),
    this, SLOT( slotSnippetSelectionChanged(Q3ListViewItem *) )
  );
  connect(
    lvSnippets, SIGNAL( doubleClicked(Q3ListViewItem *) ),
    this, SLOT( slotSnippetItemClicked(Q3ListViewItem  *) )
  );
  connect(
    lvSnippets, SIGNAL( itemRenamed(Q3ListViewItem *, int, const QString &) ),
    this, SLOT( slotSnippetItemRenamed(Q3ListViewItem *, int, const QString &) )
  );

  connect( btnNew,    SIGNAL( clicked() ), this, SLOT( slotNewClicked() ) );
  connect( btnSave,   SIGNAL( clicked() ), this, SLOT( slotSaveClicked() ) );
  connect( btnDelete, SIGNAL( clicked() ), this, SLOT( slotDeleteClicked() ) );
}

KateSnippetsWidget::~KateSnippetsWidget()
{
  // The snippets are only stored as pointers, so we need to clean up.
  foreach ( KateSnippet *snippet, m_snippets ) {
    delete snippet;
  }
}

/**
 * Read existing snippets from the given config, or create default ones
 * if no snippets exist yet.
 */
void KateSnippetsWidget::readConfig( KConfigBase* config, const QString& groupPrefix )
{
  QString key, value;
  Q3ListViewItem *lvi;

  KConfigGroup cg( config, groupPrefix );
  int snippetCount = cg.readEntry( "NumberOfSnippets", "0" ).toInt();

  for ( int i = 0; i < snippetCount; i++ )
  {
    QStringList fields;
    fields = cg.readEntry( QString::number(i), QStringList() );

    key   = fields[0];
    value = fields[1];

    lvi = insertItem( key, false );

    m_snippets.append( new KateSnippet(key, value, lvi) );
  }

  // <defaults>
  if ( snippetCount == 0 ) {
    key  = "DEBUG variable";
    value = "## < DEBUG >\nout \"
\\$ : \\\"$\\\"\\n
\"\n## </DEBUG >\n";
    lvi = insertItem( key, false );
    m_snippets.append( new KateSnippet(key, value, lvi) );

    key  = "proc-header";
    value  = "## [created : <date/>, <time/>]\n## Description:\n## ============\n## The function \"\" ...\n##\n##\n##\n##\n## Input:\n## ======\n##\n##\n##\nproc  {args} {\n\n  ## add your code here\n\n return \"\"\n}\n";
    lvi = insertItem( key, false );
    m_snippets.append( new KateSnippet(key, value, lvi) );
  }
  // </defaults>

  // set text of selected item at startup
  slotSnippetSelectionChanged( lvSnippets->selectedItem() );
}

/**
 * Store all snippets to the given config.
 */
void KateSnippetsWidget::writeConfig( KConfigBase* config, const QString& groupPrefix )
{
  KConfigGroup cg( config, groupPrefix );

  int snippetCount = m_snippets.count();
  cg.writeEntry( "NumberOfSnippets", snippetCount );

  int i = 0;

  Q_FOREACH ( KateSnippet *snippet, m_snippets ) {
    QStringList fields;
    fields.append( snippet->key() );
    fields.append( snippet->value() );

    cg.writeEntry( QString::number(i), fields );
    i++;
  }
  // sync to disc...
  config->sync();
}

KateSnippet* KateSnippetsWidget::findSnippetByListViewItem( Q3ListViewItem *item )
{
  Q_FOREACH ( KateSnippet *snippet, m_snippets ) {
    if ( snippet->listViewItem() == item ) {
      return snippet;
    }
  }
  return 0;
}

void KateSnippetsWidget::slotSnippetSelectionChanged( Q3ListViewItem  *item )
{
  KateSnippet *snippet;
  if ( (snippet = findSnippetByListViewItem(item)) != 0 ) {
    teSnippetText->setText( snippet->value() );
  }
}

void KateSnippetsWidget::slotSnippetItemClicked( Q3ListViewItem  *item )
{
  KTextEditor::View *kv = mainWindow()->activeView();
  KateSnippet *snippet;

  if ( kv ) {
    if ( (snippet = findSnippetByListViewItem(item)) != 0 ) {
      QString text = snippet->value();
      QString selection = "";

      if ( kv->selection() ) {
        selection = kv->selectionText();
        // clear selection
        kv->removeSelectionText();
      }

      // , <date/> and <time/> are special tokens and will be replaced.
      text.replace( "", selection );
      text.replace( "<date/>", QDate::currentDate().toString(Qt::LocalDate) );
      text.replace( "<time/>", QTime::currentTime().toString(Qt::LocalDate) );
      kv->document()->insertText( kv->cursorPosition(), text );
    }
    kv->setFocus();
  }
}

void KateSnippetsWidget::slotSnippetItemRenamed( Q3ListViewItem *lvi, int /*col*/, const QString& text )
{
  KateSnippet *snippet;
  if ( (snippet = findSnippetByListViewItem(lvi)) != 0 ) {
    snippet->setKey( text );
    emit saveRequested();
  }
}

void KateSnippetsWidget::slotNewClicked()
{
  QString key = i18n("New Snippet");
  QString value = "";

  Q3ListViewItem *lvi = insertItem( key, true );
  m_snippets.append( new KateSnippet(key, value, lvi) );
}

void KateSnippetsWidget::slotSaveClicked()
{
  KateSnippet *snippet;
  Q3ListViewItem *lvi = lvSnippets->selectedItem();
  if ( (snippet = findSnippetByListViewItem(lvi)) != 0 ) {
    snippet->setValue( teSnippetText->text() );
    emit saveRequested();
  }
}

void KateSnippetsWidget::slotDeleteClicked()
{
  KateSnippet *snippet;
  Q3ListViewItem *lvi = lvSnippets->selectedItem();

  if ( (snippet = findSnippetByListViewItem(lvi)) != 0 ) {
    lvSnippets->takeItem( lvi );
    m_snippets.remove( snippet );
    delete snippet;
  }
}

// kate: space-indent on; indent-width 2; replace-tabs on;
<commit_msg>add template interface support for easier debugging of the template code. This plugin isn't built by default anyways<commit_after>/* This file is part of the KDE project
   Copyright (C) 2004 Stephan Möres <Erdling@gmx.net>
   Copyright (C) 2008 Jakob Petsovits <jpetso@gmx.at>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "katesnippetswidget.h"
#include "katesnippetswidget.moc"

#include <ktexteditor/view.h>
#include <ktexteditor/document.h>
#include <ktexteditor/templateinterface.h>

#include <klocale.h>

#include <q3listview.h>
#include <qregexp.h>
#include <qtoolbutton.h>
#include <q3textedit.h>

#include <QDate>
#include <QTime>

KateSnippetsWidget::KateSnippetsWidget( Kate::MainWindow *mainWindow, QWidget* parent, const char* name, Qt::WFlags fl)
    : KateSnippetsWidgetBase( parent, name, fl ), m_mainWin( mainWindow )
{
  connect(
    lvSnippets, SIGNAL( selectionChanged(Q3ListViewItem *) ),
    this, SLOT( slotSnippetSelectionChanged(Q3ListViewItem *) )
  );
  connect(
    lvSnippets, SIGNAL( doubleClicked(Q3ListViewItem *) ),
    this, SLOT( slotSnippetItemClicked(Q3ListViewItem  *) )
  );
  connect(
    lvSnippets, SIGNAL( itemRenamed(Q3ListViewItem *, int, const QString &) ),
    this, SLOT( slotSnippetItemRenamed(Q3ListViewItem *, int, const QString &) )
  );

  connect( btnNew,    SIGNAL( clicked() ), this, SLOT( slotNewClicked() ) );
  connect( btnSave,   SIGNAL( clicked() ), this, SLOT( slotSaveClicked() ) );
  connect( btnDelete, SIGNAL( clicked() ), this, SLOT( slotDeleteClicked() ) );
}

KateSnippetsWidget::~KateSnippetsWidget()
{
  // The snippets are only stored as pointers, so we need to clean up.
  foreach ( KateSnippet *snippet, m_snippets ) {
    delete snippet;
  }
}

/**
 * Read existing snippets from the given config, or create default ones
 * if no snippets exist yet.
 */
void KateSnippetsWidget::readConfig( KConfigBase* config, const QString& groupPrefix )
{
  QString key, value;
  Q3ListViewItem *lvi;

  KConfigGroup cg( config, groupPrefix );
  int snippetCount = cg.readEntry( "NumberOfSnippets", "0" ).toInt();

  for ( int i = 0; i < snippetCount; i++ )
  {
    QStringList fields;
    fields = cg.readEntry( QString::number(i), QStringList() );

    key   = fields[0];
    value = fields[1];

    lvi = insertItem( key, false );

    m_snippets.append( new KateSnippet(key, value, lvi) );
  }

  // <defaults>
  if ( snippetCount == 0 ) {
    key  = "DEBUG variable";
    value = "## < DEBUG >\nout \"
\\$ : \\\"$\\\"\\n
\"\n## </DEBUG >\n";
    lvi = insertItem( key, false );
    m_snippets.append( new KateSnippet(key, value, lvi) );

    key  = "proc-header";
    value  = "## [created : <date/>, <time/>]\n## Description:\n## ============\n## The function \"\" ...\n##\n##\n##\n##\n## Input:\n## ======\n##\n##\n##\nproc  {args} {\n\n  ## add your code here\n\n return \"\"\n}\n";
    lvi = insertItem( key, false );
    m_snippets.append( new KateSnippet(key, value, lvi) );
  }
  // </defaults>

  // set text of selected item at startup
  slotSnippetSelectionChanged( lvSnippets->selectedItem() );
}

/**
 * Store all snippets to the given config.
 */
void KateSnippetsWidget::writeConfig( KConfigBase* config, const QString& groupPrefix )
{
  KConfigGroup cg( config, groupPrefix );

  int snippetCount = m_snippets.count();
  cg.writeEntry( "NumberOfSnippets", snippetCount );

  int i = 0;

  Q_FOREACH ( KateSnippet *snippet, m_snippets ) {
    QStringList fields;
    fields.append( snippet->key() );
    fields.append( snippet->value() );

    cg.writeEntry( QString::number(i), fields );
    i++;
  }
  // sync to disc...
  config->sync();
}

KateSnippet* KateSnippetsWidget::findSnippetByListViewItem( Q3ListViewItem *item )
{
  Q_FOREACH ( KateSnippet *snippet, m_snippets ) {
    if ( snippet->listViewItem() == item ) {
      return snippet;
    }
  }
  return 0;
}

void KateSnippetsWidget::slotSnippetSelectionChanged( Q3ListViewItem  *item )
{
  KateSnippet *snippet;
  if ( (snippet = findSnippetByListViewItem(item)) != 0 ) {
    teSnippetText->setText( snippet->value() );
  }
}

void KateSnippetsWidget::slotSnippetItemClicked( Q3ListViewItem  *item )
{
  KTextEditor::View *kv = mainWindow()->activeView();
  KateSnippet *snippet;

  if ( kv ) {
    if ( (snippet = findSnippetByListViewItem(item)) != 0 ) {
      QString text = snippet->value();
      QString selection = "";

      if ( kv->selection() ) {
        selection = kv->selectionText();
        // clear selection
        kv->removeSelectionText();
      }

      // , <date/> and <time/> are special tokens and will be replaced.
      text.replace( "", selection );
      text.replace( "<date/>", QDate::currentDate().toString(Qt::LocalDate) );
      text.replace( "<time/>", QTime::currentTime().toString(Qt::LocalDate) );
      KTextEditor::TemplateInterface *ti=qobject_cast<KTextEditor::TemplateInterface*>(kv->document()->activeView());
      if (ti) ti->insertTemplateText(kv->cursorPosition(), text,QMap<QString,QString>() );
    }
    kv->setFocus();
  }
}

void KateSnippetsWidget::slotSnippetItemRenamed( Q3ListViewItem *lvi, int /*col*/, const QString& text )
{
  KateSnippet *snippet;
  if ( (snippet = findSnippetByListViewItem(lvi)) != 0 ) {
    snippet->setKey( text );
    emit saveRequested();
  }
}

void KateSnippetsWidget::slotNewClicked()
{
  QString key = i18n("New Snippet");
  QString value = "";

  Q3ListViewItem *lvi = insertItem( key, true );
  m_snippets.append( new KateSnippet(key, value, lvi) );
}

void KateSnippetsWidget::slotSaveClicked()
{
  KateSnippet *snippet;
  Q3ListViewItem *lvi = lvSnippets->selectedItem();
  if ( (snippet = findSnippetByListViewItem(lvi)) != 0 ) {
    snippet->setValue( teSnippetText->text() );
    emit saveRequested();
  }
}

void KateSnippetsWidget::slotDeleteClicked()
{
  KateSnippet *snippet;
  Q3ListViewItem *lvi = lvSnippets->selectedItem();

  if ( (snippet = findSnippetByListViewItem(lvi)) != 0 ) {
    lvSnippets->takeItem( lvi );
    m_snippets.remove( snippet );
    delete snippet;
  }
}

// kate: space-indent on; indent-width 2; replace-tabs on;
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2015 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#include <Eigen/CXX11/Tensor>

using Eigen::internal::TensorUInt128;
using Eigen::internal::static_val;

static void VERIFY_EQUAL(TensorUInt128<uint64_t, uint64_t> actual, __uint128_t expected) {
  bool matchl = actual.lower() == static_cast<uint64_t>(expected);
  bool matchh = actual.upper() == static_cast<uint64_t>(expected >> 64);
  if (!matchl || !matchh) {
    const char* testname = g_test_stack.back().c_str();
    std::cerr << "Test " << testname << " failed in " << __FILE__
              << " (" << __LINE__ << ")"
              << std::endl;
    abort();
  }
}

static void test_add() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i + j;
          __uint128_t expected = a + b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

static void test_sub() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i - j;
          __uint128_t expected = a - b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

static void test_mul() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i * j;
          __uint128_t expected = a * b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

static void test_div() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i / j;
          __uint128_t expected = a / b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

static void test_misc1() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
    TensorUInt128<static_val<0>, uint64_t> i(0, i2);
    __uint128_t a = static_cast<__uint128_t>(i2);
    for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
      TensorUInt128<static_val<0>, uint64_t> j(0, j2);
      __uint128_t b = static_cast<__uint128_t>(j2);
      uint64_t actual = (i * j).upper();
      uint64_t expected = (a * b) >> 64;
      VERIFY_IS_EQUAL(actual, expected);
    }
  }
}

static void test_misc2() {
  int64_t incr = internal::random<int64_t>(1, 100);
  for (int64_t log_div = 0; log_div < 63; ++log_div) {
    for (int64_t divider = 1; divider <= 1000000 * incr; divider += incr) {
      uint64_t expected = (static_cast<__uint128_t>(1) << (64+log_div)) / static_cast<__uint128_t>(divider) - (static_cast<__uint128_t>(1) << 64) + 1;
      uint64_t shift = 1ULL << log_div;

      TensorUInt128<uint64_t, uint64_t> result = (TensorUInt128<uint64_t, static_val<0> >(shift, 0) / TensorUInt128<static_val<0>, uint64_t>(divider) - TensorUInt128<static_val<1>, static_val<0> >(1, 0) + TensorUInt128<static_val<0>, static_val<1> >(1));
      uint64_t actual = static_cast<uint64_t>(result);
      VERIFY_EQUAL(actual, expected);
    }
  }
}

void test_cxx11_tensor_uint128()
{
  CALL_SUBTEST_1(test_add());
  CALL_SUBTEST_2(test_sub());
  CALL_SUBTEST_3(test_mul());
  CALL_SUBTEST_4(test_div());
  CALL_SUBTEST_5(test_misc1());
  CALL_SUBTEST_6(test_misc2());
}
<commit_msg>Fixed compilation warning generated by clang<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2015 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#include <Eigen/CXX11/Tensor>

using Eigen::internal::TensorUInt128;
using Eigen::internal::static_val;

void VERIFY_EQUAL(TensorUInt128<uint64_t, uint64_t> actual, __uint128_t expected) {
  bool matchl = actual.lower() == static_cast<uint64_t>(expected);
  bool matchh = actual.upper() == static_cast<uint64_t>(expected >> 64);
  if (!matchl || !matchh) {
    const char* testname = g_test_stack.back().c_str();
    std::cerr << "Test " << testname << " failed in " << __FILE__
              << " (" << __LINE__ << ")"
              << std::endl;
    abort();
  }
}

void test_add() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i + j;
          __uint128_t expected = a + b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

void test_sub() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i - j;
          __uint128_t expected = a - b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

void test_mul() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i * j;
          __uint128_t expected = a * b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

void test_div() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i1 = 0; i1 < 100; ++i1) {
    for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
      TensorUInt128<uint64_t, uint64_t> i(i1, i2);
      __uint128_t a = (static_cast<__uint128_t>(i1) << 64) + static_cast<__uint128_t>(i2);
      for (uint64_t j1 = 0; j1 < 100; ++j1) {
        for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
          TensorUInt128<uint64_t, uint64_t> j(j1, j2);
          __uint128_t b = (static_cast<__uint128_t>(j1) << 64) + static_cast<__uint128_t>(j2);
          TensorUInt128<uint64_t, uint64_t> actual = i / j;
          __uint128_t expected = a / b;
          VERIFY_EQUAL(actual, expected);
        }
      }
    }
  }
}

void test_misc1() {
  uint64_t incr = internal::random<uint64_t>(1, 9999999999);
  for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) {
    TensorUInt128<static_val<0>, uint64_t> i(0, i2);
    __uint128_t a = static_cast<__uint128_t>(i2);
    for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) {
      TensorUInt128<static_val<0>, uint64_t> j(0, j2);
      __uint128_t b = static_cast<__uint128_t>(j2);
      uint64_t actual = (i * j).upper();
      uint64_t expected = (a * b) >> 64;
      VERIFY_IS_EQUAL(actual, expected);
    }
  }
}

void test_misc2() {
  int64_t incr = internal::random<int64_t>(1, 100);
  for (int64_t log_div = 0; log_div < 63; ++log_div) {
    for (int64_t divider = 1; divider <= 1000000 * incr; divider += incr) {
      uint64_t expected = (static_cast<__uint128_t>(1) << (64+log_div)) / static_cast<__uint128_t>(divider) - (static_cast<__uint128_t>(1) << 64) + 1;
      uint64_t shift = 1ULL << log_div;

      TensorUInt128<uint64_t, uint64_t> result = (TensorUInt128<uint64_t, static_val<0> >(shift, 0) / TensorUInt128<static_val<0>, uint64_t>(divider) - TensorUInt128<static_val<1>, static_val<0> >(1, 0) + TensorUInt128<static_val<0>, static_val<1> >(1));
      uint64_t actual = static_cast<uint64_t>(result);
      VERIFY_EQUAL(actual, expected);
    }
  }
}

void test_cxx11_tensor_uint128()
{
  CALL_SUBTEST_1(test_add());
  CALL_SUBTEST_2(test_sub());
  CALL_SUBTEST_3(test_mul());
  CALL_SUBTEST_4(test_div());
  CALL_SUBTEST_5(test_misc1());
  CALL_SUBTEST_6(test_misc2());
}
<|endoftext|>


<commit_before>#include "output.h"

void writePackageNameAndImports(const QString &filePath, const QString &packageName, const QList<Import> &imports) throw(const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for package name and import`s list output");
    }

    QXmlStreamWriter xmlWriter;
    xmlWriter.setDevice(&file);
    xmlWriter.setAutoFormatting(true);

    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("program");

    if (!packageName.isEmpty())
    {
        xmlWriter.writeStartElement("package");
        xmlWriter.writeAttribute("name", packageName);
        xmlWriter.writeEndElement();
    }

    if (!imports.isEmpty())
    {
        xmlWriter.writeStartElement("imports");
        for (auto import : imports)
        {
            xmlWriter.writeStartElement("import");
            xmlWriter.writeAttribute("name", import.importedClass);
            xmlWriter.writeEndElement();
        }
        xmlWriter.writeEndElement();
    }

    xmlWriter.writeEndElement();
    xmlWriter.writeEndDocument();
}

void writeEnums(const QString &filePath, const QList<Enum> &enums) throw (const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for enums output");
    }

    QTextStream out(&file);

    for (auto enumToOut : enums)
    {
        out << enumToOut.text << endl << endl;
    }
}

void writeMethods(const QString &filePath, const QList<Method> &methods) throw (const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for methods output");
    }

    QTextStream out(&file);

    for (auto method : methods)
    {
        out << method.text << endl << endl;
    }
}

void writeFields(const QString &filePath, const QList<Field> &fields) throw(const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for fields output");
    }

    QTextStream out(&file);

    for (auto field : fields)
    {
        out << field.text << endl;
    }
}

void writeInterface(const QString &filePath, const Interface &interfaceToWrite) throw(const QString &)
{
    QFile file(filePath + interfaceToWrite.name + ".xml");

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for interface output");
    }

    QXmlStreamWriter xmlWriter;
    xmlWriter.setDevice(&file);
    xmlWriter.setAutoFormatting(true);

    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("interface");
    xmlWriter.writeAttribute("name", interfaceToWrite.name);

    if (!interfaceToWrite.modificators.isEmpty())
    {
        xmlWriter.writeAttribute("modificators", interfaceToWrite.modificators.join(' '));
    }

    if (!interfaceToWrite.baseInterfaces.isEmpty())
    {
        xmlWriter.writeAttribute("baseInterfaces", interfaceToWrite.baseInterfaces.join(' '));
    }

    xmlWriter.writeEndElement();
    xmlWriter.writeEndDocument();

    if (!interfaceToWrite.fields.isEmpty())
    {
        writeFields(filePath + "fields.txt", interfaceToWrite.fields);
    }

    if (!interfaceToWrite.methods.isEmpty())
    {
        writeMethods(filePath + "methods.txt", interfaceToWrite.methods);
    }
}

void writeInterfaces(QDir &outputDir, const QList<Interface> &interfaces, const QString &folderName) throw(const QString &)
{
    if (!outputDir.mkdir("Interfaces"))
    {
        throw QString("Cannot create folder Interfaces");
    }

    outputDir.cd("Interfaces");

    for (auto interface : interfaces)
    {
        if (!outputDir.mkdir(interface.name))
        {
            throw QString("Cannot create folder for interface with name: " + interface.name);
        }

        writeInterface(folderName + "/Interfaces/" + interface.name + "/", interface);
    }

    outputDir.cd("..");
}

void writeClass(const QString &filePath, const Class &classToWrite) throw(const QString &)
{
    QFile file(filePath + classToWrite.name + ".xml");

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for class output");
    }

    QXmlStreamWriter xmlWriter;
    xmlWriter.setDevice(&file);
    xmlWriter.setAutoFormatting(true);

    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("class");
    xmlWriter.writeAttribute("name", classToWrite.name);

    if (!classToWrite.modificators.isEmpty())
    {
        xmlWriter.writeAttribute("modificators", classToWrite.modificators.join(' '));
    }

    if (!classToWrite.baseClasses.isEmpty())
    {
        xmlWriter.writeAttribute("baseClasses", classToWrite.baseClasses.join(' '));
    }

    if (!classToWrite.implementedInterfaces.isEmpty())
    {
        xmlWriter.writeAttribute("implementedInterfaces", classToWrite.implementedInterfaces.join(' '));
    }

    xmlWriter.writeEndElement();
    xmlWriter.writeEndDocument();

    if (!classToWrite.enums.isEmpty())
    {
        writeEnums(filePath + "enums.txt", classToWrite.enums);
    }

    if (!classToWrite.fields.isEmpty())
    {
        writeFields(filePath + "fields.txt", classToWrite.fields);
    }

    if (!classToWrite.methods.isEmpty())
    {
        writeMethods(filePath + "methods.txt", classToWrite.methods);
    }

    if (!classToWrite.nestedInterfaces.isEmpty())
    {
        writeInterfaces(QDir(filePath), classToWrite.nestedInterfaces, filePath);
    }

    if (!classToWrite.nestedClasses.isEmpty())
    {
        writeClasses(QDir(filePath), classToWrite.nestedClasses, filePath);
    }
}

void writeClasses(QDir outputDir, const QList<Class> &classes, const QString &folderName) throw(const QString &)
{
    if (!outputDir.mkdir("Classes"))
    {
        throw QString("Cannot create folder Classes");
    }

    outputDir.cd("Classes");

    for (auto classToWrite : classes)
    {
        if (!outputDir.mkdir(classToWrite.name))
        {
            throw QString("Cannot create folder for class with name: " + classToWrite.name);
        }

        writeClass("./" + folderName + "/Classes/" + classToWrite.name + "/", classToWrite);
    }

    outputDir.cd("..");
}

void writeTreeToFiles(const QString &folderName, const Program &program) throw(const QString &)
{
    QDir outputDir;

    if (folderName.isEmpty())
    {
        throw QString("Folder name cannot be empty");
    }

    if (!outputDir.exists(folderName) && !outputDir.mkdir(folderName))
    {
        throw QString("Cannot create folder for output files");
    }

    if (!program.package.packageName.isEmpty() || !program.imports.isEmpty())
    {
        writePackageNameAndImports("./" + folderName + "/packageNameAndImports.xml", program.package.packageName, program.imports);
    }

    if (!program.enums.isEmpty())
    {
        writeEnums("./" + folderName + "/enums.txt", program.enums);
    }

    outputDir.cd(folderName);

    if (!program.interfaces.isEmpty())
    {
        writeInterfaces(outputDir, program.interfaces, folderName);
    }

    if (!program.classes.isEmpty())
    {
        writeClasses(outputDir, program.classes, folderName);
    }
}<commit_msg>Добавил удаление выходной папки, если она уже существует<commit_after>#include "output.h"

void writePackageNameAndImports(const QString &filePath, const QString &packageName, const QList<Import> &imports) throw(const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for package name and import`s list output");
    }

    QXmlStreamWriter xmlWriter;
    xmlWriter.setDevice(&file);
    xmlWriter.setAutoFormatting(true);

    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("program");

    if (!packageName.isEmpty())
    {
        xmlWriter.writeStartElement("package");
        xmlWriter.writeAttribute("name", packageName);
        xmlWriter.writeEndElement();
    }

    if (!imports.isEmpty())
    {
        xmlWriter.writeStartElement("imports");
        for (auto import : imports)
        {
            xmlWriter.writeStartElement("import");
            xmlWriter.writeAttribute("name", import.importedClass);
            xmlWriter.writeEndElement();
        }
        xmlWriter.writeEndElement();
    }

    xmlWriter.writeEndElement();
    xmlWriter.writeEndDocument();
}

void writeEnums(const QString &filePath, const QList<Enum> &enums) throw (const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for enums output");
    }

    QTextStream out(&file);

    for (auto enumToOut : enums)
    {
        out << enumToOut.text << endl << endl;
    }
}

void writeMethods(const QString &filePath, const QList<Method> &methods) throw (const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for methods output");
    }

    QTextStream out(&file);

    for (auto method : methods)
    {
        out << method.text << endl << endl;
    }
}

void writeFields(const QString &filePath, const QList<Field> &fields) throw(const QString &)
{
    QFile file(filePath);

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for fields output");
    }

    QTextStream out(&file);

    for (auto field : fields)
    {
        out << field.text << endl;
    }
}

void writeInterface(const QString &filePath, const Interface &interfaceToWrite) throw(const QString &)
{
    QFile file(filePath + interfaceToWrite.name + ".xml");

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for interface output");
    }

    QXmlStreamWriter xmlWriter;
    xmlWriter.setDevice(&file);
    xmlWriter.setAutoFormatting(true);

    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("interface");
    xmlWriter.writeAttribute("name", interfaceToWrite.name);

    if (!interfaceToWrite.modificators.isEmpty())
    {
        xmlWriter.writeAttribute("modificators", interfaceToWrite.modificators.join(' '));
    }

    if (!interfaceToWrite.baseInterfaces.isEmpty())
    {
        xmlWriter.writeAttribute("baseInterfaces", interfaceToWrite.baseInterfaces.join(' '));
    }

    xmlWriter.writeEndElement();
    xmlWriter.writeEndDocument();

    if (!interfaceToWrite.fields.isEmpty())
    {
        writeFields(filePath + "fields.txt", interfaceToWrite.fields);
    }

    if (!interfaceToWrite.methods.isEmpty())
    {
        writeMethods(filePath + "methods.txt", interfaceToWrite.methods);
    }
}

void writeInterfaces(QDir &outputDir, const QList<Interface> &interfaces, const QString &folderName) throw(const QString &)
{
    if (!outputDir.mkdir("Interfaces"))
    {
        throw QString("Cannot create folder Interfaces");
    }

    outputDir.cd("Interfaces");

    for (auto interface : interfaces)
    {
        if (!outputDir.mkdir(interface.name))
        {
            throw QString("Cannot create folder for interface with name: " + interface.name);
        }

        writeInterface(folderName + "/Interfaces/" + interface.name + "/", interface);
    }

    outputDir.cd("..");
}

void writeClass(const QString &filePath, const Class &classToWrite) throw(const QString &)
{
    QFile file(filePath + classToWrite.name + ".xml");

    if (!file.open(QIODevice::WriteOnly))
    {
        throw QString("Cannot create file for class output");
    }

    QXmlStreamWriter xmlWriter;
    xmlWriter.setDevice(&file);
    xmlWriter.setAutoFormatting(true);

    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("class");
    xmlWriter.writeAttribute("name", classToWrite.name);

    if (!classToWrite.modificators.isEmpty())
    {
        xmlWriter.writeAttribute("modificators", classToWrite.modificators.join(' '));
    }

    if (!classToWrite.baseClasses.isEmpty())
    {
        xmlWriter.writeAttribute("baseClasses", classToWrite.baseClasses.join(' '));
    }

    if (!classToWrite.implementedInterfaces.isEmpty())
    {
        xmlWriter.writeAttribute("implementedInterfaces", classToWrite.implementedInterfaces.join(' '));
    }

    xmlWriter.writeEndElement();
    xmlWriter.writeEndDocument();

    if (!classToWrite.enums.isEmpty())
    {
        writeEnums(filePath + "enums.txt", classToWrite.enums);
    }

    if (!classToWrite.fields.isEmpty())
    {
        writeFields(filePath + "fields.txt", classToWrite.fields);
    }

    if (!classToWrite.methods.isEmpty())
    {
        writeMethods(filePath + "methods.txt", classToWrite.methods);
    }

    if (!classToWrite.nestedInterfaces.isEmpty())
    {
        writeInterfaces(QDir(filePath), classToWrite.nestedInterfaces, filePath);
    }

    if (!classToWrite.nestedClasses.isEmpty())
    {
        writeClasses(QDir(filePath), classToWrite.nestedClasses, filePath);
    }
}

void writeClasses(QDir outputDir, const QList<Class> &classes, const QString &folderName) throw(const QString &)
{
    if (!outputDir.mkdir("Classes"))
    {
        throw QString("Cannot create folder Classes");
    }

    outputDir.cd("Classes");

    for (auto classToWrite : classes)
    {
        if (!outputDir.mkdir(classToWrite.name))
        {
            throw QString("Cannot create folder for class with name: " + classToWrite.name);
        }

        writeClass("./" + folderName + "/Classes/" + classToWrite.name + "/", classToWrite);
    }

    outputDir.cd("..");
}

void writeTreeToFiles(const QString &folderName, const Program &program) throw(const QString &)
{
    QDir outputDir;

    if (folderName.isEmpty())
    {
        throw QString("Folder name cannot be empty");
    }

    if (outputDir.exists(folderName))
    {
        QDir dirToDelete(folderName);
        dirToDelete.removeRecursively();
    }

    if (!outputDir.mkdir(folderName))
    {
        throw QString("Cannot create folder for output files");
    }

    if (!program.package.packageName.isEmpty() || !program.imports.isEmpty())
    {
        writePackageNameAndImports("./" + folderName + "/packageNameAndImports.xml", program.package.packageName, program.imports);
    }

    if (!program.enums.isEmpty())
    {
        writeEnums("./" + folderName + "/enums.txt", program.enums);
    }

    outputDir.cd(folderName);

    if (!program.interfaces.isEmpty())
    {
        writeInterfaces(outputDir, program.interfaces, folderName);
    }

    if (!program.classes.isEmpty())
    {
        writeClasses(outputDir, program.classes, folderName);
    }
}<|endoftext|>


<commit_before>#include <iterator>
#include <vector>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <algorithm>
#include <sstream>
#include <map>
#include <ut/throwf.hxx>

#include "utility.hxx"
#include "command.hxx"
#include "grammar.hxx"
#include "parser_action.hxx"
#include "parser_state.hxx"

using namespace std::literals;

namespace cl
{
	namespace internal
	{
		void command_base::check_required() const
		{
			// Check if there ary any arguments that are required but not supplied
			for (auto& arg : m_ArgMap)
			{
				auto& ptr = arg.second;

				if (ptr->required() && !ptr->supplied())
				{
					ut::throwf<std::runtime_error>(
						"Required argument \"--%s\" was not supplied!",
						ptr->long_name()
					);
				}
			}
		}

		void command_base::add(argument_ptr p_ptr)
		{
			if(m_ArgMap.count(p_ptr->long_name()) != 0)
			{
				ut::throwf<::std::runtime_error>(
					"Tried to register multiple arguments with identical long name"
					" \"--%s\"",
					p_ptr->long_name()
				);
			}

			if (p_ptr->has_id())
				m_IdMap[p_ptr->id()] = ut::make_observer<internal::argument_base>(p_ptr.get());

			// Add argument and hand over ownership
			m_ArgMap[p_ptr->long_name()] = ::std::move(p_ptr);
		}

		auto command_base::get(const ::std::string& p_str) const
			-> const_argument_view
		{
			// Lookup by long name
			const auto t_it = m_ArgMap.find(p_str);

			if(t_it != m_ArgMap.end())
			{
				return ut::make_observer<const internal::argument_base>(t_it->second.get());
			}
			else
			{
				ut::throwf<::std::runtime_error>(
					"Unknown commandline argument:"
					" \"--%s\"",
					p_str
				);
			}
		}

		auto command_base::get(char p_chr) const
			-> const_argument_view
		{
			// Lookup by short name
			const auto t_it = ::std::find_if(m_ArgMap.cbegin(), m_ArgMap.cend(),
				[p_chr](const auto& p_pair) -> bool
				{
					return p_pair.second->short_name() == p_chr;
				}
			);

			if(t_it != m_ArgMap.cend())
			{
				return ut::make_observer<const internal::argument_base>(t_it->second.get());
			}
			else
			{
				ut::throwf<::std::runtime_error>(
					"Unknown commandline argument:"
					" \"-%c\"",
					p_chr
				);
			}
		}

		auto command_base::get(::std::size_t p_id) const
			-> const_argument_view
		{
			// Lookup by id
			const auto t_it = m_IdMap.find(p_id);

			if(t_it != m_IdMap.cend())
			{
				return ut::make_observer<const internal::argument_base>(t_it->second.get());
			}
			else
			{
				ut::throwf<::std::runtime_error>(
					"Unknown commandline argument id:"
					" \"%u\"",
					p_id
				);
			}
		}

		auto command_base::get(const ::std::string& p_str)
			-> argument_view
		{
			const auto t_view = const_cast<const this_type*>(this)->get(p_str);

			return ut::make_observer<internal::argument_base>(
				const_cast<internal::argument_base*>(t_view.get())
			);
		}

		auto command_base::get(char p_short)
			-> argument_view
		{
			const auto t_view = const_cast<const this_type*>(this)->get(p_short);

			return ut::make_observer<internal::argument_base>(
				const_cast<internal::argument_base*>(t_view.get())
			);
		}

		auto command_base::get(::std::size_t p_id)
			-> argument_view
		{
			const auto t_view = const_cast<const this_type*>(this)->get(p_id);

			return ut::make_observer<internal::argument_base>(
				const_cast<internal::argument_base*>(t_view.get())
			);
		}

		auto command_base::has(const ::std::string& p_long) const
			-> bool
		{
			return m_ArgMap.count(p_long) != 0;
		}

		auto command_base::has(::std::size_t p_id) const
			-> bool
		{
			return m_IdMap.count(p_id) != 0;
		}

		auto command_base::has(char p_short) const
			-> bool
		{
			const auto t_it = ::std::find_if(m_ArgMap.begin(), m_ArgMap.end(),
				[p_short](const auto& p_pair) -> bool
				{
					return p_pair.second->short_name() == p_short;
				}
			);

			return t_it != m_ArgMap.end();
		}

		auto command_base::supplied(const ::std::string& p_long) const
			-> bool
		{
			return get(p_long)->supplied();
		}

		auto command_base::supplied(char p_short) const
			-> bool
		{
			return get(p_short)->supplied();
		}

		auto command_base::supplied(::std::size_t p_id) const
			-> bool
		{
			return get(p_id)->supplied();
		}

		auto command_base::read(input_type p_cl)
			-> void
		{
			::std::ostringstream ss{};

			for (const char* t_entry: p_cl)
			{
				ss << std::quoted(t_entry) << ' ';
			}

			internal::parser_state state{};

			pegtl::parse<internal::R_Commandline, internal::parser_action>(ss.str(), "", *this, state);

			// Call read_end on all arguments to refresh references etc
			for (auto& arg : m_ArgMap)
				arg.second->read_end();

			// Perform after-read tasks and checks
			check_required();
		}

		auto command_base::local_data() const
			-> const command_data&
		{
			return m_LocalData;
		}

		auto command_base::local_data()
			-> command_data&
		{
			return m_LocalData;
		}

		auto command_base::global_data() const
			-> const handler_data&
		{
			if(m_GlobalDataPtr)
				return *m_GlobalDataPtr;
			else throw ::std::runtime_error("Tried to access null global data ptr!");
		}

		auto command_base::set_global_data(global_data_ptr p_ptr)
			-> void
		{
			m_GlobalDataPtr = p_ptr;
		}

		auto command_base::print_help() const
			-> void
		{
			if(global_data().m_HelpMode != internal::help_mode_::show_none)
			{
				// Print usage first
				if(global_data().m_HelpMode & internal::help_mode_::show_usage)
					print_usage();

				if(global_data().m_HelpMode & internal::help_mode_::show_summary)
					print_summary();
			}
		}

		auto command_base::print_usage() const
			-> void
		{
			if(!m_LocalData.m_Usage.empty())
				std::cout << m_LocalData.m_Usage << std::endl;
		}

		auto command_base::print_summary() const
			-> void
		{
			// Retrieve arguments sorted by category
			const auto t_categories = sort_arguments();

			// Handle "general" category first
			const auto t_it = t_categories.find("General"s);

			if(t_it != t_categories.end())
				print_category("General"s, t_it->second);

			// Handle rest
			for(const auto& t_kvp: t_categories)
			{
				if(t_kvp.first != "General")
					print_category(t_kvp.first, t_kvp.second);
			}
		}

		auto command_base::print_category(const ::std::string& p_name, const ::std::vector<argument_view>& p_cat) const
			-> void
		{
			::std::cout << p_name << ":" << ::std::endl;

			::std::ostringstream t_ss{ };

			// Character used to fill empty space
			const auto t_fillChar = (global_data().m_SummaryStyle == summary_style_::dots ? '.' : ' ');

			constexpr const auto t_LengthArgumentSpace = 22U;
			constexpr const auto t_DescriptionLineLength = 47U;

			for(const auto& t_entry: p_cat)
			{
				// Ensure string stream is empty
				t_ss.str(""s);

				// Build string containing long and (possibly) short name
				t_ss << '[';

				if(t_entry->has_short_name())
					t_ss << '-' << t_entry->short_name() << ", ";

				t_ss << "--" << t_entry->long_name() << "] ";
				//

				if(t_entry->has_description())
				{
					// -1 because the last space is set manually
					::std::cout << "    " << ::std::setfill(t_fillChar) << ::std::left << ::std::setw(t_LengthArgumentSpace-1) << t_ss.str() << ' ';

					// TODO: real line breaks, aka ones that do not divide words
					::std::cout << insert_line_breaks(t_entry->description(), t_DescriptionLineLength, t_LengthArgumentSpace) << ::std::endl;
				}
				else
				{
					::std::cout << "    " << t_ss.str() << ::std::endl;
				}
			}

			::std::cout << ::std::endl;
		}

		auto command_base::sort_arguments() const
			-> category_map_type
		{
			category_map_type t_categories{ };

			for(const auto& t_kvp: m_ArgMap)
			{
				const auto& t_ptr = t_kvp.second;

				t_categories[(t_ptr->has_category() ? t_ptr->category() : "General"s)].push_back({t_ptr.get()});
			}

			return t_categories;
		}
	}
}
<commit_msg>Fixed argument long name field being to short in print_summary()<commit_after>#include <iterator>
#include <vector>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <algorithm>
#include <sstream>
#include <map>
#include <ut/throwf.hxx>

#include "utility.hxx"
#include "command.hxx"
#include "grammar.hxx"
#include "parser_action.hxx"
#include "parser_state.hxx"

using namespace std::literals;

namespace cl
{
	namespace internal
	{
		void command_base::check_required() const
		{
			// Check if there ary any arguments that are required but not supplied
			for (auto& arg : m_ArgMap)
			{
				auto& ptr = arg.second;

				if (ptr->required() && !ptr->supplied())
				{
					ut::throwf<std::runtime_error>(
						"Required argument \"--%s\" was not supplied!",
						ptr->long_name()
					);
				}
			}
		}

		void command_base::add(argument_ptr p_ptr)
		{
			if(m_ArgMap.count(p_ptr->long_name()) != 0)
			{
				ut::throwf<::std::runtime_error>(
					"Tried to register multiple arguments with identical long name"
					" \"--%s\"",
					p_ptr->long_name()
				);
			}

			if (p_ptr->has_id())
				m_IdMap[p_ptr->id()] = ut::make_observer<internal::argument_base>(p_ptr.get());

			// Add argument and hand over ownership
			m_ArgMap[p_ptr->long_name()] = ::std::move(p_ptr);
		}

		auto command_base::get(const ::std::string& p_str) const
			-> const_argument_view
		{
			// Lookup by long name
			const auto t_it = m_ArgMap.find(p_str);

			if(t_it != m_ArgMap.end())
			{
				return ut::make_observer<const internal::argument_base>(t_it->second.get());
			}
			else
			{
				ut::throwf<::std::runtime_error>(
					"Unknown commandline argument:"
					" \"--%s\"",
					p_str
				);
			}
		}

		auto command_base::get(char p_chr) const
			-> const_argument_view
		{
			// Lookup by short name
			const auto t_it = ::std::find_if(m_ArgMap.cbegin(), m_ArgMap.cend(),
				[p_chr](const auto& p_pair) -> bool
				{
					return p_pair.second->short_name() == p_chr;
				}
			);

			if(t_it != m_ArgMap.cend())
			{
				return ut::make_observer<const internal::argument_base>(t_it->second.get());
			}
			else
			{
				ut::throwf<::std::runtime_error>(
					"Unknown commandline argument:"
					" \"-%c\"",
					p_chr
				);
			}
		}

		auto command_base::get(::std::size_t p_id) const
			-> const_argument_view
		{
			// Lookup by id
			const auto t_it = m_IdMap.find(p_id);

			if(t_it != m_IdMap.cend())
			{
				return ut::make_observer<const internal::argument_base>(t_it->second.get());
			}
			else
			{
				ut::throwf<::std::runtime_error>(
					"Unknown commandline argument id:"
					" \"%u\"",
					p_id
				);
			}
		}

		auto command_base::get(const ::std::string& p_str)
			-> argument_view
		{
			const auto t_view = const_cast<const this_type*>(this)->get(p_str);

			return ut::make_observer<internal::argument_base>(
				const_cast<internal::argument_base*>(t_view.get())
			);
		}

		auto command_base::get(char p_short)
			-> argument_view
		{
			const auto t_view = const_cast<const this_type*>(this)->get(p_short);

			return ut::make_observer<internal::argument_base>(
				const_cast<internal::argument_base*>(t_view.get())
			);
		}

		auto command_base::get(::std::size_t p_id)
			-> argument_view
		{
			const auto t_view = const_cast<const this_type*>(this)->get(p_id);

			return ut::make_observer<internal::argument_base>(
				const_cast<internal::argument_base*>(t_view.get())
			);
		}

		auto command_base::has(const ::std::string& p_long) const
			-> bool
		{
			return m_ArgMap.count(p_long) != 0;
		}

		auto command_base::has(::std::size_t p_id) const
			-> bool
		{
			return m_IdMap.count(p_id) != 0;
		}

		auto command_base::has(char p_short) const
			-> bool
		{
			const auto t_it = ::std::find_if(m_ArgMap.begin(), m_ArgMap.end(),
				[p_short](const auto& p_pair) -> bool
				{
					return p_pair.second->short_name() == p_short;
				}
			);

			return t_it != m_ArgMap.end();
		}

		auto command_base::supplied(const ::std::string& p_long) const
			-> bool
		{
			return get(p_long)->supplied();
		}

		auto command_base::supplied(char p_short) const
			-> bool
		{
			return get(p_short)->supplied();
		}

		auto command_base::supplied(::std::size_t p_id) const
			-> bool
		{
			return get(p_id)->supplied();
		}

		auto command_base::read(input_type p_cl)
			-> void
		{
			::std::ostringstream ss{};

			for (const char* t_entry: p_cl)
			{
				ss << std::quoted(t_entry) << ' ';
			}

			internal::parser_state state{};

			pegtl::parse<internal::R_Commandline, internal::parser_action>(ss.str(), "", *this, state);

			// Call read_end on all arguments to refresh references etc
			for (auto& arg : m_ArgMap)
				arg.second->read_end();

			// Perform after-read tasks and checks
			check_required();
		}

		auto command_base::local_data() const
			-> const command_data&
		{
			return m_LocalData;
		}

		auto command_base::local_data()
			-> command_data&
		{
			return m_LocalData;
		}

		auto command_base::global_data() const
			-> const handler_data&
		{
			if(m_GlobalDataPtr)
				return *m_GlobalDataPtr;
			else throw ::std::runtime_error("Tried to access null global data ptr!");
		}

		auto command_base::set_global_data(global_data_ptr p_ptr)
			-> void
		{
			m_GlobalDataPtr = p_ptr;
		}

		auto command_base::print_help() const
			-> void
		{
			if(global_data().m_HelpMode != internal::help_mode_::show_none)
			{
				// Print usage first
				if(global_data().m_HelpMode & internal::help_mode_::show_usage)
					print_usage();

				if(global_data().m_HelpMode & internal::help_mode_::show_summary)
					print_summary();
			}
		}

		auto command_base::print_usage() const
			-> void
		{
			if(!m_LocalData.m_Usage.empty())
				std::cout << m_LocalData.m_Usage << std::endl;
		}

		auto command_base::print_summary() const
			-> void
		{
			// Retrieve arguments sorted by category
			const auto t_categories = sort_arguments();

			// Handle "general" category first
			const auto t_it = t_categories.find("General"s);

			if(t_it != t_categories.end())
				print_category("General"s, t_it->second);

			// Handle rest
			for(const auto& t_kvp: t_categories)
			{
				if(t_kvp.first != "General")
					print_category(t_kvp.first, t_kvp.second);
			}
		}

		auto command_base::print_category(const ::std::string& p_name, const ::std::vector<argument_view>& p_cat) const
			-> void
		{
			::std::cout << p_name << ":" << ::std::endl;

			::std::ostringstream t_ss{ };

			// Character used to fill empty space
			const auto t_fillChar = (global_data().m_SummaryStyle == summary_style_::dots ? '.' : ' ');

			// TODO determine length based on longest argument
			constexpr const auto t_LengthArgumentSpace = 30U;
			constexpr const auto t_DescriptionLineLength = 47U;

			for(const auto& t_entry: p_cat)
			{
				// Ensure string stream is empty
				t_ss.str(""s);

				// Build string containing long and (possibly) short name
				t_ss << '[';

				if(t_entry->has_short_name())
					t_ss << '-' << t_entry->short_name() << ", ";

				t_ss << "--" << t_entry->long_name() << "] ";
				//

				if(t_entry->has_description())
				{
					// -1 because the last space is set manually
					::std::cout << "    " << ::std::setfill(t_fillChar) << ::std::left << ::std::setw(t_LengthArgumentSpace-1) << t_ss.str() << ' ';

					// TODO: real line breaks, aka ones that do not divide words
					::std::cout << insert_line_breaks(t_entry->description(), t_DescriptionLineLength, t_LengthArgumentSpace+4) << ::std::endl;
				}
				else
				{
					::std::cout << "    " << t_ss.str() << ::std::endl;
				}
			}

			::std::cout << ::std::endl;
		}

		auto command_base::sort_arguments() const
			-> category_map_type
		{
			category_map_type t_categories{ };

			for(const auto& t_kvp: m_ArgMap)
			{
				const auto& t_ptr = t_kvp.second;

				t_categories[(t_ptr->has_category() ? t_ptr->category() : "General"s)].push_back({t_ptr.get()});
			}

			return t_categories;
		}
	}
}
<|endoftext|>