<commit_before>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * settings.h
 *
 *  Created on: Oct 2018
 *      Author: Norbert Podhorszki
 */

#include "settings.h"

#include <cmath>
#include <cstring>
#include <getopt.h>
#include <iostream>
#include <stdexcept>
#include <string>

#include "adios2/helper/adiosLog.h"

struct option options[] = {{"help", no_argument, NULL, 'h'},
                           {"verbose", no_argument, NULL, 'v'},
                           {"appid", required_argument, NULL, 'a'},
                           {"config", required_argument, NULL, 'c'},
                           {"decomp", required_argument, NULL, 'd'},
                           {"decomp-ratio", required_argument, NULL, 'D'},
                           {"xml", required_argument, NULL, 'x'},
                           {"path", required_argument, NULL, 'p'},
                           {"strong-scaling", no_argument, NULL, 's'},
                           {"weak-scaling", no_argument, NULL, 'w'},
                           {"timer", no_argument, NULL, 't'},
                           {"fixed", no_argument, NULL, 'F'},
#ifdef ADIOS2_HAVE_HDF5_PARALLEL
                           {"hdf5", no_argument, NULL, 'H'},
#endif
                           {NULL, 0, NULL, 0}};

static const char *optstring = "-hvswtFHa:c:d:D:x:p:";

size_t Settings::ndigits(size_t n) const
{
    /* Determine how many characters are needed to print n */
    static char digitstr[32];
    return static_cast<size_t>(snprintf(digitstr, 32, "%zu", n));
}

void Settings::displayHelp()
{
    std::cout
        << "Usage: adios_iotest -a appid -c config {-s | -w} {-d d1[,d2,..,dN] "
           "| -D r1[,r2,..,rN]}"
           "[-x "
           "file]\n"
        << "  -a appID:  unique number for each application in the workflow\n"
        << "  -c config: data specification config file\n"
        << "  -d ...     define process decomposition:\n"
        << "      d1:        number of processes in 1st (slowest) dimension\n"
        << "      dN:        number of processes in Nth dimension\n"
        << "                 d1*d2*..*dN must equal the number of processes\n"
        << "   -D ...    define process decomposition ratio:\n"
        << "      r1:        ratio of process decomposition in the 1st "
           "(slowest) dimension\n"
        << "      rN:        ratio of process decomposition in the Nth "
           "dimension\n"
        << "                 r1xr2x..xrN must scale up to process count"
           "count without remainder\n"
        << "  -s OR -w:  strong or weak scaling. \n"
        << "             Dimensions in config are treated accordingly\n"
        << "  -x file    ADIOS configuration XML file\n"
#ifdef ADIOS2_HAVE_HDF5_PARALLEL
        << "  --hdf5     Use native Parallel HDF5 instead of ADIOS for I/O\n"
#endif
        << "  -v         increase verbosity\n"
        << "  -h         display this help\n"
        << "  -F         turn on fixed I/O pattern explicitly\n"
        << "  -p         specify the path of the output explicitly\n"
        << "  -t         print and dump the timing measured by the I/O "
           "timer\n\n";
}

size_t Settings::stringToNumber(const std::string &varName,
                                const char *arg) const
{
    char *end;
    size_t retval = static_cast<size_t>(std::strtoull(arg, &end, 10));
    if (end[0] || errno == ERANGE)
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "stringToNumber",
            "Invalid value given for " + varName + ": " + std::string(arg));
    }
    return retval;
}

#ifdef _WIN32
#define strdup _strdup
#endif

int Settings::parseCSDecomp(const char *arg)
{
    char *argCopy;
    char *ratio;

    argCopy = strdup(arg);
    ratio = strtok(argCopy, ",");
    while (ratio)
    {
        processDecomp[nDecomp++] = stringToNumber("decomposition ratio", ratio);
        ratio = strtok(NULL, ",");
    }

    free(argCopy);

    return (0);
}

int Settings::rescaleDecomp()
{
    size_t ratioProd = 1;
    size_t scaleFactor;

    for (size_t i = 0; i < nDecomp; i++)
    {
        ratioProd *= processDecomp[i];
    }

    for (scaleFactor = 1; ratioProd * pow(scaleFactor, nDecomp) <= nProc;
         scaleFactor++)
    {
        if (ratioProd * pow(scaleFactor, nDecomp) == nProc)
        {
            for (size_t i = 0; i < nDecomp; i++)
            {
                processDecomp[i] *= scaleFactor;
            }
            return (0);
        }
    }

    adios2::helper::Throw<std::invalid_argument>(
        "Utils::adios_iotest", "settings", "rescaleDecomp",
        "decomposition ratios must scale up to process count");
}

int Settings::processArgs(int argc, char *argv[])
{
    bool appIdDefined = false;
    bool scalingDefined = false;
    bool decompDefined = false;
    int c;
    int last_c = '_';

    /* Process the arguments */
    while ((c = getopt_long(argc, argv, optstring, options, NULL)) != -1)
    {
        switch (c)
        {
        case 'a':
            appId = stringToNumber("appID", optarg);
            appIdDefined = true;
            break;
        case 'c':
            configFileName = optarg;
            break;
        case 'd':
            if (decompDefined && isRatioDecomp)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -D and -d used at the same time");
            }
            if (strchr(optarg, ','))
            {
                parseCSDecomp(optarg);
            }
            else
            {
                processDecomp[nDecomp] =
                    stringToNumber("decomposition in dimension 1", optarg);
                ++nDecomp;
            }
            decompDefined = true;
            break;
        case 'D':
            if (decompDefined && !isRatioDecomp)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -D and -d used at the same time");
            }
            if (strchr(optarg, ','))
            {
                parseCSDecomp(optarg);
            }
            else
            {
                processDecomp[nDecomp] =
                    stringToNumber("decomposition in dimension 1", optarg);
                ++nDecomp;
            }
            decompDefined = true;
            isRatioDecomp = true;
            break;
        case 'F':
            fixedPattern = true;
            break;
        case 'h':
            if (!myRank)
            {
                displayHelp();
            }
            return 1;
#ifdef ADIOS2_HAVE_HDF5_PARALLEL
        case 'H':
            iolib = IOLib::HDF5;
            break;
#endif
        case 's':
            if (scalingDefined && !isStrongScaling)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -w and -s used at the same time");
            }
            isStrongScaling = true;
            scalingDefined = true;
            break;
        case 'v':
            ++verbose;
            break;
        case 'w':
            if (scalingDefined && isStrongScaling)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -s and -w used at the same time");
            }
            isStrongScaling = false;
            scalingDefined = true;
            break;
        case 't':
            ioTimer = true;
            break;
        case 'x':
            adiosConfigFileName = optarg;
            break;
        case 'p':
            outputPath = optarg;
            break;
        case 1:
            /* This means a field is unknown, or could be multiple arg or bad
             * arg*/

            if (last_c == 'd' || last_c == 'D')
            { // --decomp extra arg (or not if not a number)
                processDecomp[nDecomp] = stringToNumber(
                    "decomposition in dimension " + std::to_string(nDecomp + 1),
                    optarg);
                ++nDecomp;
            }
            else
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Invalid argument " + std::string(optarg));
            }
            break;

        default:
            adios2::helper::Throw<std::invalid_argument>(
                "Utils::adios_iotest", "settings", "processArgs",
                "Invalid argument option " + std::string(optarg));
        } /* end switch */
        if (c != 1)
        {
            last_c = c;
        }
    } /* end while */

    /* Check if we have extra unprocessed arguments */
    if (optind < argc)
    {
        std::string s;
        while (optind < argc)
        {
            s += std::string(argv[optind]) + " ";
            ++optind;
        }
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "There are unknown arguments: " + s);
    }

    /* Check if we have a everything defined */
    if (!appIdDefined)
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "Missing argument for application ID, which must be unique for "
            "each application (see -a option)");
    }
    if (configFileName.empty())
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "Missing argument for config file (see -c option)");
    }
    if (!scalingDefined)
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "Missing argument for scaling, which must be set to Strong or Weak "
            "(see -s, -w options)");
    }

    return 0;
}

int Settings::processArguments(int argc, char *argv[], MPI_Comm worldComm)
{
    int retval = 0;
    try
    {
        retval = processArgs(argc, argv);

        int wrank;
        MPI_Comm_rank(worldComm, &wrank);
        MPI_Comm_split(worldComm, static_cast<int>(appId), wrank, &appComm);

        int rank, nproc;
        MPI_Comm_rank(appComm, &rank);
        MPI_Comm_size(appComm, &nproc);
        myRank = static_cast<size_t>(rank);
        nProc = static_cast<size_t>(nproc);

        if (isRatioDecomp)
        {
            rescaleDecomp();
        }
    }
    catch (std::exception &e) // command-line argument errors
    {
        std::cout << "ERROR : " << e.what() << std::endl;
        displayHelp();
        retval = 1;
    }
    return retval;
}

int Settings::extraArgumentChecks()
{
    if (!nDecomp && nProc > 1)
    {
        std::cout << "ERROR : Missing decomposition for parallel program (see "
                     "-d option)"
                  << std::endl;
        return 1;
    }

    size_t N = 1;
    for (size_t i = 0; i < nDecomp; ++i)
    {
        N *= processDecomp[i];
    }

    if (N != nProc)
    {
        std::cout << "ERROR : Product of decomposition values = " << N
                  << " must equal the number of processes = " << nProc
                  << std::endl;
        return 1;
    }
    return 0;
}
<commit_msg>fix warning<commit_after>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * settings.h
 *
 *  Created on: Oct 2018
 *      Author: Norbert Podhorszki
 */

#include "settings.h"

#include <cmath>
#include <cstring>
#include <getopt.h>
#include <iostream>
#include <stdexcept>
#include <string>

#include "adios2/helper/adiosLog.h"

struct option options[] = {{"help", no_argument, NULL, 'h'},
                           {"verbose", no_argument, NULL, 'v'},
                           {"appid", required_argument, NULL, 'a'},
                           {"config", required_argument, NULL, 'c'},
                           {"decomp", required_argument, NULL, 'd'},
                           {"decomp-ratio", required_argument, NULL, 'D'},
                           {"xml", required_argument, NULL, 'x'},
                           {"path", required_argument, NULL, 'p'},
                           {"strong-scaling", no_argument, NULL, 's'},
                           {"weak-scaling", no_argument, NULL, 'w'},
                           {"timer", no_argument, NULL, 't'},
                           {"fixed", no_argument, NULL, 'F'},
#ifdef ADIOS2_HAVE_HDF5_PARALLEL
                           {"hdf5", no_argument, NULL, 'H'},
#endif
                           {NULL, 0, NULL, 0}};

static const char *optstring = "-hvswtFHa:c:d:D:x:p:";

size_t Settings::ndigits(size_t n) const
{
    /* Determine how many characters are needed to print n */
    static char digitstr[32];
    return static_cast<size_t>(snprintf(digitstr, 32, "%zu", n));
}

void Settings::displayHelp()
{
    std::cout
        << "Usage: adios_iotest -a appid -c config {-s | -w} {-d d1[,d2,..,dN] "
           "| -D r1[,r2,..,rN]}"
           "[-x "
           "file]\n"
        << "  -a appID:  unique number for each application in the workflow\n"
        << "  -c config: data specification config file\n"
        << "  -d ...     define process decomposition:\n"
        << "      d1:        number of processes in 1st (slowest) dimension\n"
        << "      dN:        number of processes in Nth dimension\n"
        << "                 d1*d2*..*dN must equal the number of processes\n"
        << "   -D ...    define process decomposition ratio:\n"
        << "      r1:        ratio of process decomposition in the 1st "
           "(slowest) dimension\n"
        << "      rN:        ratio of process decomposition in the Nth "
           "dimension\n"
        << "                 r1xr2x..xrN must scale up to process count"
           "count without remainder\n"
        << "  -s OR -w:  strong or weak scaling. \n"
        << "             Dimensions in config are treated accordingly\n"
        << "  -x file    ADIOS configuration XML file\n"
#ifdef ADIOS2_HAVE_HDF5_PARALLEL
        << "  --hdf5     Use native Parallel HDF5 instead of ADIOS for I/O\n"
#endif
        << "  -v         increase verbosity\n"
        << "  -h         display this help\n"
        << "  -F         turn on fixed I/O pattern explicitly\n"
        << "  -p         specify the path of the output explicitly\n"
        << "  -t         print and dump the timing measured by the I/O "
           "timer\n\n";
}

size_t Settings::stringToNumber(const std::string &varName,
                                const char *arg) const
{
    char *end;
    size_t retval = static_cast<size_t>(std::strtoull(arg, &end, 10));
    if (end[0] || errno == ERANGE)
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "stringToNumber",
            "Invalid value given for " + varName + ": " + std::string(arg));
    }
    return retval;
}

#ifdef _WIN32
#define strdup _strdup
#endif

int Settings::parseCSDecomp(const char *arg)
{
    char *argCopy;
    char *ratio;

    argCopy = strdup(arg);
    ratio = strtok(argCopy, ",");
    while (ratio)
    {
        processDecomp[nDecomp++] = stringToNumber("decomposition ratio", ratio);
        ratio = strtok(NULL, ",");
    }

    free(argCopy);

    return (0);
}

int Settings::rescaleDecomp()
{
    size_t ratioProd = 1;
    size_t scaleFactor;

    for (size_t i = 0; i < nDecomp; i++)
    {
        ratioProd *= processDecomp[i];
    }

    for (scaleFactor = 1; ratioProd * pow(scaleFactor, nDecomp) <= nProc;
         scaleFactor++)
    {
        if (ratioProd * pow(scaleFactor, nDecomp) == nProc)
        {
            for (size_t i = 0; i < nDecomp; i++)
            {
                processDecomp[i] *= scaleFactor;
            }
            return (0);
        }
    }

    adios2::helper::Throw<std::invalid_argument>(
        "Utils::adios_iotest", "settings", "rescaleDecomp",
        "decomposition ratios must scale up to process count");
    return 0;
}

int Settings::processArgs(int argc, char *argv[])
{
    bool appIdDefined = false;
    bool scalingDefined = false;
    bool decompDefined = false;
    int c;
    int last_c = '_';

    /* Process the arguments */
    while ((c = getopt_long(argc, argv, optstring, options, NULL)) != -1)
    {
        switch (c)
        {
        case 'a':
            appId = stringToNumber("appID", optarg);
            appIdDefined = true;
            break;
        case 'c':
            configFileName = optarg;
            break;
        case 'd':
            if (decompDefined && isRatioDecomp)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -D and -d used at the same time");
            }
            if (strchr(optarg, ','))
            {
                parseCSDecomp(optarg);
            }
            else
            {
                processDecomp[nDecomp] =
                    stringToNumber("decomposition in dimension 1", optarg);
                ++nDecomp;
            }
            decompDefined = true;
            break;
        case 'D':
            if (decompDefined && !isRatioDecomp)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -D and -d used at the same time");
            }
            if (strchr(optarg, ','))
            {
                parseCSDecomp(optarg);
            }
            else
            {
                processDecomp[nDecomp] =
                    stringToNumber("decomposition in dimension 1", optarg);
                ++nDecomp;
            }
            decompDefined = true;
            isRatioDecomp = true;
            break;
        case 'F':
            fixedPattern = true;
            break;
        case 'h':
            if (!myRank)
            {
                displayHelp();
            }
            return 1;
#ifdef ADIOS2_HAVE_HDF5_PARALLEL
        case 'H':
            iolib = IOLib::HDF5;
            break;
#endif
        case 's':
            if (scalingDefined && !isStrongScaling)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -w and -s used at the same time");
            }
            isStrongScaling = true;
            scalingDefined = true;
            break;
        case 'v':
            ++verbose;
            break;
        case 'w':
            if (scalingDefined && isStrongScaling)
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Cannot have -s and -w used at the same time");
            }
            isStrongScaling = false;
            scalingDefined = true;
            break;
        case 't':
            ioTimer = true;
            break;
        case 'x':
            adiosConfigFileName = optarg;
            break;
        case 'p':
            outputPath = optarg;
            break;
        case 1:
            /* This means a field is unknown, or could be multiple arg or bad
             * arg*/

            if (last_c == 'd' || last_c == 'D')
            { // --decomp extra arg (or not if not a number)
                processDecomp[nDecomp] = stringToNumber(
                    "decomposition in dimension " + std::to_string(nDecomp + 1),
                    optarg);
                ++nDecomp;
            }
            else
            {
                adios2::helper::Throw<std::invalid_argument>(
                    "Utils::adios_iotest", "settings", "processArgs",
                    "Invalid argument " + std::string(optarg));
            }
            break;

        default:
            adios2::helper::Throw<std::invalid_argument>(
                "Utils::adios_iotest", "settings", "processArgs",
                "Invalid argument option " + std::string(optarg));
        } /* end switch */
        if (c != 1)
        {
            last_c = c;
        }
    } /* end while */

    /* Check if we have extra unprocessed arguments */
    if (optind < argc)
    {
        std::string s;
        while (optind < argc)
        {
            s += std::string(argv[optind]) + " ";
            ++optind;
        }
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "There are unknown arguments: " + s);
    }

    /* Check if we have a everything defined */
    if (!appIdDefined)
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "Missing argument for application ID, which must be unique for "
            "each application (see -a option)");
    }
    if (configFileName.empty())
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "Missing argument for config file (see -c option)");
    }
    if (!scalingDefined)
    {
        adios2::helper::Throw<std::invalid_argument>(
            "Utils::adios_iotest", "settings", "processArgs",
            "Missing argument for scaling, which must be set to Strong or Weak "
            "(see -s, -w options)");
    }

    return 0;
}

int Settings::processArguments(int argc, char *argv[], MPI_Comm worldComm)
{
    int retval = 0;
    try
    {
        retval = processArgs(argc, argv);

        int wrank;
        MPI_Comm_rank(worldComm, &wrank);
        MPI_Comm_split(worldComm, static_cast<int>(appId), wrank, &appComm);

        int rank, nproc;
        MPI_Comm_rank(appComm, &rank);
        MPI_Comm_size(appComm, &nproc);
        myRank = static_cast<size_t>(rank);
        nProc = static_cast<size_t>(nproc);

        if (isRatioDecomp)
        {
            rescaleDecomp();
        }
    }
    catch (std::exception &e) // command-line argument errors
    {
        std::cout << "ERROR : " << e.what() << std::endl;
        displayHelp();
        retval = 1;
    }
    return retval;
}

int Settings::extraArgumentChecks()
{
    if (!nDecomp && nProc > 1)
    {
        std::cout << "ERROR : Missing decomposition for parallel program (see "
                     "-d option)"
                  << std::endl;
        return 1;
    }

    size_t N = 1;
    for (size_t i = 0; i < nDecomp; ++i)
    {
        N *= processDecomp[i];
    }

    if (N != nProc)
    {
        std::cout << "ERROR : Product of decomposition values = " << N
                  << " must equal the number of processes = " << nProc
                  << std::endl;
        return 1;
    }
    return 0;
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2022 katursis
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "main.h"

StringView PluginComponent::componentName() const {
  return Plugin::Instance().Name();
}

SemanticVersion PluginComponent::componentVersion() const {
  auto [major, minor, patch] =
      Plugin::VersionToTuple(Plugin::Instance().Version());

  return SemanticVersion(0, major, minor, patch);
}

void PluginComponent::onLoad(ICore *c) {
  core_ = c;

  getCore() = c;
  get() = this;
}

void PluginComponent::onInit(IComponentList *components) {
  pawn_component_ = components->queryComponent<IPawnComponent>();
  if (!pawn_component_) {
    StringView name = componentName();

    core_->logLn(LogLevel::Error,
                 "Error loading component %.*s: Pawn component not loaded",
                 name.length(), name.data());

    return;
  }

  core_->getEventDispatcher().addEventHandler(this);
  pawn_component_->getEventDispatcher().addEventHandler(this);

  for (auto network : core_->getNetworks()) {
    network->getInEventDispatcher().addEventHandler(this);
    network->getOutEventDispatcher().addEventHandler(this);
  }

  plugin_data_[PLUGIN_DATA_LOGPRINTF] =
      reinterpret_cast<void *>(&PluginLogprintf);
  plugin_data_[PLUGIN_DATA_AMX_EXPORTS] =
      const_cast<void **>(pawn_component_->getAmxFunctions().data());

  Plugin::DoLoad(plugin_data_);
}

void PluginComponent::onAmxLoad(void *amx) {
  Plugin::DoAmxLoad(static_cast<AMX *>(amx));
};

void PluginComponent::onAmxUnload(void *amx){};

void PluginComponent::onTick(Microseconds elapsed, TimePoint now) {
  Plugin::DoProcessTick();
}

bool PluginComponent::onReceivePacket(IPlayer &peer, int id,
                                      NetworkBitStream &bs) {
  return Plugin::OnEvent<PR_INCOMING_PACKET>(peer.getID(), id, &bs);
}

bool PluginComponent::onReceiveRPC(IPlayer &peer, int id,
                                   NetworkBitStream &bs) {
  auto &plugin = Plugin::Get();

  const auto on_event = plugin.IsCustomRPC(static_cast<RPCIndex>(id))
                            ? Plugin::OnEvent<PR_INCOMING_CUSTOM_RPC>
                            : Plugin::OnEvent<PR_INCOMING_RPC>;

  return on_event(peer.getID(), id, &bs);
}

bool PluginComponent::onSendPacket(IPlayer *peer, int id,
                                   NetworkBitStream &bs) {
  return Plugin::OnEvent<PR_OUTGOING_PACKET>(peer ? peer->getID() : -1, id,
                                             &bs);
}

bool PluginComponent::onSendRPC(IPlayer *peer, int id, NetworkBitStream &bs) {
  return Plugin::OnEvent<PR_OUTGOING_RPC>(peer ? peer->getID() : -1, id, &bs);
}

void PluginComponent::onFree(IComponent *component) {
  if (component == pawn_component_ || component == this) {
    Plugin::DoUnload();

    if (pawn_component_) {
        core_->getEventDispatcher().removeEventHandler(this);
        pawn_component_->getEventDispatcher().removeEventHandler(this);
    }
    pawn_component_ = nullptr;
  }
}

void PluginComponent::reset() {}

void PluginComponent::free() {
  delete this;
}

void PluginComponent::PluginLogprintf(const char *fmt, ...) {
  auto core = getCore();
  if (!core) {
    return;
  }

  va_list args{};

  va_start(args, fmt);

  core->vprintLn(fmt, args);

  va_end(args);
}

ICore *&PluginComponent::getCore() {
  static ICore *core{};

  return core;
}

PluginComponent *&PluginComponent::get() {
  static PluginComponent *component{};

  return component;
}

COMPONENT_ENTRY_POINT() { return new PluginComponent(); }
<commit_msg>Add missed line<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2022 katursis
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "main.h"

StringView PluginComponent::componentName() const {
  return Plugin::Instance().Name();
}

SemanticVersion PluginComponent::componentVersion() const {
  auto [major, minor, patch] =
      Plugin::VersionToTuple(Plugin::Instance().Version());

  return SemanticVersion(0, major, minor, patch);
}

void PluginComponent::onLoad(ICore *c) {
  core_ = c;

  getCore() = c;
  get() = this;
}

void PluginComponent::onInit(IComponentList *components) {
  pawn_component_ = components->queryComponent<IPawnComponent>();
  if (!pawn_component_) {
    StringView name = componentName();

    core_->logLn(LogLevel::Error,
                 "Error loading component %.*s: Pawn component not loaded",
                 name.length(), name.data());

    return;
  }

  core_->getEventDispatcher().addEventHandler(this);
  pawn_component_->getEventDispatcher().addEventHandler(this);

  for (auto network : core_->getNetworks()) {
    network->getInEventDispatcher().addEventHandler(this);
    network->getOutEventDispatcher().addEventHandler(this);
  }

  plugin_data_[PLUGIN_DATA_LOGPRINTF] =
      reinterpret_cast<void *>(&PluginLogprintf);
  plugin_data_[PLUGIN_DATA_AMX_EXPORTS] =
      const_cast<void **>(pawn_component_->getAmxFunctions().data());

  Plugin::DoLoad(plugin_data_);
}

void PluginComponent::onAmxLoad(void *amx) {
  Plugin::DoAmxLoad(static_cast<AMX *>(amx));
};

void PluginComponent::onAmxUnload(void *amx){};

void PluginComponent::onTick(Microseconds elapsed, TimePoint now) {
  Plugin::DoProcessTick();
}

bool PluginComponent::onReceivePacket(IPlayer &peer, int id,
                                      NetworkBitStream &bs) {
  return Plugin::OnEvent<PR_INCOMING_PACKET>(peer.getID(), id, &bs);
}

bool PluginComponent::onReceiveRPC(IPlayer &peer, int id,
                                   NetworkBitStream &bs) {
  auto &plugin = Plugin::Get();

  const auto on_event = plugin.IsCustomRPC(static_cast<RPCIndex>(id))
                            ? Plugin::OnEvent<PR_INCOMING_CUSTOM_RPC>
                            : Plugin::OnEvent<PR_INCOMING_RPC>;

  return on_event(peer.getID(), id, &bs);
}

bool PluginComponent::onSendPacket(IPlayer *peer, int id,
                                   NetworkBitStream &bs) {
  return Plugin::OnEvent<PR_OUTGOING_PACKET>(peer ? peer->getID() : -1, id,
                                             &bs);
}

bool PluginComponent::onSendRPC(IPlayer *peer, int id, NetworkBitStream &bs) {
  return Plugin::OnEvent<PR_OUTGOING_RPC>(peer ? peer->getID() : -1, id, &bs);
}

void PluginComponent::onFree(IComponent *component) {
  if (component == pawn_component_ || component == this) {
    Plugin::DoUnload();

    if (pawn_component_) {
        core_->getEventDispatcher().removeEventHandler(this);
        pawn_component_->getEventDispatcher().removeEventHandler(this);
    }

    pawn_component_ = nullptr;
  }
}

void PluginComponent::reset() {}

void PluginComponent::free() {
  delete this;
}

void PluginComponent::PluginLogprintf(const char *fmt, ...) {
  auto core = getCore();
  if (!core) {
    return;
  }

  va_list args{};

  va_start(args, fmt);

  core->vprintLn(fmt, args);

  va_end(args);
}

ICore *&PluginComponent::getCore() {
  static ICore *core{};

  return core;
}

PluginComponent *&PluginComponent::get() {
  static PluginComponent *component{};

  return component;
}

COMPONENT_ENTRY_POINT() { return new PluginComponent(); }
<|endoftext|>


<commit_before>/**
 * \file   main.cc
 * \Author Andrea Barberio <insomniac@slackware.it>
 * \date   October 2015
 * \brief  entry point for dublin-traceroute
 *
 * This file contains the main routine for calling the standalone dublin-traceroute
 * executable.
 */

#include <iostream>
#include <fstream>

#include <dublintraceroute/dublin_traceroute.h>

// TODO argument parsing

#define TARGET		"8.8.8.8"
#define PATHS		10

void
usage(const char *name) {
	std::cout << "Usage: " << name << " target" << std::endl;
	exit(EXIT_FAILURE);
}

int
main(int argc, char **argv) {
	if (argc != 2)
		usage(argv[0]);

	const std::string target = std::string(argv[1]);
	std::cout << "Starting dublin-traceroute" << std::endl;

	DublinTraceroute Dublin(
			target,
			12345,
			(1<<15) + 666,  // traceroute's port
			PATHS
	);
	std::cout
		<< "Traceroute from 0.0.0.0:" << Dublin.srcport()
		<< " to " << Dublin.dst()
		<< ":" << Dublin.dstport() << "~" << (Dublin.dstport() + PATHS - 1)
		<< std::endl;

	std::shared_ptr<TracerouteResults> results;
	try {
		results = std::make_shared<TracerouteResults>(Dublin.traceroute());
	} catch (DublinTracerouteException &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	} catch (std::runtime_error &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	}

	results->show();

	// Save as JSON
	std::ofstream jsonfile;
	jsonfile.open("trace.json");
	jsonfile << results->to_json();
	jsonfile.close();
	std::cout << "Saved JSON file to trace.json ." << std::endl;

	std::cout << "You can convert it to DOT by running python -m dublintraceroute --plot trace.json" << std::endl;
}

<commit_msg>Exit success if no command is specified<commit_after>/**
 * \file   main.cc
 * \Author Andrea Barberio <insomniac@slackware.it>
 * \date   October 2015
 * \brief  entry point for dublin-traceroute
 *
 * This file contains the main routine for calling the standalone dublin-traceroute
 * executable.
 */

#include <iostream>
#include <fstream>

#include <dublintraceroute/dublin_traceroute.h>

// TODO argument parsing

#define TARGET		"8.8.8.8"
#define PATHS		10

void
usage(const char *name) {
	std::cout << "Usage: " << name << " target" << std::endl;
	exit(EXIT_SUCCESS);
}

int
main(int argc, char **argv) {
	if (argc != 2)
		usage(argv[0]);

	const std::string target = std::string(argv[1]);
	std::cout << "Starting dublin-traceroute" << std::endl;

	DublinTraceroute Dublin(
			target,
			12345,
			(1<<15) + 666,  // traceroute's port
			PATHS
	);
	std::cout
		<< "Traceroute from 0.0.0.0:" << Dublin.srcport()
		<< " to " << Dublin.dst()
		<< ":" << Dublin.dstport() << "~" << (Dublin.dstport() + PATHS - 1)
		<< std::endl;

	std::shared_ptr<TracerouteResults> results;
	try {
		results = std::make_shared<TracerouteResults>(Dublin.traceroute());
	} catch (DublinTracerouteException &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	} catch (std::runtime_error &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	}

	results->show();

	// Save as JSON
	std::ofstream jsonfile;
	jsonfile.open("trace.json");
	jsonfile << results->to_json();
	jsonfile.close();
	std::cout << "Saved JSON file to trace.json ." << std::endl;

	std::cout << "You can convert it to DOT by running python -m dublintraceroute --plot trace.json" << std::endl;

	exit(EXIT_SUCCESS);
}

<|endoftext|>


<commit_before>#ifdef TEST
#include <unistd.h>
#include <getopt.h>

#include <deal.II/base/mpi.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "test_helpers/bart_test_helper.h"

#endif

//#include "aqdata/aq_base.h"

#ifdef TEST
int main(int argc, char* argv[]) {
  // Parse optional arguments
  ::testing::InitGoogleMock(&argc, argv);

  int option_index = 0;

  const struct option longopts[] =
  {
    {"report", no_argument, nullptr, 'r'}
  };

  int c;
  while ((c = getopt_long (argc, argv, "rd:", longopts, &option_index)) != -1) {
    switch(c) {
      case 'r':
        btest::GlobalBARTTestHelper().SetReport(true);
        break;
      case 'd':
        btest::GlobalBARTTestHelper().SetGoldFilesDirectory(optarg);
        break;
      default:
        break;
    }
  }
  //dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, 1);
  // Testing
  //::testing::TestEventListeners& listeners =
  //::testing::UnitTest::GetInstance()->listeners();
  //if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) != 0)
  //if (world.rank() != 0)
  //delete listeners.Release(listeners.default_result_printer());
  return RUN_ALL_TESTS();
#else
int main() {
  return 0;
#endif
}
<commit_msg>rewrote main function<commit_after>#ifdef TEST
#include <unistd.h>
#include <getopt.h>

#include <deal.II/base/mpi.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "test_helpers/bart_test_helper.h"
#else
#include "common/problem_definition.h"
#include "common/bart_driver.h"
#endif

int main(int argc, char* argv[]) {
#ifdef TEST
  // Parse optional arguments
  ::testing::InitGoogleMock(&argc, argv);

  int option_index = 0;

  const struct option longopts[] =
  {
    {"report", no_argument, nullptr, 'r'}
  };

  int c;
  while ((c = getopt_long (argc, argv, "rd:", longopts, &option_index)) != -1) {
    switch(c) {
      case 'r':
        btest::GlobalBARTTestHelper().SetReport(true);
        break;
      case 'd':
        btest::GlobalBARTTestHelper().SetGoldFilesDirectory(optarg);
        break;
      default:
        break;
    }
  }
  return RUN_ALL_TESTS();
#else
  try {
    if (argc!=2) {
      std::cerr << "Call the program as mpirun -np num_proc xtrans input_file_name" << std::endl;
      return 1;
    }
    ParameterHandler prm;
    bparams::DeclareParameters (prm);
    prm.read_input(argv[1]);
    dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
    int dim = prm.get_integer ("problem dimension");
    switch (dim) {
      case 1:{
        BARTDriver<1> drive1d (prm);
        drive1d.DriveBART();
        break;
      }
      case 2:{
        BARTDriver<2> drive2d (prm);
        drive2d.DriveBART ();
        break;
      }
      case 3:{
        BARTDriver<3> drive3d (prm);
        drive3d.DriveBART ();
        break;
      }
      default:
        break;
    }
  }
  catch (std::exception &exc) {
    std::cerr << std::endl << std::endl
              << "----------------------------------------------------"
              << std::endl;
    std::cerr << "Exception on processing: " << std::endl
              << exc.what() << std::endl
              << "Aborting!" << std::endl
              << "----------------------------------------------------"
              << std::endl;
    return 1;
  }
  catch (...) {
    std::cerr << std::endl << std::endl
              << "----------------------------------------------------"
              << std::endl;
    std::cerr << "Unknown exception!" << std::endl
              << "Aborting!" << std::endl
              << "----------------------------------------------------"
              << std::endl;
    return 1;
  }
  return 0;
#endif
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 Muhammad Tayyab Akram
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>

extern "C" {
#include <SheenBidi.h>
}

#include <Parser/BidiBrackets.h>
#include <Parser/BidiCharacterTest.h>
#include <Parser/BidiMirroring.h>
#include <Parser/BidiTest.h>
#include <Parser/PropertyValueAliases.h>
#include <Parser/Scripts.h>
#include <Parser/UnicodeData.h>

#include "AlgorithmTester.h"
#include "BidiTypeTester.h"
#include "BracketTester.h"
#include "CodepointSequenceTester.h"
#include "MirrorTester.h"
#include "ScriptTester.h"

using namespace std;
using namespace SheenBidi::Parser;
using namespace SheenBidi::Tester;

int main(int argc, const char *argv[]) {
    const char *dir = argv[1];

    UnicodeData unicodeData(dir);
    BidiMirroring bidiMirroring(dir);
    BidiBrackets bidiBrackets(dir);
    BidiTest bidiTest(dir);
    BidiCharacterTest bidiCharacterTest(dir);
    Scripts scripts(dir);
    PropertyValueAliases propertyValueAliases(dir);

    BidiTypeTester bidiTypeTester(unicodeData);
    CodepointSequenceTester codepointSequenceTester;
    MirrorTester mirrorTester(bidiMirroring);
    BracketTester bracketTester(bidiBrackets);
    ScriptTester scriptTester(scripts, propertyValueAliases);
    AlgorithmTester algorithmTester(&bidiTest, &bidiCharacterTest, &bidiMirroring);

    bidiTypeTester.test();
    codepointSequenceTester.test();
    mirrorTester.test();
    bracketTester.test();
    scriptTester.test();
    algorithmTester.test();

    return 0;
}
<commit_msg>[test] Added general category tester in main...<commit_after>/*
 * Copyright (C) 2018 Muhammad Tayyab Akram
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>

extern "C" {
#include <SheenBidi.h>
}

#include <Parser/BidiBrackets.h>
#include <Parser/BidiCharacterTest.h>
#include <Parser/BidiMirroring.h>
#include <Parser/BidiTest.h>
#include <Parser/PropertyValueAliases.h>
#include <Parser/Scripts.h>
#include <Parser/UnicodeData.h>

#include "AlgorithmTester.h"
#include "BidiTypeTester.h"
#include "BracketTester.h"
#include "CodepointSequenceTester.h"
#include "GeneralCategoryTester.h"
#include "MirrorTester.h"
#include "ScriptTester.h"

using namespace std;
using namespace SheenBidi::Parser;
using namespace SheenBidi::Tester;

int main(int argc, const char *argv[]) {
    const char *dir = argv[1];

    UnicodeData unicodeData(dir);
    BidiMirroring bidiMirroring(dir);
    BidiBrackets bidiBrackets(dir);
    BidiTest bidiTest(dir);
    BidiCharacterTest bidiCharacterTest(dir);
    Scripts scripts(dir);
    PropertyValueAliases propertyValueAliases(dir);

    BidiTypeTester bidiTypeTester(unicodeData);
    CodepointSequenceTester codepointSequenceTester;
    MirrorTester mirrorTester(bidiMirroring);
    BracketTester bracketTester(bidiBrackets);
    GeneralCategoryTester generalCategoryTester(unicodeData);
    ScriptTester scriptTester(scripts, propertyValueAliases);
    AlgorithmTester algorithmTester(&bidiTest, &bidiCharacterTest, &bidiMirroring);

    bidiTypeTester.test();
    codepointSequenceTester.test();
    mirrorTester.test();
    bracketTester.test();
    generalCategoryTester.test();
    scriptTester.test();
    algorithmTester.test();

    return 0;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief V8 line editor
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "v8-line-editor.h"

#include <readline/readline.h>
#include <readline/history.h>

#include "BasicsC/strings.h"

#if RL_READLINE_VERSION >= 0x0500
#define completion_matches rl_completion_matches
#endif

using namespace std;

// -----------------------------------------------------------------------------
// --SECTION--                                                class V8LineEditor
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8Shell
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief word break characters
////////////////////////////////////////////////////////////////////////////////

static char WordBreakCharacters[] = {
    ' ', '\t', '\n', '"', '\\', '\'', '`', '@',
    '<', '>', '=', ';', '|', '&', '{', '}', '(', ')',
    '\0'
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8LineEditor
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief completion generator
////////////////////////////////////////////////////////////////////////////////

static char* CompletionGenerator (char const* text, int state) {
  static size_t currentIndex;
  static vector<string> result;
  char* prefix;

  // compute the possible completion
  if (state == 0) {
    if (! v8::Context::InContext()) {
      return 0;
    }

    // locate global object or sub-object
    v8::Handle<v8::Object> current = v8::Context::GetCurrent()->Global();
    string path;

    if (*text != '\0') {
      TRI_vector_string_t splitted = TRI_SplitString(text, '.');

      if (1 < splitted._length) {
        for (size_t i = 0;  i < splitted._length - 1;  ++i) {
          v8::Handle<v8::String> name = v8::String::New(splitted._buffer[i]);

          if (! current->Has(name)) {
            TRI_DestroyVectorString(&splitted);
            return 0;
          }

          v8::Handle<v8::Value> val = current->Get(name);

          if (! val->IsObject()) {
            TRI_DestroyVectorString(&splitted);
            return 0;
          }

          current = val->ToObject();
          path = path + splitted._buffer[i] + ".";
        }

        prefix = TRI_DuplicateString(splitted._buffer[splitted._length - 1]);
      }
      else {
        prefix = TRI_DuplicateString(text);
      }

      TRI_DestroyVectorString(&splitted);
    }
    else {
      prefix = TRI_DuplicateString(text);
    }

    // compute all possible completions
    v8::Handle<v8::Array> properties;
    v8::Handle<v8::String> cpl = v8::String::New("_COMPLETIONS");

    if (current->HasOwnProperty(cpl)) {
      v8::Handle<v8::Value> funcVal = current->Get(cpl);

      if (funcVal->IsFunction()) {
        v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(funcVal);
        v8::Handle<v8::Value> args;
        v8::Handle<v8::Value> cpls = func->Call(current, 0, &args);

        if (cpls->IsArray()) {
          properties = v8::Handle<v8::Array>::Cast(cpls);
        }
      }
    }
    else {
      properties = current->GetPropertyNames();
    }

    // locate
    if (! properties.IsEmpty()) {
      size_t n = properties->Length();

      for (size_t i = 0;  i < n;  ++i) {
        v8::Handle<v8::Value> v = properties->Get(i);

        v8::String::Utf8Value str(v);
        char const* s = *str;

        if (s != 0) {
          string suffix = (current->Get(v)->IsFunction()) ? "()" : "";
          string name = path + s + suffix;

          if (*prefix == '\0' || TRI_IsPrefixString(s, prefix)) {
            result.push_back(name);
          }
        }
      }
    }

    currentIndex = 0;

    TRI_FreeString(prefix);
  }

  if (currentIndex < result.size()) {
    return TRI_DuplicateString(result[currentIndex++].c_str());
  }
  else {
    result.clear();
    return 0;
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief attempted completion
////////////////////////////////////////////////////////////////////////////////

static char** AttemptedCompletion (char const* text, int start, int end) {
  char** result;

  result = completion_matches(text, CompletionGenerator);
  rl_attempted_completion_over = true;

  if (result != 0 && result[0] != 0 && result[1] == 0) {
    size_t n = strlen(result[0]);

    if (result[0][n-1] == ')') {
      result[0][n-1] = '\0';
      rl_completion_suppress_append = 1;
    }
  }

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks if javascript is missing a closing bracket
////////////////////////////////////////////////////////////////////////////////

static bool CheckJavaScript (string const& source) {
  char const* ptr;
  char const* end;
  int openParen;
  int openBrackets;
  int openBraces;

  enum {
    NORMAL,             // start
    NORMAL_1,           // from NORMAL: seen a single /
    DOUBLE_QUOTE,       // from NORMAL: seen a single "
    DOUBLE_QUOTE_ESC,   // from DOUBLE_QUOTE: seen a backslash
    SINGLE_QUOTE,       // from NORMAL: seen a single '
    SINGLE_QUOTE_ESC,   // from SINGLE_QUOTE: seen a backslash
    MULTI_COMMENT,      // from NORMAL_1: seen a *
    MULTI_COMMENT_1,    // from MULTI_COMMENT, seen a *
    SINGLE_COMMENT      // from NORMAL_1; seen a /
  }
  state;

  openParen = 0;
  openBrackets = 0;
  openBraces = 0;

  ptr = source.c_str();
  end = ptr + source.length();
  state = NORMAL;

  while (ptr < end) {
    if (state == DOUBLE_QUOTE) {
      if (*ptr == '\\') {
        state = DOUBLE_QUOTE_ESC;
      }
      else if (*ptr == '"') {
        state = NORMAL;
      }

      ++ptr;
    }
    else if (state == DOUBLE_QUOTE_ESC) {
      state = DOUBLE_QUOTE;
      ptr++;
    }
    else if (state == SINGLE_QUOTE) {
      if (*ptr == '\\') {
        state = SINGLE_QUOTE_ESC;
      }
      else if (*ptr == '\'') {
        state = NORMAL;
      }

      ++ptr;
    }
    else if (state == SINGLE_QUOTE_ESC) {
      state = SINGLE_QUOTE;
      ptr++;
    }
    else if (state == MULTI_COMMENT) {
      if (*ptr == '*') {
        state = MULTI_COMMENT_1;
      }

      ++ptr;
    }
    else if (state == MULTI_COMMENT_1) {
      if (*ptr == '/') {
        state = NORMAL;
      }

      ++ptr;
    }
    else if (state == SINGLE_COMMENT) {
      ++ptr;

      if (ptr == end) {
        state = NORMAL;
      }
    }
    else if (state == NORMAL_1) {
      switch (*ptr) {
        case '/':
          state = SINGLE_COMMENT;
          ++ptr;
          break;

        case '*':
          state = MULTI_COMMENT;
          ++ptr;
          break;

        default:
          state = NORMAL; // try again, do not change ptr
          break;
      }
    }
    else {
      switch (*ptr) {
        case '"':
          state = DOUBLE_QUOTE;
          break;

        case '\'':
          state = SINGLE_QUOTE;
          break;

        case '/':
          state = NORMAL_1;
          break;

        case '(':
          ++openParen;
          break;

        case ')':
          --openParen;
          break;

        case '[':
          ++openBrackets;
          break;

        case ']':
          --openBrackets;
          break;

        case '{':
          ++openBraces;
          break;

        case '}':
          --openBraces;
          break;
      }

      ++ptr;
    }
  }

  return openParen <= 0 && openBrackets <= 0 && openBraces <= 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8LineEditor
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new editor
////////////////////////////////////////////////////////////////////////////////

V8LineEditor::V8LineEditor (v8::Handle<v8::Context> context, string const& history)
  : _current(), _historyFilename(history), _context(context) {
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8LineEditor
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor open
////////////////////////////////////////////////////////////////////////////////

bool V8LineEditor::open (const bool autoComplete) {
  rl_initialize();

  if (autoComplete) {
    rl_attempted_completion_function = AttemptedCompletion;
    rl_completer_word_break_characters = WordBreakCharacters;

    rl_bind_key('\t', rl_complete);
  }

  using_history();
  stifle_history(MAX_HISTORY_ENTRIES);

  return read_history(getHistoryPath().c_str()) == 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor shutdown
////////////////////////////////////////////////////////////////////////////////

bool V8LineEditor::close () {
  bool result = write_history(getHistoryPath().c_str());

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief get the history file path
////////////////////////////////////////////////////////////////////////////////

string V8LineEditor::getHistoryPath () {
  string path;

  if (getenv("HOME")) {
    path.append(getenv("HOME"));
    path += '/';
  }

  path.append(_historyFilename);

  return path;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor prompt
////////////////////////////////////////////////////////////////////////////////

char* V8LineEditor::prompt (char const* prompt) {
  string dotdot;
  char const* p = prompt;
  size_t len1 = strlen(prompt);
  size_t len2 = len1;

  if (len1 < 3) {
    dotdot = "> ";
    len2 = 2;
  }
  else {
    dotdot = string(len1 - 2, '.') + "> ";
  }

  char const* sep = "";
  char* originalLine = 0;

  while (true) {
    char* result = readline(p);
    originalLine = result;
    p = dotdot.c_str();

    if (result == 0) {
      // give up, if the user pressed control-D on the top-most level
      if (_current.empty()) {
        return 0;
      }

      // otherwise clear current content
      _current.clear();
      break;
    }

    _current += sep;
    sep = "\n";

    bool c1 = strncmp(result, prompt, len1) == 0;
    bool c2 = strncmp(result, dotdot.c_str(), len2) == 0;

    while (c1 || c2) {
      if (c1) {
        result += len1;
      }
      else if (c2) {
        result += len2;
      }

      c1 = strncmp(result, prompt, len1) == 0;
      c2 = strncmp(result, dotdot.c_str(), len2) == 0;
    }

    _current += result;
    bool ok = CheckJavaScript(_current);

    if (ok) {
      break;
    }
    TRI_Free(originalLine);
  }

  char* line = TRI_DuplicateString(_current.c_str());
  _current.clear();

  // avoid memleaks
  if (originalLine != 0) {
    TRI_Free(originalLine);
  }

  return line;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add to history
////////////////////////////////////////////////////////////////////////////////

void V8LineEditor::addHistory (char const* str) {
  if (*str == '\0') {
    return;
  }

  history_set_pos(history_length-1);

  if (current_history()) {
    do {
      if (strcmp(current_history()->line, str) == 0) {
        remove_history(where_history());
        break;
      }
    }
    while (previous_history());
  }

  add_history(str);
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:
<commit_msg>readline<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief V8 line editor
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "v8-line-editor.h"

#include <readline/readline.h>
#include <readline/history.h>

#include "BasicsC/strings.h"

#if RL_READLINE_VERSION >= 0x0500
#define completion_matches rl_completion_matches
#endif

using namespace std;

// -----------------------------------------------------------------------------
// --SECTION--                                                class V8LineEditor
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8Shell
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief word break characters
////////////////////////////////////////////////////////////////////////////////

static char WordBreakCharacters[] = {
    ' ', '\t', '\n', '"', '\\', '\'', '`', '@',
    '<', '>', '=', ';', '|', '&', '{', '}', '(', ')',
    '\0'
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8LineEditor
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief completion generator
////////////////////////////////////////////////////////////////////////////////

static char* CompletionGenerator (char const* text, int state) {
  static size_t currentIndex;
  static vector<string> result;
  char* prefix;

  // compute the possible completion
  if (state == 0) {
    if (! v8::Context::InContext()) {
      return 0;
    }

    // locate global object or sub-object
    v8::Handle<v8::Object> current = v8::Context::GetCurrent()->Global();
    string path;

    if (*text != '\0') {
      TRI_vector_string_t splitted = TRI_SplitString(text, '.');

      if (1 < splitted._length) {
        for (size_t i = 0;  i < splitted._length - 1;  ++i) {
          v8::Handle<v8::String> name = v8::String::New(splitted._buffer[i]);

          if (! current->Has(name)) {
            TRI_DestroyVectorString(&splitted);
            return 0;
          }

          v8::Handle<v8::Value> val = current->Get(name);

          if (! val->IsObject()) {
            TRI_DestroyVectorString(&splitted);
            return 0;
          }

          current = val->ToObject();
          path = path + splitted._buffer[i] + ".";
        }

        prefix = TRI_DuplicateString(splitted._buffer[splitted._length - 1]);
      }
      else {
        prefix = TRI_DuplicateString(text);
      }

      TRI_DestroyVectorString(&splitted);
    }
    else {
      prefix = TRI_DuplicateString(text);
    }

    // compute all possible completions
    v8::Handle<v8::Array> properties;
    v8::Handle<v8::String> cpl = v8::String::New("_COMPLETIONS");

    if (current->HasOwnProperty(cpl)) {
      v8::Handle<v8::Value> funcVal = current->Get(cpl);

      if (funcVal->IsFunction()) {
        v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(funcVal);
        v8::Handle<v8::Value> args;
        v8::Handle<v8::Value> cpls = func->Call(current, 0, &args);

        if (cpls->IsArray()) {
          properties = v8::Handle<v8::Array>::Cast(cpls);
        }
      }
    }
    else {
      properties = current->GetPropertyNames();
    }

    // locate
    if (! properties.IsEmpty()) {
      size_t n = properties->Length();

      for (size_t i = 0;  i < n;  ++i) {
        v8::Handle<v8::Value> v = properties->Get(i);

        v8::String::Utf8Value str(v);
        char const* s = *str;

        if (s != 0) {
          string suffix = (current->Get(v)->IsFunction()) ? "()" : "";
          string name = path + s + suffix;

          if (*prefix == '\0' || TRI_IsPrefixString(s, prefix)) {
            result.push_back(name);
          }
        }
      }
    }

    currentIndex = 0;

    TRI_FreeString(prefix);
  }

  if (currentIndex < result.size()) {
    return TRI_DuplicateString(result[currentIndex++].c_str());
  }
  else {
    result.clear();
    return 0;
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief attempted completion
////////////////////////////////////////////////////////////////////////////////

static char** AttemptedCompletion (char const* text, int start, int end) {
  char** result;

  result = completion_matches(text, CompletionGenerator);
  rl_attempted_completion_over = true;

  if (result != 0 && result[0] != 0 && result[1] == 0) {
    size_t n = strlen(result[0]);

    if (result[0][n-1] == ')') {
      result[0][n-1] = '\0';

#if RL_READLINE_VERSION < 0x0500
      rl_completion_suppress_append = 1;
#endif
    }
  }

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks if javascript is missing a closing bracket
////////////////////////////////////////////////////////////////////////////////

static bool CheckJavaScript (string const& source) {
  char const* ptr;
  char const* end;
  int openParen;
  int openBrackets;
  int openBraces;

  enum {
    NORMAL,             // start
    NORMAL_1,           // from NORMAL: seen a single /
    DOUBLE_QUOTE,       // from NORMAL: seen a single "
    DOUBLE_QUOTE_ESC,   // from DOUBLE_QUOTE: seen a backslash
    SINGLE_QUOTE,       // from NORMAL: seen a single '
    SINGLE_QUOTE_ESC,   // from SINGLE_QUOTE: seen a backslash
    MULTI_COMMENT,      // from NORMAL_1: seen a *
    MULTI_COMMENT_1,    // from MULTI_COMMENT, seen a *
    SINGLE_COMMENT      // from NORMAL_1; seen a /
  }
  state;

  openParen = 0;
  openBrackets = 0;
  openBraces = 0;

  ptr = source.c_str();
  end = ptr + source.length();
  state = NORMAL;

  while (ptr < end) {
    if (state == DOUBLE_QUOTE) {
      if (*ptr == '\\') {
        state = DOUBLE_QUOTE_ESC;
      }
      else if (*ptr == '"') {
        state = NORMAL;
      }

      ++ptr;
    }
    else if (state == DOUBLE_QUOTE_ESC) {
      state = DOUBLE_QUOTE;
      ptr++;
    }
    else if (state == SINGLE_QUOTE) {
      if (*ptr == '\\') {
        state = SINGLE_QUOTE_ESC;
      }
      else if (*ptr == '\'') {
        state = NORMAL;
      }

      ++ptr;
    }
    else if (state == SINGLE_QUOTE_ESC) {
      state = SINGLE_QUOTE;
      ptr++;
    }
    else if (state == MULTI_COMMENT) {
      if (*ptr == '*') {
        state = MULTI_COMMENT_1;
      }

      ++ptr;
    }
    else if (state == MULTI_COMMENT_1) {
      if (*ptr == '/') {
        state = NORMAL;
      }

      ++ptr;
    }
    else if (state == SINGLE_COMMENT) {
      ++ptr;

      if (ptr == end) {
        state = NORMAL;
      }
    }
    else if (state == NORMAL_1) {
      switch (*ptr) {
        case '/':
          state = SINGLE_COMMENT;
          ++ptr;
          break;

        case '*':
          state = MULTI_COMMENT;
          ++ptr;
          break;

        default:
          state = NORMAL; // try again, do not change ptr
          break;
      }
    }
    else {
      switch (*ptr) {
        case '"':
          state = DOUBLE_QUOTE;
          break;

        case '\'':
          state = SINGLE_QUOTE;
          break;

        case '/':
          state = NORMAL_1;
          break;

        case '(':
          ++openParen;
          break;

        case ')':
          --openParen;
          break;

        case '[':
          ++openBrackets;
          break;

        case ']':
          --openBrackets;
          break;

        case '{':
          ++openBraces;
          break;

        case '}':
          --openBraces;
          break;
      }

      ++ptr;
    }
  }

  return openParen <= 0 && openBrackets <= 0 && openBraces <= 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8LineEditor
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new editor
////////////////////////////////////////////////////////////////////////////////

V8LineEditor::V8LineEditor (v8::Handle<v8::Context> context, string const& history)
  : _current(), _historyFilename(history), _context(context) {
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8LineEditor
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor open
////////////////////////////////////////////////////////////////////////////////

bool V8LineEditor::open (const bool autoComplete) {
  rl_initialize();

  if (autoComplete) {
    rl_attempted_completion_function = AttemptedCompletion;
    rl_completer_word_break_characters = WordBreakCharacters;

    rl_bind_key('\t', rl_complete);
  }

  using_history();
  stifle_history(MAX_HISTORY_ENTRIES);

  return read_history(getHistoryPath().c_str()) == 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor shutdown
////////////////////////////////////////////////////////////////////////////////

bool V8LineEditor::close () {
  bool result = write_history(getHistoryPath().c_str());

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief get the history file path
////////////////////////////////////////////////////////////////////////////////

string V8LineEditor::getHistoryPath () {
  string path;

  if (getenv("HOME")) {
    path.append(getenv("HOME"));
    path += '/';
  }

  path.append(_historyFilename);

  return path;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor prompt
////////////////////////////////////////////////////////////////////////////////

char* V8LineEditor::prompt (char const* prompt) {
  string dotdot;
  char const* p = prompt;
  size_t len1 = strlen(prompt);
  size_t len2 = len1;

  if (len1 < 3) {
    dotdot = "> ";
    len2 = 2;
  }
  else {
    dotdot = string(len1 - 2, '.') + "> ";
  }

  char const* sep = "";
  char* originalLine = 0;

  while (true) {
    char* result = readline(p);
    originalLine = result;
    p = dotdot.c_str();

    if (result == 0) {
      // give up, if the user pressed control-D on the top-most level
      if (_current.empty()) {
        return 0;
      }

      // otherwise clear current content
      _current.clear();
      break;
    }

    _current += sep;
    sep = "\n";

    bool c1 = strncmp(result, prompt, len1) == 0;
    bool c2 = strncmp(result, dotdot.c_str(), len2) == 0;

    while (c1 || c2) {
      if (c1) {
        result += len1;
      }
      else if (c2) {
        result += len2;
      }

      c1 = strncmp(result, prompt, len1) == 0;
      c2 = strncmp(result, dotdot.c_str(), len2) == 0;
    }

    _current += result;
    bool ok = CheckJavaScript(_current);

    if (ok) {
      break;
    }
    TRI_Free(originalLine);
  }

  char* line = TRI_DuplicateString(_current.c_str());
  _current.clear();

  // avoid memleaks
  if (originalLine != 0) {
    TRI_Free(originalLine);
  }

  return line;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add to history
////////////////////////////////////////////////////////////////////////////////

void V8LineEditor::addHistory (char const* str) {
  if (*str == '\0') {
    return;
  }

  history_set_pos(history_length-1);

  if (current_history()) {
    do {
      if (strcmp(current_history()->line, str) == 0) {
        remove_history(where_history());
        break;
      }
    }
    while (previous_history());
  }

  add_history(str);
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:
<|endoftext|>


<commit_before>/* This file is part of Zanshin Todo.

   Copyright 2008-2009 Kevin Ottens <ervin@kde.org>

   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 3 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 "sidebar.h"

#include <akonadi/collection.h>
#include <akonadi/item.h>
#include <akonadi/itemcreatejob.h>
#include <akonadi/itemdeletejob.h>
#include <akonadi/transactionsequence.h>

#include <boost/shared_ptr.hpp>

#include <kcal/todo.h>

#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KIcon>
#include <KDE/KInputDialog>
#include <KDE/KLocale>
#include <KDE/KMessageBox>

#include <QtGui/QStackedWidget>
#include <QtGui/QToolBar>
#include <QtGui/QTreeView>
#include <QtGui/QVBoxLayout>

#include "contextsmodel.h"
#include "globalmodel.h"
#include "librarymodel.h"
#include "projectsmodel.h"
#include "todoflatmodel.h"
#include "todotreemodel.h"

typedef boost::shared_ptr<KCal::Incidence> IncidencePtr;

SideBar::SideBar(QWidget *parent, KActionCollection *ac)
    : QWidget(parent)
{
    setupActions(ac);

    setLayout(new QVBoxLayout(this));
    m_stack = new QStackedWidget(this);
    layout()->addWidget(m_stack);

    setupProjectPage();
    setupContextPage();
}

void SideBar::setupProjectPage()
{
    QWidget *projectPage = new QWidget(m_stack);
    projectPage->setLayout(new QVBoxLayout(projectPage));

    m_projectTree = new QTreeView(projectPage);
    projectPage->layout()->addWidget(m_projectTree);
    m_projectTree->setAnimated(true);
    m_projectTree->setModel(GlobalModel::projectsLibrary());
    m_projectTree->setSelectionMode(QAbstractItemView::SingleSelection);
    m_projectTree->setDragEnabled(true);
    m_projectTree->viewport()->setAcceptDrops(true);
    m_projectTree->setDropIndicatorShown(true);
    m_projectTree->setCurrentIndex(m_projectTree->model()->index(0, 0));
    connect(m_projectTree->model(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
            m_projectTree, SLOT(expand(const QModelIndex&)));
    connect(m_projectTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SIGNAL(projectChanged(QModelIndex)));
    connect(m_projectTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(updateActions(QModelIndex)));

    QToolBar *projectBar = new QToolBar(projectPage);
    projectPage->layout()->addWidget(projectBar);
    projectBar->addAction(m_add);
    projectBar->addAction(m_remove);
    projectBar->addAction(m_addFolder);

    m_stack->addWidget(projectPage);
}

void SideBar::setupContextPage()
{
    QWidget *contextPage = new QWidget(m_stack);
    contextPage->setLayout(new QVBoxLayout(contextPage));

    m_contextTree = new QTreeView(contextPage);
    contextPage->layout()->addWidget(m_contextTree);
    m_contextTree->setAnimated(true);
    m_contextTree->setModel(GlobalModel::contextsLibrary());
    m_contextTree->setSelectionMode(QAbstractItemView::SingleSelection);
    m_contextTree->setDragEnabled(true);
    m_contextTree->viewport()->setAcceptDrops(true);
    m_contextTree->setDropIndicatorShown(true);
    m_contextTree->setCurrentIndex(m_contextTree->model()->index(0, 0));
    connect(m_contextTree->model(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
            m_contextTree, SLOT(expand(const QModelIndex&)));
    connect(m_contextTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SIGNAL(contextChanged(QModelIndex)));
    connect(m_contextTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(updateActions(QModelIndex)));

    QToolBar *contextBar = new QToolBar(contextPage);
    contextPage->layout()->addWidget(contextBar);
    contextBar->addAction(m_add);
    contextBar->addAction(m_remove);

    m_stack->addWidget(contextPage);
}

void SideBar::setupActions(KActionCollection *ac)
{
    m_addFolder = ac->addAction("sidebar_new_folder", this, SLOT(onAddFolder()));
    m_addFolder->setText(i18n("New Folder"));
    m_addFolder->setIcon(KIcon("folder-new"));

    m_add = ac->addAction("sidebar_new", this, SLOT(onAddItem()));
    m_add->setText(i18n("New"));
    m_add->setIcon(KIcon("list-add"));

    m_remove = ac->addAction("sidebar_remove", this, SLOT(onRemoveItem()));
    m_remove->setText(i18n("Remove"));
    m_remove->setIcon(KIcon("list-remove"));
}

void SideBar::switchToProjectMode()
{
    m_stack->setCurrentIndex(ProjectPageIndex);
    m_add->setText("New Project");
    m_remove->setText("Remove Project/Folder");
    updateActions(m_projectTree->currentIndex());
    emit projectChanged(m_projectTree->currentIndex());
}

void SideBar::switchToContextMode()
{
    m_stack->setCurrentIndex(ContextPageIndex);
    m_add->setText("New Context");
    m_remove->setText("Remove Context");
    updateActions(m_contextTree->currentIndex());
    emit contextChanged(m_contextTree->currentIndex());
}

void SideBar::updateActions(const QModelIndex &index)
{
    const LibraryModel *model = qobject_cast<const LibraryModel*>(index.model());;

    if (model==GlobalModel::projectsLibrary()) {
        m_addFolder->setEnabled(true);
    } else {
        m_addFolder->setEnabled(false);
    }

    if (model->isInbox(index)) {
        m_addFolder->setEnabled(false);
        m_add->setEnabled(false);
        m_remove->setEnabled(false);
    } else {
        m_add->setEnabled(true);
        m_remove->setEnabled(!model->isLibraryRoot(index));

        QModelIndex sourceIndex = model->mapToSource(index); // into "projects"
        if (m_addFolder->isEnabled() && sourceIndex.isValid()) { // Shouldn't be enabled on projects
            sourceIndex = GlobalModel::projects()->mapToSource(sourceIndex); // into "todoTree"
            sourceIndex = sourceIndex.sibling(sourceIndex.row(), TodoFlatModel::RowType); // we want the row type
            if (GlobalModel::todoTree()->data(sourceIndex).toInt()!=TodoFlatModel::FolderTodo) {
                m_addFolder->setEnabled(false);
                m_add->setEnabled(false);
            }
        }
    }
}

void SideBar::onAddFolder()
{
    bool ok;
    QString summary = KInputDialog::getText(i18n("New Folder"),
                                            i18n("Enter folder name:"),
                                            QString(), &ok, this);
    summary = summary.trimmed();

    if (!ok || summary.isEmpty()) return;

    QModelIndex parent = m_projectTree->currentIndex();
    parent = GlobalModel::projectsLibrary()->mapToSource(parent);
    parent = GlobalModel::projects()->mapToSource(parent);
    parent = parent.sibling(parent.row(), TodoFlatModel::RemoteId);

    QString parentRemoteId = GlobalModel::todoTree()->data(parent).toString();

    KCal::Todo *todo = new KCal::Todo();
    todo->setSummary(summary);
    todo->addComment("X-Zanshin-Folder");

    if (!parentRemoteId.isEmpty()) {
        todo->setRelatedToUid(parentRemoteId);
    }

    IncidencePtr incidence(todo);
    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<IncidencePtr>(incidence);

    Akonadi::Collection collection = GlobalModel::todoFlat()->collection();
    Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob(item, collection);
    job->start();
}

void SideBar::onAddItem()
{
    switch (m_stack->currentIndex()) {
    case ProjectPageIndex:
        addNewProject();
        break;
    case ContextPageIndex:
        addNewContext();
        break;
    default:
        Q_ASSERT(false);
    }
}

void SideBar::onRemoveItem()
{
    switch (m_stack->currentIndex()) {
    case ProjectPageIndex:
        removeCurrentProject();
        break;
    case ContextPageIndex:
        removeCurrentContext();
        break;
    default:
        Q_ASSERT(false);
    }
}

void SideBar::addNewProject()
{
    bool ok;
    QString summary = KInputDialog::getText(i18n("New Project"),
                                            i18n("Enter project name:"),
                                            QString(), &ok, this);
    summary = summary.trimmed();

    if (!ok || summary.isEmpty()) return;

    QModelIndex parent = m_projectTree->currentIndex();
    parent = GlobalModel::projectsLibrary()->mapToSource(parent);
    parent = GlobalModel::projects()->mapToSource(parent);
    parent = parent.sibling(parent.row(), TodoFlatModel::RemoteId);

    QString parentRemoteId = GlobalModel::todoTree()->data(parent).toString();

    KCal::Todo *todo = new KCal::Todo();
    todo->setSummary(summary);
    todo->addComment("X-Zanshin-Project");

    if (!parentRemoteId.isEmpty()) {
        todo->setRelatedToUid(parentRemoteId);
    }

    IncidencePtr incidence(todo);
    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<IncidencePtr>(incidence);

    Akonadi::Collection collection = GlobalModel::todoFlat()->collection();
    Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob(item, collection);
    job->start();
}

void addDeleteTodoJobsHelper(const QModelIndex &index, Akonadi::TransactionSequence *transaction)
{
    for (int i=0; i<GlobalModel::todoTree()->rowCount(index); i++) {
        addDeleteTodoJobsHelper(index.child(i, 0), transaction);
    }

    Akonadi::Item item = GlobalModel::todoTree()->itemForIndex(index);
    new Akonadi::ItemDeleteJob(item, transaction);
}

void SideBar::removeCurrentProject()
{
    QModelIndex current = m_projectTree->currentIndex();
    current = GlobalModel::projectsLibrary()->mapToSource(current);
    current = GlobalModel::projects()->mapToSource(current);
    current = current.sibling(current.row(), 0);

    bool canRemove = true;

    if (GlobalModel::todoTree()->rowCount(current)>0) {
        QString summary = GlobalModel::todoTree()->data(current).toString();
        int rowType = GlobalModel::todoTree()->data(current.sibling(current.row(), TodoFlatModel::RowType)).toInt();
        QString message;
        QString caption;
        if (rowType==TodoFlatModel::FolderTodo) {
            message = i18n("Do you really want to delete the folder '%1', with all its projects and actions?", summary);
            caption = i18n("Delete Folder");
        } else {
            message = i18n("Do you really want to delete the project '%1', with all its actions?", summary);
            caption = i18n("Delete Project");
        }
        int button = KMessageBox::questionYesNo(this, message, caption);

        canRemove = (button==KMessageBox::Yes);
    }

    if (!canRemove) return;

    Akonadi::TransactionSequence *transaction = new Akonadi::TransactionSequence();
    addDeleteTodoJobsHelper(current, transaction);
    transaction->start();
}

void SideBar::addNewContext()
{

}

void SideBar::removeCurrentContext()
{

}
<commit_msg>Allow to create new contexts in the sidebar.<commit_after>/* This file is part of Zanshin Todo.

   Copyright 2008-2009 Kevin Ottens <ervin@kde.org>

   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 3 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 "sidebar.h"

#include <akonadi/collection.h>
#include <akonadi/item.h>
#include <akonadi/itemcreatejob.h>
#include <akonadi/itemdeletejob.h>
#include <akonadi/transactionsequence.h>

#include <boost/shared_ptr.hpp>

#include <kcal/todo.h>

#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KIcon>
#include <KDE/KInputDialog>
#include <KDE/KLocale>
#include <KDE/KMessageBox>

#include <QtGui/QStackedWidget>
#include <QtGui/QToolBar>
#include <QtGui/QTreeView>
#include <QtGui/QVBoxLayout>

#include "contextsmodel.h"
#include "globalmodel.h"
#include "librarymodel.h"
#include "projectsmodel.h"
#include "todocategoriesmodel.h"
#include "todoflatmodel.h"
#include "todotreemodel.h"

typedef boost::shared_ptr<KCal::Incidence> IncidencePtr;

SideBar::SideBar(QWidget *parent, KActionCollection *ac)
    : QWidget(parent)
{
    setupActions(ac);

    setLayout(new QVBoxLayout(this));
    m_stack = new QStackedWidget(this);
    layout()->addWidget(m_stack);

    setupProjectPage();
    setupContextPage();
}

void SideBar::setupProjectPage()
{
    QWidget *projectPage = new QWidget(m_stack);
    projectPage->setLayout(new QVBoxLayout(projectPage));

    m_projectTree = new QTreeView(projectPage);
    projectPage->layout()->addWidget(m_projectTree);
    m_projectTree->setAnimated(true);
    m_projectTree->setModel(GlobalModel::projectsLibrary());
    m_projectTree->setSelectionMode(QAbstractItemView::SingleSelection);
    m_projectTree->setDragEnabled(true);
    m_projectTree->viewport()->setAcceptDrops(true);
    m_projectTree->setDropIndicatorShown(true);
    m_projectTree->setCurrentIndex(m_projectTree->model()->index(0, 0));
    connect(m_projectTree->model(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
            m_projectTree, SLOT(expand(const QModelIndex&)));
    connect(m_projectTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SIGNAL(projectChanged(QModelIndex)));
    connect(m_projectTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(updateActions(QModelIndex)));

    QToolBar *projectBar = new QToolBar(projectPage);
    projectPage->layout()->addWidget(projectBar);
    projectBar->addAction(m_add);
    projectBar->addAction(m_remove);
    projectBar->addAction(m_addFolder);

    m_stack->addWidget(projectPage);
}

void SideBar::setupContextPage()
{
    QWidget *contextPage = new QWidget(m_stack);
    contextPage->setLayout(new QVBoxLayout(contextPage));

    m_contextTree = new QTreeView(contextPage);
    contextPage->layout()->addWidget(m_contextTree);
    m_contextTree->setAnimated(true);
    m_contextTree->setModel(GlobalModel::contextsLibrary());
    m_contextTree->setSelectionMode(QAbstractItemView::SingleSelection);
    m_contextTree->setDragEnabled(true);
    m_contextTree->viewport()->setAcceptDrops(true);
    m_contextTree->setDropIndicatorShown(true);
    m_contextTree->setCurrentIndex(m_contextTree->model()->index(0, 0));
    connect(m_contextTree->model(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
            m_contextTree, SLOT(expand(const QModelIndex&)));
    connect(m_contextTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SIGNAL(contextChanged(QModelIndex)));
    connect(m_contextTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(updateActions(QModelIndex)));

    QToolBar *contextBar = new QToolBar(contextPage);
    contextPage->layout()->addWidget(contextBar);
    contextBar->addAction(m_add);
    contextBar->addAction(m_remove);

    m_stack->addWidget(contextPage);
}

void SideBar::setupActions(KActionCollection *ac)
{
    m_addFolder = ac->addAction("sidebar_new_folder", this, SLOT(onAddFolder()));
    m_addFolder->setText(i18n("New Folder"));
    m_addFolder->setIcon(KIcon("folder-new"));

    m_add = ac->addAction("sidebar_new", this, SLOT(onAddItem()));
    m_add->setText(i18n("New"));
    m_add->setIcon(KIcon("list-add"));

    m_remove = ac->addAction("sidebar_remove", this, SLOT(onRemoveItem()));
    m_remove->setText(i18n("Remove"));
    m_remove->setIcon(KIcon("list-remove"));
}

void SideBar::switchToProjectMode()
{
    m_stack->setCurrentIndex(ProjectPageIndex);
    m_add->setText("New Project");
    m_remove->setText("Remove Project/Folder");
    updateActions(m_projectTree->currentIndex());
    emit projectChanged(m_projectTree->currentIndex());
}

void SideBar::switchToContextMode()
{
    m_stack->setCurrentIndex(ContextPageIndex);
    m_add->setText("New Context");
    m_remove->setText("Remove Context");
    updateActions(m_contextTree->currentIndex());
    emit contextChanged(m_contextTree->currentIndex());
}

void SideBar::updateActions(const QModelIndex &index)
{
    const LibraryModel *model = qobject_cast<const LibraryModel*>(index.model());;

    if (model==GlobalModel::projectsLibrary()) {
        m_addFolder->setEnabled(true);
    } else {
        m_addFolder->setEnabled(false);
    }

    if (model->isInbox(index)) {
        m_addFolder->setEnabled(false);
        m_add->setEnabled(false);
        m_remove->setEnabled(false);
    } else {
        m_add->setEnabled(true);
        m_remove->setEnabled(!model->isLibraryRoot(index));

        QModelIndex sourceIndex = model->mapToSource(index); // into "projects"
        if (m_addFolder->isEnabled() && sourceIndex.isValid()) { // Shouldn't be enabled on projects
            sourceIndex = GlobalModel::projects()->mapToSource(sourceIndex); // into "todoTree"
            sourceIndex = sourceIndex.sibling(sourceIndex.row(), TodoFlatModel::RowType); // we want the row type
            if (GlobalModel::todoTree()->data(sourceIndex).toInt()!=TodoFlatModel::FolderTodo) {
                m_addFolder->setEnabled(false);
                m_add->setEnabled(false);
            }
        }
    }
}

void SideBar::onAddFolder()
{
    bool ok;
    QString summary = KInputDialog::getText(i18n("New Folder"),
                                            i18n("Enter folder name:"),
                                            QString(), &ok, this);
    summary = summary.trimmed();

    if (!ok || summary.isEmpty()) return;

    QModelIndex parent = m_projectTree->currentIndex();
    parent = GlobalModel::projectsLibrary()->mapToSource(parent);
    parent = GlobalModel::projects()->mapToSource(parent);
    parent = parent.sibling(parent.row(), TodoFlatModel::RemoteId);

    QString parentRemoteId = GlobalModel::todoTree()->data(parent).toString();

    KCal::Todo *todo = new KCal::Todo();
    todo->setSummary(summary);
    todo->addComment("X-Zanshin-Folder");

    if (!parentRemoteId.isEmpty()) {
        todo->setRelatedToUid(parentRemoteId);
    }

    IncidencePtr incidence(todo);
    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<IncidencePtr>(incidence);

    Akonadi::Collection collection = GlobalModel::todoFlat()->collection();
    Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob(item, collection);
    job->start();
}

void SideBar::onAddItem()
{
    switch (m_stack->currentIndex()) {
    case ProjectPageIndex:
        addNewProject();
        break;
    case ContextPageIndex:
        addNewContext();
        break;
    default:
        Q_ASSERT(false);
    }
}

void SideBar::onRemoveItem()
{
    switch (m_stack->currentIndex()) {
    case ProjectPageIndex:
        removeCurrentProject();
        break;
    case ContextPageIndex:
        removeCurrentContext();
        break;
    default:
        Q_ASSERT(false);
    }
}

void SideBar::addNewProject()
{
    bool ok;
    QString summary = KInputDialog::getText(i18n("New Project"),
                                            i18n("Enter project name:"),
                                            QString(), &ok, this);
    summary = summary.trimmed();

    if (!ok || summary.isEmpty()) return;

    QModelIndex parent = m_projectTree->currentIndex();
    parent = GlobalModel::projectsLibrary()->mapToSource(parent);
    parent = GlobalModel::projects()->mapToSource(parent);
    parent = parent.sibling(parent.row(), TodoFlatModel::RemoteId);

    QString parentRemoteId = GlobalModel::todoTree()->data(parent).toString();

    KCal::Todo *todo = new KCal::Todo();
    todo->setSummary(summary);
    todo->addComment("X-Zanshin-Project");

    if (!parentRemoteId.isEmpty()) {
        todo->setRelatedToUid(parentRemoteId);
    }

    IncidencePtr incidence(todo);
    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<IncidencePtr>(incidence);

    Akonadi::Collection collection = GlobalModel::todoFlat()->collection();
    Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob(item, collection);
    job->start();
}

void addDeleteTodoJobsHelper(const QModelIndex &index, Akonadi::TransactionSequence *transaction)
{
    for (int i=0; i<GlobalModel::todoTree()->rowCount(index); i++) {
        addDeleteTodoJobsHelper(index.child(i, 0), transaction);
    }

    Akonadi::Item item = GlobalModel::todoTree()->itemForIndex(index);
    new Akonadi::ItemDeleteJob(item, transaction);
}

void SideBar::removeCurrentProject()
{
    QModelIndex current = m_projectTree->currentIndex();
    current = GlobalModel::projectsLibrary()->mapToSource(current);
    current = GlobalModel::projects()->mapToSource(current);
    current = current.sibling(current.row(), 0);

    bool canRemove = true;

    if (GlobalModel::todoTree()->rowCount(current)>0) {
        QString summary = GlobalModel::todoTree()->data(current).toString();
        int rowType = GlobalModel::todoTree()->data(current.sibling(current.row(), TodoFlatModel::RowType)).toInt();
        QString message;
        QString caption;
        if (rowType==TodoFlatModel::FolderTodo) {
            message = i18n("Do you really want to delete the folder '%1', with all its projects and actions?", summary);
            caption = i18n("Delete Folder");
        } else {
            message = i18n("Do you really want to delete the project '%1', with all its actions?", summary);
            caption = i18n("Delete Project");
        }
        int button = KMessageBox::questionYesNo(this, message, caption);

        canRemove = (button==KMessageBox::Yes);
    }

    if (!canRemove) return;

    Akonadi::TransactionSequence *transaction = new Akonadi::TransactionSequence();
    addDeleteTodoJobsHelper(current, transaction);
    transaction->start();
}

void SideBar::addNewContext()
{
    bool ok;
    QString summary = KInputDialog::getText(i18n("New Context"),
                                            i18n("Enter context name:"),
                                            QString(), &ok, this);
    summary = summary.trimmed();

    if (!ok || summary.isEmpty()) return;

    QModelIndex parent = m_contextTree->currentIndex();
    parent = GlobalModel::contextsLibrary()->mapToSource(parent);
    parent = GlobalModel::contexts()->mapToSource(parent);
    parent = parent.sibling(parent.row(), TodoFlatModel::Summary);

    GlobalModel::todoCategories()->addCategory(summary, parent);
}

void SideBar::removeCurrentContext()
{

}
<|endoftext|>