<commit_before>/////////////////////////////////////////////////////////////////////////
//
// 'Limit Example' RooStats tutorial macro #101
// author: Kyle Cranmer
// date June. 2009
//
// This tutorial shows an example of creating a simple
// model for a number counting experiment with uncertainty
// on both the background rate and signal efficeincy. We then
// use a Confidence Interval Calculator to set a limit on the signal.
//
//
/////////////////////////////////////////////////////////////////////////

#ifndef __CINT__
#include "RooGlobalFunc.h"
#endif

#include "RooProfileLL.h"
#include "RooAbsPdf.h"
#include "RooStats/HypoTestResult.h"
#include "RooRealVar.h"
#include "RooPlot.h"
#include "RooDataSet.h"
#include "RooTreeDataStore.h"
#include "TTree.h"
#include "TCanvas.h"
#include "TLine.h"
#include "TStopwatch.h"

#include "RooStats/ProfileLikelihoodCalculator.h"
#include "RooStats/MCMCCalculator.h"
#include "RooStats/UniformProposal.h"
#include "RooStats/FeldmanCousins.h"
#include "RooStats/NumberCountingPdfFactory.h"
#include "RooStats/ConfInterval.h"
#include "RooStats/PointSetInterval.h"
#include "RooStats/LikelihoodInterval.h"
#include "RooStats/LikelihoodIntervalPlot.h"
#include "RooStats/RooStatsUtils.h"

// use this order for safety on library loading
using namespace RooFit ;
using namespace RooStats ;

void rs101_limitexample()
{
  /////////////////////////////////////////
  // An example of setting a limit in a number counting experiment with uncertainty on background and signal
  /////////////////////////////////////////

  // to time the macro
  TStopwatch t;
  t.Start();

  /////////////////////////////////////////
  // The Model building stage
  /////////////////////////////////////////
  RooWorkspace* wspace = new RooWorkspace();
  wspace->factory("Poisson::countingModel(obs[150,0,300], sum(s[50,0,120]*ratioSigEff[1.,0,2.],b[100,0,300]*ratioBkgEff[1.,0.,2.]))"); // counting model
  wspace->factory("Gaussian::sigConstraint(ratioSigEff,1,0.05)"); // 5% signal efficiency uncertainty
  wspace->factory("Gaussian::bkgConstraint(ratioBkgEff,1,0.1)"); // 10% background efficiency uncertainty
  wspace->factory("PROD::modelWithConstraints(countingModel,sigConstraint,bkgConstraint)"); // product of terms
  wspace->Print();

  RooAbsPdf* modelWithConstraints = wspace->pdf("modelWithConstraints"); // get the model
  RooRealVar* obs = wspace->var("obs"); // get the observable
  RooRealVar* s = wspace->var("s"); // get the signal we care about
  RooRealVar* b = wspace->var("b"); // get the background and set it to a constant.  Uncertainty included in ratioBkgEff
  b->setConstant();
  RooRealVar* ratioSigEff = wspace->var("ratioSigEff"); // get uncertaint parameter to constrain
  RooRealVar* ratioBkgEff = wspace->var("ratioBkgEff"); // get uncertaint parameter to constrain
  RooArgSet constrainedParams(*ratioSigEff, *ratioBkgEff); // need to constrain these in the fit (should change default behavior)

  // Create an example dataset with 160 observed events
  obs->setVal(160.);
  RooDataSet* data = new RooDataSet("exampleData", "exampleData", RooArgSet(*obs));
  data->add(*obs);

  RooArgSet all(*s, *ratioBkgEff, *ratioSigEff);

  // not necessary
  modelWithConstraints->fitTo(*data, RooFit::Constrain(RooArgSet(*ratioSigEff, *ratioBkgEff)));

  // Now let's make some confidence intervals for s, our parameter of interest
  RooArgSet paramOfInterest(*s);

  // First, let's use a Calculator based on the Profile Likelihood Ratio
  ProfileLikelihoodCalculator plc(*data, *modelWithConstraints, paramOfInterest);
  plc.SetTestSize(.1);
  ConfInterval* lrint = plc.GetInterval();  // that was easy.

  // Second, use a Calculator based on the Feldman Cousins technique
  FeldmanCousins fc;
  fc.SetPdf(*modelWithConstraints);
  fc.SetData(*data);
  fc.SetParameters( paramOfInterest );
  fc.UseAdaptiveSampling(true);
  fc.FluctuateNumDataEntries(false); // number counting analysis: dataset always has 1 entry with N events observed
  fc.SetNBins(100); // number of points to test per parameter
  fc.SetTestSize(.1);
  //  fc.SaveBeltToFile(true); // optional
  ConfInterval* fcint = NULL;
  fcint = fc.GetInterval();  // that was easy.

  // Third, use a Calculator based on Markov Chain monte carlo
  UniformProposal up;
  MCMCCalculator mc;
  mc.SetPdf(*modelWithConstraints);
  mc.SetData(*data);
  mc.SetParameters(paramOfInterest);
  mc.SetProposalFunction(up);
  mc.SetNumIters(100000); // steps in the chain
  mc.SetTestSize(.1); // 90% CL
  mc.SetNumBins(50); // used in posterior histogram
  mc.SetNumBurnInSteps(40); // ignore first steps in chain due to "burn in"
  ConfInterval* mcmcint = NULL;
  mcmcint = mc.GetInterval();

  // Let's make a plot
  TCanvas* dataCanvas = new TCanvas("dataCanvas");
  dataCanvas->Divide(2,1);

  dataCanvas->cd(1);
  LikelihoodIntervalPlot plotInt((LikelihoodInterval*)lrint);
  plotInt.SetTitle("Profile Likelihood Ratio and Posterior for S");
  plotInt.Draw();

  // draw posterior
  TH1* posterior = ((MCMCInterval*)mcmcint)->GetPosteriorHist();
  posterior->Scale(1/posterior->GetBinContent(posterior->GetMaximumBin())); // scale so highest bin has y=1.
  posterior->Draw("same");

  // Get Lower and Upper limits from Profile Calculator
  cout << "Profile lower limit on s = " << ((LikelihoodInterval*) lrint)->LowerLimit(*s) << endl;
  cout << "Profile upper limit on s = " << ((LikelihoodInterval*) lrint)->UpperLimit(*s) << endl;

  // Get Lower and Upper limits from FeldmanCousins with profile construction
  if (fcint != NULL) {
     double fcul = ((PointSetInterval*) fcint)->UpperLimit(*s);
     double fcll = ((PointSetInterval*) fcint)->LowerLimit(*s);
     cout << "FC lower limit on s = " << fcll << endl;
     cout << "FC upper limit on s = " << fcul << endl;
     TLine* fcllLine = new TLine(fcll, 0, fcll, 1);
     TLine* fculLine = new TLine(fcul, 0, fcul, 1);
     fcllLine->SetLineColor(kRed);
     fculLine->SetLineColor(kRed);
     fcllLine->Draw("same");
     fculLine->Draw("same");
     dataCanvas->Update();
  }

  // Get Lower and Upper limits from MCMC
  double mcul = ((MCMCInterval*) mcmcint)->UpperLimit(*s);
  double mcll = ((MCMCInterval*) mcmcint)->LowerLimit(*s);
  cout << "MCMC lower limit on s = " << mcll << endl;
  cout << "MCMC upper limit on s = " << mcul << endl;
  TLine* mcllLine = new TLine(mcll, 0, mcll, 1);
  TLine* mculLine = new TLine(mcul, 0, mcul, 1);
  mcllLine->SetLineColor(kMagenta);
  mculLine->SetLineColor(kMagenta);
  mcllLine->Draw("same");
  mculLine->Draw("same");
  dataCanvas->Update();

  // 3-d plot of the parameter points
  dataCanvas->cd(2);
  // also plot the points in the markov chain
  TTree& chain =  ((RooTreeDataStore*) ((MCMCInterval*)mcmcint)->GetChain()->GetAsConstDataSet())->tree();
  chain.SetMarkerStyle(6);
  chain.SetMarkerColor(kRed);
  chain.Draw("s:ratioSigEff:ratioBkgEff","w","box"); // 3-d box proporional to posterior

  // the points used in the profile construction
  TTree& parameterScan =  ((RooTreeDataStore*) fc.GetPointsToScan()->store())->tree();
  parameterScan.SetMarkerStyle(24);
  parameterScan.Draw("s:ratioSigEff:ratioBkgEff","","same");

  delete wspace;
  delete lrint;
  if (fcint != NULL) delete fcint;
  delete data;

  /// print timing info
  t.Stop();
  t.Print();
}
<commit_msg>new attempt to fic tutorial<commit_after>/////////////////////////////////////////////////////////////////////////
//
// 'Limit Example' RooStats tutorial macro #101
// author: Kyle Cranmer
// date June. 2009
//
// This tutorial shows an example of creating a simple
// model for a number counting experiment with uncertainty
// on both the background rate and signal efficeincy. We then
// use a Confidence Interval Calculator to set a limit on the signal.
//
//
/////////////////////////////////////////////////////////////////////////

#ifndef __CINT__
#include "RooGlobalFunc.h"
#endif

#include "RooProfileLL.h"
#include "RooAbsPdf.h"
#include "RooStats/HypoTestResult.h"
#include "RooRealVar.h"
#include "RooPlot.h"
#include "RooDataSet.h"
#include "RooTreeDataStore.h"
#include "TTree.h"
#include "TCanvas.h"
#include "TLine.h"
#include "TStopwatch.h"

#include "RooStats/ProfileLikelihoodCalculator.h"
#include "RooStats/MCMCCalculator.h"
#include "RooStats/UniformProposal.h"
#include "RooStats/FeldmanCousins.h"
#include "RooStats/NumberCountingPdfFactory.h"
#include "RooStats/ConfInterval.h"
#include "RooStats/PointSetInterval.h"
#include "RooStats/LikelihoodInterval.h"
#include "RooStats/LikelihoodIntervalPlot.h"
#include "RooStats/RooStatsUtils.h"

// use this order for safety on library loading
using namespace RooFit ;
using namespace RooStats ;

void rs101_limitexample()
{
  /////////////////////////////////////////
  // An example of setting a limit in a number counting experiment with uncertainty on background and signal
  /////////////////////////////////////////

  // to time the macro
  TStopwatch t;
  t.Start();

  /////////////////////////////////////////
  // The Model building stage
  /////////////////////////////////////////
  RooWorkspace* wspace = new RooWorkspace();
  wspace->factory("Poisson::countingModel(obs[150,0,300], sum(s[50,0,120]*ratioSigEff[1.,0,2.],b[100,0,300]*ratioBkgEff[1.,0.,2.]))"); // counting model
  wspace->factory("Gaussian::sigConstraint(ratioSigEff,1,0.05)"); // 5% signal efficiency uncertainty
  wspace->factory("Gaussian::bkgConstraint(ratioBkgEff,1,0.1)"); // 10% background efficiency uncertainty
  wspace->factory("PROD::modelWithConstraints(countingModel,sigConstraint,bkgConstraint)"); // product of terms
  wspace->Print();

  RooAbsPdf* modelWithConstraints = wspace->pdf("modelWithConstraints"); // get the model
  RooRealVar* obs = wspace->var("obs"); // get the observable
  RooRealVar* s = wspace->var("s"); // get the signal we care about
  RooRealVar* b = wspace->var("b"); // get the background and set it to a constant.  Uncertainty included in ratioBkgEff
  b->setConstant();
  RooRealVar* ratioSigEff = wspace->var("ratioSigEff"); // get uncertaint parameter to constrain
  RooRealVar* ratioBkgEff = wspace->var("ratioBkgEff"); // get uncertaint parameter to constrain
  RooArgSet constrainedParams(*ratioSigEff, *ratioBkgEff); // need to constrain these in the fit (should change default behavior)

  // Create an example dataset with 160 observed events
  obs->setVal(160.);
  RooDataSet* data = new RooDataSet("exampleData", "exampleData", RooArgSet(*obs));
  data->add(*obs);

  RooArgSet all(*s, *ratioBkgEff, *ratioSigEff);

  // not necessary
  modelWithConstraints->fitTo(*data, RooFit::Constrain(RooArgSet(*ratioSigEff, *ratioBkgEff)));

  // Now let's make some confidence intervals for s, our parameter of interest
  RooArgSet paramOfInterest(*s);

  // First, let's use a Calculator based on the Profile Likelihood Ratio
  ProfileLikelihoodCalculator plc(*data, *modelWithConstraints, paramOfInterest);
  plc.SetTestSize(.1);
  ConfInterval* lrint = plc.GetInterval();  // that was easy.

  // Second, use a Calculator based on the Feldman Cousins technique
  FeldmanCousins fc;
  fc.SetPdf(*modelWithConstraints);
  fc.SetData(*data);
  fc.SetParameters( paramOfInterest );
  fc.UseAdaptiveSampling(true);
  fc.FluctuateNumDataEntries(false); // number counting analysis: dataset always has 1 entry with N events observed
  fc.SetNBins(100); // number of points to test per parameter
  fc.SetTestSize(.1);
  //  fc.SaveBeltToFile(true); // optional
  ConfInterval* fcint = NULL;
  fcint = fc.GetInterval();  // that was easy.

  // Third, use a Calculator based on Markov Chain monte carlo
  UniformProposal up;
  MCMCCalculator mc;
  mc.SetPdf(*modelWithConstraints);
  mc.SetData(*data);
  mc.SetParameters(paramOfInterest);
  mc.SetProposalFunction(up);
  mc.SetNumIters(100000); // steps in the chain
  mc.SetTestSize(.1); // 90% CL
  mc.SetNumBins(50); // used in posterior histogram
  mc.SetNumBurnInSteps(40); // ignore first steps in chain due to "burn in"
  ConfInterval* mcmcint = NULL;
  mcmcint = mc.GetInterval();

  // Let's make a plot
  TCanvas* dataCanvas = new TCanvas("dataCanvas");
  dataCanvas->Divide(2,1);

  dataCanvas->cd(1);
  LikelihoodIntervalPlot plotInt((LikelihoodInterval*)lrint);
  plotInt.SetTitle("Profile Likelihood Ratio and Posterior for S");
  plotInt.Draw();

  // draw posterior
  TH1* posterior = ((MCMCInterval*)mcmcint)->GetPosteriorHist();
  posterior->Scale(1/posterior->GetBinContent(posterior->GetMaximumBin())); // scale so highest bin has y=1.
  posterior->Draw("same");

  // Get Lower and Upper limits from Profile Calculator
  cout << "Profile lower limit on s = " << ((LikelihoodInterval*) lrint)->LowerLimit(*s) << endl;
  cout << "Profile upper limit on s = " << ((LikelihoodInterval*) lrint)->UpperLimit(*s) << endl;

  // Get Lower and Upper limits from FeldmanCousins with profile construction
  if (fcint != NULL) {
     double fcul = ((PointSetInterval*) fcint)->UpperLimit(*s);
     double fcll = ((PointSetInterval*) fcint)->LowerLimit(*s);
     cout << "FC lower limit on s = " << fcll << endl;
     cout << "FC upper limit on s = " << fcul << endl;
     TLine* fcllLine = new TLine(fcll, 0, fcll, 1);
     TLine* fculLine = new TLine(fcul, 0, fcul, 1);
     fcllLine->SetLineColor(kRed);
     fculLine->SetLineColor(kRed);
     fcllLine->Draw("same");
     fculLine->Draw("same");
     dataCanvas->Update();
  }

  // Get Lower and Upper limits from MCMC
  double mcul = ((MCMCInterval*) mcmcint)->UpperLimit(*s);
  double mcll = ((MCMCInterval*) mcmcint)->LowerLimit(*s);
  cout << "MCMC lower limit on s = " << mcll << endl;
  cout << "MCMC upper limit on s = " << mcul << endl;
  TLine* mcllLine = new TLine(mcll, 0, mcll, 1);
  TLine* mculLine = new TLine(mcul, 0, mcul, 1);
  mcllLine->SetLineColor(kMagenta);
  mculLine->SetLineColor(kMagenta);
  mcllLine->Draw("same");
  mculLine->Draw("same");
  dataCanvas->Update();

  // 3-d plot of the parameter points
  dataCanvas->cd(2);
  // also plot the points in the markov chain
  TTree& chain =  ((RooTreeDataStore*) ((MCMCInterval*)mcmcint)->GetChainAsDataSet()->store())->tree();
  chain.SetMarkerStyle(6);
  chain.SetMarkerColor(kRed);
  chain.Draw("s:ratioSigEff:ratioBkgEff","w","box"); // 3-d box proporional to posterior

  // the points used in the profile construction
  TTree& parameterScan =  ((RooTreeDataStore*) fc.GetPointsToScan()->store())->tree();
  parameterScan.SetMarkerStyle(24);
  parameterScan.Draw("s:ratioSigEff:ratioBkgEff","","same");

  delete wspace;
  delete lrint;
  if (fcint != NULL) delete fcint;
  delete data;

  /// print timing info
  t.Stop();
  t.Print();
}
// int main() {
//    rs101_limitexample();
// }
<|endoftext|>


<commit_before>#include <ctrcommon/input.hpp>
#include <ctrcommon/platform.hpp>
#include <ctrcommon/ui.hpp>

#include <sstream>
#include <iomanip>
#include <stdio.h>

typedef enum {
    INSTALL,
    DELETE
} Mode;

int main(int argc, char **argv) {
    if(!platformInit()) {
        return 0;
    }

    bool ninjhax = platformIsNinjhax();

    std::vector<std::string> extensions;
    extensions.push_back("cia");

    MediaType destination = SD;
    Mode mode = INSTALL;
    bool exit = false;
    bool netInstall = false;
    u64 freeSpace = fsGetFreeSpace(destination);
    auto onLoop = [&]() {
        if(ninjhax && inputIsPressed(BUTTON_SELECT)) {
            exit = true;
            return true;
        }

        bool breakLoop = false;

        if(inputIsPressed(BUTTON_L)) {
            if(destination == SD) {
                destination = NAND;
            } else {
                destination = SD;
            }

            freeSpace = fsGetFreeSpace(destination);
            if(mode == DELETE) {
                breakLoop = true;
            }
        }

        if(inputIsPressed(BUTTON_R)) {
            if(mode == INSTALL) {
                mode = DELETE;
            } else {
                mode = INSTALL;
            }

            breakLoop = true;
        }

        if(inputIsPressed(BUTTON_Y)) {
            netInstall = true;
            breakLoop = true;
        }

        std::stringstream stream;
        stream << "Free Space: " << freeSpace << " bytes (" << std::fixed << std::setprecision(2) << freeSpace / 1024.0f / 1024.0f << "MB)" << "\n";
        stream << "Destination: " << (destination == NAND ? "NAND" : "SD") << ", Mode: " << (mode == INSTALL ? "Install" : "Delete") << "\n";
        stream << "L - Switch Destination, R - Switch Mode" << "\n";
        stream << "Y - Receive an app over the network" << "\n";
        if(ninjhax) {
            stream << "SELECT - Exit to launcher" << "\n";
        }

        std::string str = stream.str();
        screenDrawString(str, (screenGetWidth() - screenGetStrWidth(str)) / 2, screenGetHeight() - 4 - screenGetStrHeight(str), 255, 255, 255);

        return breakLoop;
    };

    auto onProgress = [&](int progress) {
        uiDisplayProgress(TOP_SCREEN, "Installing", "Press B to cancel.", true, progress);
        inputPoll();
        return !inputIsPressed(BUTTON_B);
    };

    while(platformIsRunning()) {
        std::string targetInstall;
        App targetDelete;
        if(mode == INSTALL) {
            uiSelectFile(&targetInstall, "sdmc:", extensions, [&](bool inRoot) {
                return onLoop();
            }, [&](std::string path, bool &updateList) {
                if(uiPrompt(TOP_SCREEN, "Install the selected title?", true)) {
                    AppResult ret = appInstallFile(destination, path, onProgress);
                    std::stringstream resultMsg;

                    resultMsg << "Install ";
                    if(ret == APP_SUCCESS) {
                        resultMsg << "succeeded!";
                    } else {
                        resultMsg << "failed!" << "\n";
                        resultMsg << appGetResultString(ret) << "\n";
                    }

                    uiPrompt(TOP_SCREEN, resultMsg.str(), false);

                    freeSpace = fsGetFreeSpace(destination);
                }

                return false;
            });
        } else if(mode == DELETE) {
            uiSelectApp(&targetDelete, destination, onLoop, [&](App app, bool &updateList) {
                if(uiPrompt(TOP_SCREEN, "Delete the selected title?", true)) {
                    updateList = true;
                    uiDisplayMessage(TOP_SCREEN, "Deleting title...");
                    AppResult ret = appDelete(app);

                    std::stringstream resultMsg;
                    resultMsg << "Delete ";
                    if(ret == APP_SUCCESS) {
                        resultMsg << "succeeded!";
                    } else {
                        resultMsg << "failed!" << "\n";
                        resultMsg << appGetResultString(ret) << "\n";
                    }

                    uiPrompt(TOP_SCREEN, resultMsg.str(), false);

                    freeSpace = fsGetFreeSpace(destination);
                }

                return false;
            });
        }

        if(netInstall && !exit) {
            netInstall = false;

            screenClearBuffers(BOTTOM_SCREEN, 0, 0, 0);

            RemoteFile file = uiAcceptRemoteFile(TOP_SCREEN);
            if(file.fd == NULL) {
                continue;
            }

            std::stringstream confirmStream;
            confirmStream << "Install the received application?" << "\n";
            confirmStream << "Size: " << file.fileSize << " bytes (" << std::fixed << std::setprecision(2) << file.fileSize / 1024.0f / 1024.0f << "MB)" << "\n";
            if(uiPrompt(TOP_SCREEN, confirmStream.str(), true)) {
                AppResult ret = appInstall(destination, file.fd, file.fileSize, onProgress);
                std::stringstream resultMsg;
                if(mode == INSTALL) {
                    resultMsg << "Install ";
                } else if(mode == DELETE) {
                    resultMsg << "Delete ";
                }

                if(ret == APP_SUCCESS) {
                    resultMsg << "succeeded!";
                } else {
                    resultMsg << "failed!" << "\n";
                    resultMsg << appGetResultString(ret) << "\n";
                }

                uiPrompt(TOP_SCREEN, resultMsg.str(), false);
            }

            fclose(file.fd);
            continue;
        }

        if(exit) {
            break;
        }
    }

    platformCleanup();
    return 0;
}
<commit_msg>Allow deleting CIA files and installing/deleting all CIA files in a directory at once.<commit_after>#include <ctrcommon/input.hpp>
#include <ctrcommon/platform.hpp>
#include <ctrcommon/ui.hpp>

#include <stdio.h>

#include <sstream>
#include <iomanip>

#include <sys/dirent.h>

typedef enum {
    INSTALL_CIA,
    DELETE_CIA,
    DELETE_TITLE
} Mode;

int main(int argc, char **argv) {
    if(!platformInit()) {
        return 0;
    }

    bool ninjhax = platformIsNinjhax();
    /* if(ninjhax) {
        consoleInit(GFX_BOTTOM, NULL);
        consoleClear();

        AcquireResult result = platformAcquireServices();
        if(result != ACQUIRE_SUCCESS) {
            //std::stringstream errorStream;
            //errorStream << "Failed to acquire services." << "\n";
            //errorStream << platformGetAcquireResultString(result) << "\n";
            //uiPrompt(TOP_SCREEN, errorStream.str(), false);

            while(true) {
                inputPoll();
                if(inputIsPressed(BUTTON_START)) {
                    break;
                }
            }

            platformCleanup();
            return 0;
        }
    } */

    std::vector<std::string> extensions;
    extensions.push_back("cia");

    MediaType destination = SD;
    Mode mode = INSTALL_CIA;
    bool exit = false;
    bool netInstall = false;
    u64 freeSpace = fsGetFreeSpace(destination);
    auto onLoop = [&]() {
        if(ninjhax && inputIsPressed(BUTTON_SELECT)) {
            exit = true;
            return true;
        }

        bool breakLoop = false;

        if(inputIsPressed(BUTTON_L)) {
            if(destination == SD) {
                destination = NAND;
            } else {
                destination = SD;
            }

            freeSpace = fsGetFreeSpace(destination);
            if(mode == DELETE_TITLE) {
                breakLoop = true;
            }
        }

        if(inputIsPressed(BUTTON_R)) {
            if(mode == INSTALL_CIA) {
                mode = DELETE_CIA;
            } else if(mode == DELETE_CIA) {
                mode = DELETE_TITLE;
            } else {
                mode = INSTALL_CIA;
            }

            breakLoop = true;
        }

        if(inputIsPressed(BUTTON_Y)) {
            netInstall = true;
            breakLoop = true;
        }

        std::stringstream stream;
        stream << "Free Space: " << freeSpace << " bytes (" << std::fixed << std::setprecision(2) << freeSpace / 1024.0f / 1024.0f << "MB)" << "\n";
        stream << "Destination: " << (destination == NAND ? "NAND" : "SD") << ", Mode: " << (mode == INSTALL_CIA ? "Install CIA" : mode == DELETE_CIA ? "Delete CIA" : "Delete Title") << "\n";
        stream << "L - Switch Destination, R - Switch Mode" << "\n";
        if(mode == INSTALL_CIA) {
            stream << "X - Install all CIAs in the current directory" << "\n";
        } else if(mode == DELETE_CIA) {
            stream << "X - Delete all CIAs in the current directory" << "\n";
        }

        stream << "Y - Receive an app over the network" << "\n";
        if(ninjhax) {
            stream << "SELECT - Exit to launcher" << "\n";
        }

        std::string str = stream.str();
        screenDrawString(str, (screenGetWidth() - screenGetStrWidth(str)) / 2, screenGetHeight() - 4 - screenGetStrHeight(str), 255, 255, 255);

        return breakLoop;
    };

    auto onProgress = [&](int progress) {
        uiDisplayProgress(TOP_SCREEN, "Installing", "Press B to cancel.", true, progress);
        inputPoll();
        return !inputIsPressed(BUTTON_B);
    };

    while(platformIsRunning()) {
        std::string fileTarget;
        App appTarget;
        if(mode == INSTALL_CIA) {
            uiSelectFile(&fileTarget, "/", extensions, [&](const std::string currDirectory, bool inRoot, bool &updateList) {
                if(inputIsPressed(BUTTON_X)) {
                    if(uiPrompt(TOP_SCREEN, "Install all CIAs in the current directory?", true)) {
                        bool failed = false;
                        std::vector<FileInfo> contents = fsGetDirectoryContents(currDirectory);
                        for(std::vector<FileInfo>::iterator it = contents.begin(); it != contents.end(); it++) {
                            std::string path = (*it).path;
                            std::string fileName = (*it).name;
                            if(!fsIsDirectory(path) && fsHasExtensions(path, extensions)) {
                                AppResult ret = appInstallFile(destination, path, onProgress);
                                if(ret != APP_SUCCESS) {
                                    std::stringstream resultMsg;
                                    resultMsg << "Install failed!" << "\n";
                                    resultMsg << fileName << "\n";
                                    resultMsg << appGetResultString(ret) << "\n";
                                    uiPrompt(TOP_SCREEN, resultMsg.str(), false);
                                    failed = true;
                                    break;
                                }
                            }
                        }

                        if(!failed) {
                            uiPrompt(TOP_SCREEN, "Install succeeded!\n", false);
                        }

                        freeSpace = fsGetFreeSpace(destination);
                    }
                }

                return onLoop();
            }, [&](const std::string path, bool &updateList) {
                if(uiPrompt(TOP_SCREEN, "Install the selected CIA?", true)) {
                    AppResult ret = appInstallFile(destination, path, onProgress);

                    std::stringstream resultMsg;
                    resultMsg << "Install ";
                    if(ret == APP_SUCCESS) {
                        resultMsg << "succeeded!";
                    } else {
                        resultMsg << "failed!" << "\n";
                        resultMsg << appGetResultString(ret) << "\n";
                    }

                    uiPrompt(TOP_SCREEN, resultMsg.str(), false);

                    freeSpace = fsGetFreeSpace(destination);
                }

                return false;
            });
        } else if(mode == DELETE_CIA) {
            uiSelectFile(&fileTarget, "/", extensions, [&](const std::string currDirectory, bool inRoot, bool &updateList) {
                if(inputIsPressed(BUTTON_X)) {
                    if(uiPrompt(TOP_SCREEN, "Delete all CIAs in the current directory?", true)) {
                        updateList = true;
                        bool failed = false;
                        std::vector<FileInfo> contents = fsGetDirectoryContents(currDirectory);
                        for(std::vector<FileInfo>::iterator it = contents.begin(); it != contents.end(); it++) {
                            std::string path = (*it).path;
                            std::string fileName = (*it).name;
                            if(!fsIsDirectory(path) && fsHasExtensions(path, extensions)) {
                                if(!fsDelete(path)) {
                                    std::stringstream resultMsg;
                                    resultMsg << "Delete failed!" << "\n";
                                    resultMsg << fileName << "\n";
                                    uiPrompt(TOP_SCREEN, resultMsg.str(), false);
                                    failed = true;
                                    break;
                                }
                            }
                        }

                        if(!failed) {
                            uiPrompt(TOP_SCREEN, "Delete succeeded!\n", false);
                        }

                        freeSpace = fsGetFreeSpace(destination);
                    }
                }

                return onLoop();
            }, [&](const std::string path, bool &updateList) {
                if(uiPrompt(TOP_SCREEN, "Delete the selected CIA?", true)) {
                    updateList = true;
                    std::stringstream resultMsg;
                    resultMsg << "Delete ";
                    if(fsDelete(path)) {
                        resultMsg << "succeeded!";
                    } else {
                        resultMsg << "failed!" << "\n";
                    }

                    uiPrompt(TOP_SCREEN, resultMsg.str(), false);

                    freeSpace = fsGetFreeSpace(destination);
                }

                return false;
            });
        } else if(mode == DELETE_TITLE) {
            uiSelectApp(&appTarget, destination, [&](bool &updateList) {
                return onLoop();
            }, [&](App app, bool &updateList) {
                if(uiPrompt(TOP_SCREEN, "Delete the selected title?", true)) {
                    updateList = true;
                    uiDisplayMessage(TOP_SCREEN, "Deleting title...");
                    AppResult ret = appDelete(app);

                    std::stringstream resultMsg;
                    resultMsg << "Delete ";
                    if(ret == APP_SUCCESS) {
                        resultMsg << "succeeded!";
                    } else {
                        resultMsg << "failed!" << "\n";
                        resultMsg << appGetResultString(ret) << "\n";
                    }

                    uiPrompt(TOP_SCREEN, resultMsg.str(), false);

                    freeSpace = fsGetFreeSpace(destination);
                }

                return false;
            });
        }

        if(netInstall && !exit) {
            netInstall = false;

            screenClearBuffers(BOTTOM_SCREEN, 0, 0, 0);

            RemoteFile file = uiAcceptRemoteFile(TOP_SCREEN);
            if(file.fd == NULL) {
                continue;
            }

            std::stringstream confirmStream;
            confirmStream << "Install the received application?" << "\n";
            confirmStream << "Size: " << file.fileSize << " bytes (" << std::fixed << std::setprecision(2) << file.fileSize / 1024.0f / 1024.0f << "MB)" << "\n";
            if(uiPrompt(TOP_SCREEN, confirmStream.str(), true)) {
                AppResult ret = appInstall(destination, file.fd, file.fileSize, onProgress);
                std::stringstream resultMsg;
                resultMsg << "Install ";
                if(ret == APP_SUCCESS) {
                    resultMsg << "succeeded!";
                } else {
                    resultMsg << "failed!" << "\n";
                    resultMsg << appGetResultString(ret) << "\n";
                }

                uiPrompt(TOP_SCREEN, resultMsg.str(), false);
            }

            fclose(file.fd);
            continue;
        }

        if(exit) {
            break;
        }
    }

    platformCleanup();
    return 0;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "warnings_guard_ne_locks.h"
#include <ne_uri.h>
#include "rtl/ustring.hxx"
#include "osl/time.h"
#include "osl/thread.hxx"
#include "salhelper/thread.hxx"
#include "NeonSession.hxx"
#include "NeonLockStore.hxx"

using namespace webdav_ucp;

namespace webdav_ucp {

class TickerThread : public salhelper::Thread
{
    bool m_bFinish;
    NeonLockStore & m_rLockStore;

public:

    TickerThread( NeonLockStore & rLockStore )
    : Thread( "NeonTickerThread" ), m_bFinish( false ),
      m_rLockStore( rLockStore ) {}

    void finish() { m_bFinish = true; }

private:

    virtual void execute();
};

} // namespace webdav_ucp

// -------------------------------------------------------------------
void TickerThread::execute()
{
    OSL_TRACE( "TickerThread: start." );

    // we have to go through the loop more often to be able to finish ~quickly
    const int nNth = 25;

    int nCount = nNth;
    while ( !m_bFinish )
    {
        if ( nCount-- <= 0 )
        {
            m_rLockStore.refreshLocks();
            nCount = nNth;
        }

        TimeValue aTV;
        aTV.Seconds = 0;
        aTV.Nanosec = 1000000000 / nNth;
        osl::Thread::wait( aTV );
    }

    OSL_TRACE( "TickerThread: stop." );
}

// -------------------------------------------------------------------
NeonLockStore::NeonLockStore()
    : m_pNeonLockStore( ne_lockstore_create() )
{
    OSL_ENSURE( m_pNeonLockStore, "Unable to create neon lock store!" );
}

// -------------------------------------------------------------------
NeonLockStore::~NeonLockStore()
{
    stopTicker();

    // release active locks, if any.
    OSL_ENSURE( m_aLockInfoMap.empty(),
                "NeonLockStore::~NeonLockStore - Releasing active locks!" );

    LockInfoMap::const_iterator it( m_aLockInfoMap.begin() );
    const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
    while ( it != end )
    {
        NeonLock * pLock = (*it).first;
        (*it).second.xSession->UNLOCK( pLock );

        ne_lockstore_remove( m_pNeonLockStore, pLock );
        ne_lock_destroy( pLock );

        ++it;
    }

    ne_lockstore_destroy( m_pNeonLockStore );
}

// -------------------------------------------------------------------
void NeonLockStore::startTicker()
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( !m_pTickerThread.is() )
    {
        m_pTickerThread = new TickerThread( *this );
        m_pTickerThread->launch();
    }
}

// -------------------------------------------------------------------
void NeonLockStore::stopTicker()
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( m_pTickerThread.is() )
    {
        m_pTickerThread->finish();
        m_pTickerThread->join();
        m_pTickerThread.clear();
    }
}

// -------------------------------------------------------------------
void NeonLockStore::registerSession( HttpSession * pHttpSession )
{
    osl::MutexGuard aGuard( m_aMutex );

    ne_lockstore_register( m_pNeonLockStore, pHttpSession );
}

// -------------------------------------------------------------------
NeonLock * NeonLockStore::findByUri( rtl::OUString const & rUri )
{
    osl::MutexGuard aGuard( m_aMutex );

    ne_uri aUri;
    ne_uri_parse( rtl::OUStringToOString(
        rUri, RTL_TEXTENCODING_UTF8 ).getStr(), &aUri );
    return ne_lockstore_findbyuri( m_pNeonLockStore, &aUri );
}

// -------------------------------------------------------------------
void NeonLockStore::addLock( NeonLock * pLock,
                             rtl::Reference< NeonSession > const & xSession,
                             sal_Int32 nLastChanceToSendRefreshRequest )
{
    osl::MutexGuard aGuard( m_aMutex );

    ne_lockstore_add( m_pNeonLockStore, pLock );
    m_aLockInfoMap[ pLock ]
        = LockInfo( xSession, nLastChanceToSendRefreshRequest );

    startTicker();
}

// -------------------------------------------------------------------
void NeonLockStore::updateLock( NeonLock * pLock,
                                sal_Int32 nLastChanceToSendRefreshRequest )
{
    osl::MutexGuard aGuard( m_aMutex );

    LockInfoMap::iterator it( m_aLockInfoMap.find( pLock ) );
    OSL_ENSURE( it != m_aLockInfoMap.end(),
                "NeonLockStore::updateLock: lock not found!" );

    if ( it != m_aLockInfoMap.end() )
    {
        (*it).second.nLastChanceToSendRefreshRequest
            = nLastChanceToSendRefreshRequest;
    }
}

// -------------------------------------------------------------------
void NeonLockStore::removeLock( NeonLock * pLock )
{
    osl::MutexGuard aGuard( m_aMutex );

    m_aLockInfoMap.erase( pLock );
    ne_lockstore_remove( m_pNeonLockStore, pLock );

    if ( m_aLockInfoMap.empty() )
        stopTicker();
}

// -------------------------------------------------------------------
void NeonLockStore::refreshLocks()
{
    osl::MutexGuard aGuard( m_aMutex );

    LockInfoMap::iterator it( m_aLockInfoMap.begin() );
    const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
    while ( it != end )
    {
        LockInfo & rInfo = (*it).second;
        if ( rInfo.nLastChanceToSendRefreshRequest != -1 )
        {
            // 30 seconds or less remaining until lock expires?
            TimeValue t1;
            osl_getSystemTime( &t1 );
            if ( rInfo.nLastChanceToSendRefreshRequest - 30
                     <= sal_Int32( t1.Seconds ) )
            {
                // refresh the lock.
                sal_Int32 nlastChanceToSendRefreshRequest = -1;
                if ( rInfo.xSession->LOCK(
                         (*it).first,
                         /* out param */ nlastChanceToSendRefreshRequest ) )
                {
                    rInfo.nLastChanceToSendRefreshRequest
                        = nlastChanceToSendRefreshRequest;
                }
                else
                {
                    // refresh failed. stop auto-refresh.
                    rInfo.nLastChanceToSendRefreshRequest = -1;
                }
            }
        }
        ++it;
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>fix msvc2005 build<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "warnings_guard_ne_locks.h"
#include <ne_uri.h>
#include "rtl/ustring.hxx"
#include "osl/time.h"
#include "osl/thread.hxx"
#include "salhelper/thread.hxx"
#include "NeonSession.hxx"
#include "NeonLockStore.hxx"

using namespace webdav_ucp;

namespace webdav_ucp {

class TickerThread : public salhelper::Thread
{
    bool m_bFinish;
    NeonLockStore & m_rLockStore;

public:

    TickerThread( NeonLockStore & rLockStore )
    : Thread( "NeonTickerThread" ), m_bFinish( false ),
      m_rLockStore( rLockStore ) {}

    void finish() { m_bFinish = true; }

private:

    virtual void execute();
};

} // namespace webdav_ucp

// -------------------------------------------------------------------
void TickerThread::execute()
{
    OSL_TRACE( "TickerThread: start." );

    // we have to go through the loop more often to be able to finish ~quickly
    const int nNth = 25;

    int nCount = nNth;
    while ( !m_bFinish )
    {
        if ( nCount-- <= 0 )
        {
            m_rLockStore.refreshLocks();
            nCount = nNth;
        }

        TimeValue aTV;
        aTV.Seconds = 0;
        aTV.Nanosec = 1000000000 / nNth;
        salhelper::Thread::wait( aTV );
    }

    OSL_TRACE( "TickerThread: stop." );
}

// -------------------------------------------------------------------
NeonLockStore::NeonLockStore()
    : m_pNeonLockStore( ne_lockstore_create() )
{
    OSL_ENSURE( m_pNeonLockStore, "Unable to create neon lock store!" );
}

// -------------------------------------------------------------------
NeonLockStore::~NeonLockStore()
{
    stopTicker();

    // release active locks, if any.
    OSL_ENSURE( m_aLockInfoMap.empty(),
                "NeonLockStore::~NeonLockStore - Releasing active locks!" );

    LockInfoMap::const_iterator it( m_aLockInfoMap.begin() );
    const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
    while ( it != end )
    {
        NeonLock * pLock = (*it).first;
        (*it).second.xSession->UNLOCK( pLock );

        ne_lockstore_remove( m_pNeonLockStore, pLock );
        ne_lock_destroy( pLock );

        ++it;
    }

    ne_lockstore_destroy( m_pNeonLockStore );
}

// -------------------------------------------------------------------
void NeonLockStore::startTicker()
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( !m_pTickerThread.is() )
    {
        m_pTickerThread = new TickerThread( *this );
        m_pTickerThread->launch();
    }
}

// -------------------------------------------------------------------
void NeonLockStore::stopTicker()
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( m_pTickerThread.is() )
    {
        m_pTickerThread->finish();
        m_pTickerThread->join();
        m_pTickerThread.clear();
    }
}

// -------------------------------------------------------------------
void NeonLockStore::registerSession( HttpSession * pHttpSession )
{
    osl::MutexGuard aGuard( m_aMutex );

    ne_lockstore_register( m_pNeonLockStore, pHttpSession );
}

// -------------------------------------------------------------------
NeonLock * NeonLockStore::findByUri( rtl::OUString const & rUri )
{
    osl::MutexGuard aGuard( m_aMutex );

    ne_uri aUri;
    ne_uri_parse( rtl::OUStringToOString(
        rUri, RTL_TEXTENCODING_UTF8 ).getStr(), &aUri );
    return ne_lockstore_findbyuri( m_pNeonLockStore, &aUri );
}

// -------------------------------------------------------------------
void NeonLockStore::addLock( NeonLock * pLock,
                             rtl::Reference< NeonSession > const & xSession,
                             sal_Int32 nLastChanceToSendRefreshRequest )
{
    osl::MutexGuard aGuard( m_aMutex );

    ne_lockstore_add( m_pNeonLockStore, pLock );
    m_aLockInfoMap[ pLock ]
        = LockInfo( xSession, nLastChanceToSendRefreshRequest );

    startTicker();
}

// -------------------------------------------------------------------
void NeonLockStore::updateLock( NeonLock * pLock,
                                sal_Int32 nLastChanceToSendRefreshRequest )
{
    osl::MutexGuard aGuard( m_aMutex );

    LockInfoMap::iterator it( m_aLockInfoMap.find( pLock ) );
    OSL_ENSURE( it != m_aLockInfoMap.end(),
                "NeonLockStore::updateLock: lock not found!" );

    if ( it != m_aLockInfoMap.end() )
    {
        (*it).second.nLastChanceToSendRefreshRequest
            = nLastChanceToSendRefreshRequest;
    }
}

// -------------------------------------------------------------------
void NeonLockStore::removeLock( NeonLock * pLock )
{
    osl::MutexGuard aGuard( m_aMutex );

    m_aLockInfoMap.erase( pLock );
    ne_lockstore_remove( m_pNeonLockStore, pLock );

    if ( m_aLockInfoMap.empty() )
        stopTicker();
}

// -------------------------------------------------------------------
void NeonLockStore::refreshLocks()
{
    osl::MutexGuard aGuard( m_aMutex );

    LockInfoMap::iterator it( m_aLockInfoMap.begin() );
    const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
    while ( it != end )
    {
        LockInfo & rInfo = (*it).second;
        if ( rInfo.nLastChanceToSendRefreshRequest != -1 )
        {
            // 30 seconds or less remaining until lock expires?
            TimeValue t1;
            osl_getSystemTime( &t1 );
            if ( rInfo.nLastChanceToSendRefreshRequest - 30
                     <= sal_Int32( t1.Seconds ) )
            {
                // refresh the lock.
                sal_Int32 nlastChanceToSendRefreshRequest = -1;
                if ( rInfo.xSession->LOCK(
                         (*it).first,
                         /* out param */ nlastChanceToSendRefreshRequest ) )
                {
                    rInfo.nLastChanceToSendRefreshRequest
                        = nlastChanceToSendRefreshRequest;
                }
                else
                {
                    // refresh failed. stop auto-refresh.
                    rInfo.nLastChanceToSendRefreshRequest = -1;
                }
            }
        }
        ++it;
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/* http.cc
   Mathieu Stefani, 13 August 2015

   Http layer implementation
*/

#include <cstring>
#include <iostream>
#include <stdexcept>
#include "common.h"
#include "http.h"
#include "net.h"
#include "peer.h"

using namespace std;

namespace Net {

namespace Http {

static constexpr char CR = 0xD;
static constexpr char LF = 0xA;
static constexpr char CRLF[] = {CR, LF};

namespace Private {

    Parser::Buffer::Buffer()
        : len(0)
    {
        memset(data, sizeof data, 0);
    }

    void
    Parser::Buffer::reset() {
        memset(data, sizeof data, 0);
        len = 0;
    }

    bool
    Parser::Cursor::advance(size_t count)
    {
        if (value + count >= sizeof (buff.data)) {
            //parser->raise("Early EOF");
        }
        // Allowed to advance one past the end
        else if (value + count > buff.len) {
            return false;
        }

        value += count;
        return true;
    }

    bool
    Parser::Cursor::eol() const {
        return buff.data[value] == CR && next() == LF;
    }

    int
    Parser::Cursor::next() const {
        if (value + 1 >= sizeof (buff.data)) {
            //parser->raise("Early EOF");
        }

        else if (value + 1 >= buff.len) {
            return Eof;
        }

        return buff.data[value + 1];
    }

    char
    Parser::Cursor::current() const {
        return buff.data[value];
    }

    const char *
    Parser::Cursor::offset() const {
        return buff.data + value;
    }

    const char *
    Parser::Cursor::offset(size_t off) const {
        return buff.data + off;
    }

    size_t
    Parser::Cursor::diff(size_t other) const {
        return value - other;
    }

    size_t
    Parser::Cursor::diff(const Cursor& other) const {
        return value - other.value;
    }

    size_t
    Parser::Cursor::remaining() const {
        // assert(val <= buff.len);
        return buff.len - value;
    }

    void
    Parser::Cursor::reset() {
        value = 0;
    }

    void
    Parser::Step::raise(const char* msg, Code code /* = Code::Bad_Request */) {
        throw HttpError(code, msg);
    }

    Parser::State
    Parser::RequestLineStep::apply(Cursor& cursor) {
        Cursor::Revert revert(cursor);

        auto tryMatch = [&](const char* const str) {
            const size_t len = std::strlen(str);
            if (strncmp(cursor.offset(), str, len) == 0) {
                cursor.advance(len - 1);
                return true;
            }
            return false;
        };

        // Method

        if (tryMatch("OPTIONS")) {
           request->method = Method::Options;
        }
        else if (tryMatch("GET")) {
            request->method = Method::Get;
        }
        else if (tryMatch("POST")) {
            request->method = Method::Post;
        }
        else if (tryMatch("HEAD")) {
            request->method = Method::Head;
        }
        else if (tryMatch("PUT")) {
            request->method = Method::Put;
        }
        else if (tryMatch("DELETE")) {
            request->method = Method::Delete;
        }
        else {
            raise("Unknown HTTP request method");
        }

        auto n = cursor.next();
        if (n == Cursor::Eof) return State::Again;
        else if (n != ' ') raise("Malformed HTTP request after Method, expected SP");

        if (!cursor.advance(2)) return State::Again;

        size_t start = cursor;

        while ((n = cursor.next()) != Cursor::Eof && n != ' ') {
            if (!cursor.advance(1)) return State::Again;
        }

        request->resource = std::string(cursor.offset(start), cursor.diff(start) + 1);
        if ((n = cursor.next()) == Cursor::Eof) return State::Again;

        if (n != ' ')
            raise("Malformed HTTP request after Request-URI");

        // SP
        if (!cursor.advance(2)) return State::Again;

        // HTTP-Version
        start = cursor;

        while (!cursor.eol())
            if (!cursor.advance(1)) return State::Again;

        const size_t diff = cursor.diff(start);
        if (strncmp(cursor.offset(start), "HTTP/1.0", diff) == 0) {
            request->version = Version::Http10;
        }
        else if (strncmp(cursor.offset(start), "HTTP/1.1", diff) == 0) {
            request->version = Version::Http11;
        }
        else {
            raise("Encountered invalid HTTP version");
        }

        if (!cursor.advance(2)) return State::Again;

        revert.ignore();
        return State::Next;

    }

    Parser::State
    Parser::HeadersStep::apply(Cursor& cursor) {
        Cursor::Revert revert(cursor);

        while (!cursor.eol()) {
            Cursor::Revert headerRevert(cursor);

            // Read the header name
            size_t start = cursor;

            while (cursor.current() != ':')
                if (!cursor.advance(1)) return State::Again;

            // Skip the ':'
            if (!cursor.advance(1)) return State::Again;

            std::string name = std::string(cursor.offset(start), cursor.diff(start) - 1);

            // Ignore spaces
            while (cursor.current() == ' ')
                if (!cursor.advance(1)) return State::Again;

            // Read the header value
            start = cursor;
            while (!cursor.eol()) {
                if (!cursor.advance(1)) return State::Again;
            }

            if (HeaderRegistry::isRegistered(name)) {
                std::shared_ptr<Header> header = HeaderRegistry::makeHeader(name);
                header->parseRaw(cursor.offset(start), cursor.diff(start));
                request->headers.add(header);
            }

            // CRLF
            if (!cursor.advance(2)) return State::Again;

            headerRevert.ignore();
        }

        revert.ignore();
        return Parser::State::Next;
    }

    Parser::State
    Parser::BodyStep::apply(Cursor& cursor) {
        auto cl = request->headers.tryGet<ContentLength>();
        if (!cl) return Parser::State::Done;

        auto contentLength = cl->value();
        // We already started to read some bytes but we got an incomplete payload
        if (bytesRead > 0) {
            // How many bytes do we still need to read ?
            const size_t remaining = contentLength - bytesRead;
            auto start = cursor;

            // Could be refactored in a single function / lambda but I'm too lazy
            // for that right now
            if (!cursor.advance(remaining)) {
                const size_t available = cursor.remaining();

                request->body.append(cursor.offset(start), available);
                bytesRead += available;

                cursor.advance(available);
                return State::Again;
            }
            else {
                request->body.append(cursor.offset(), cursor.diff(start));
            }

        }
        // This is the first time we are reading the payload
        else {
            if (!cursor.advance(2)) return State::Again;

            request->body.reserve(contentLength);

            auto start = cursor;

            // We have an incomplete body, read what we can
            if (!cursor.advance(contentLength)) {
                const size_t available = cursor.remaining();

                request->body.append(cursor.offset(start), available);
                bytesRead += available;

                cursor.advance(available);
                return State::Again;
            }

            request->body.append(cursor.offset(start), cursor.diff(start));
        }

        bytesRead = 0;
        return Parser::State::Done;
    }

    Parser::State
    Parser::parse() {
        State state = State::Again;
        do {
            Step *step = allSteps[currentStep].get();
            state = step->apply(cursor);
            if (state == State::Next) {
                ++currentStep;
            }
        } while (state == State::Next);

        // Should be either Again or Done
        return state;
    }

    bool
    Parser::feed(const char* data, size_t len) {
        if (len + buffer.len >= sizeof (buffer.data)) {
            return false;
        }

        memcpy(buffer.data + buffer.len, data, len);
        buffer.len += len;

        return true;
    }

    void
    Parser::reset() {
        buffer.reset();
        cursor.reset();

        currentStep = 0;

        request.headers.clear();
        request.body.clear();
        request.resource.clear();
    }

    ssize_t
    Writer::writeRaw(const void* data, size_t len) {
        buf = static_cast<char *>(memcpy(buf, data, len));
        buf += len;

        return 0;
    }

    ssize_t
    Writer::writeString(const char* str) {
        const size_t len = std::strlen(str);
        return writeRaw(str, std::strlen(str));
    }

    ssize_t
    Writer::writeHeader(const char* name, const char* value) {
        writeString(name);
        writeChar(':');
        writeString(value);
        writeRaw(CRLF, 2);

        return 0;
    }

} // namespace Private

const char* methodString(Method method)
{
    switch (method) {
#define METHOD(name, str) \
    case Method::name: \
        return str;
    HTTP_METHODS
#undef METHOD
    }

    unreachable();
}

const char* codeString(Code code)
{
    switch (code) {
#define CODE(_, name, str) \
    case Code::name: \
         return str;
    STATUS_CODES
#undef CODE
    }

    return "";
}

HttpError::HttpError(Code code, std::string reason)
    : code_(static_cast<int>(code))
    , reason_(std::move(reason))
{ }

HttpError::HttpError(int code, std::string reason)
    : code_(code)
    , reason_(std::move(reason))
{ }

Message::Message()
    : version(Version::Http11)
{ }

Request::Request()
    : Message()
{ }

Response::Response(int code, std::string body)
{
    this->body = std::move(body);
    code_ = code;
}

Response::Response(Code code, std::string body)
    : Message()
{
    this->body = std::move(body);
    code_ = static_cast<int>(code);
}

void
Response::writeTo(Tcp::Peer& peer)
{
    int fd = peer.fd();

    char buffer[Const::MaxBuffer];
    std::memset(buffer, 0, Const::MaxBuffer);
    Private::Writer fmt(buffer, sizeof buffer);

    fmt.writeString("HTTP/1.1 ");
    fmt.writeInt(code_);
    fmt.writeChar(' ');
    fmt.writeString(codeString(static_cast<Code>(code_)));
    fmt.writeRaw(CRLF, 2);

    for (const auto& header: headers.list()) {
        std::ostringstream oss;
        header->write(oss);

        std::string str = oss.str();
        fmt.writeRaw(str.c_str(), str.size());
        fmt.writeRaw(CRLF, 2);
    }

    fmt.writeHeader("Content-Length", body.size());

    fmt.writeRaw(CRLF, 2);
    fmt.writeString(body.c_str());

    const size_t len = fmt.cursor() - buffer;

    ssize_t bytes = send(fd, buffer, len, 0);
}

void
Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) {
    auto& parser = getParser(peer);

    if (!parser.feed(buffer, len)) {
        cout << "Could not feed parser bro" << endl;
    }
    else {
        try {
            auto state = parser.parse();
            if (state == Private::Parser::State::Done) {
                onRequest(parser.request, peer);
                parser.reset();
            }
        } catch (const HttpError &err) {
            Response response(err.code(), err.reason());
            response.writeTo(peer);
        }
        catch (const std::exception& e) {
            Response response(Code::Internal_Server_Error, e.what());
            response.writeTo(peer);
        }
    }
}

void
Handler::onOutput() {
}

void
Handler::onConnection(Tcp::Peer& peer) {
    peer.setData(std::make_shared<Private::Parser>());
}

void
Handler::onDisconnection(Tcp::Peer& peer) {
}

Private::Parser&
Handler::getParser(Tcp::Peer& peer) {
    auto data = peer.data();
    return *std::static_pointer_cast<Private::Parser>(data);
}

Endpoint::Endpoint()
{ }

Endpoint::Endpoint(const Net::Address& addr)
    : listener(addr)
{ }

void
Endpoint::setHandler(const std::shared_ptr<Handler>& handler) {
    handler_ = handler;
}

void
Endpoint::serve()
{
    if (!handler_)
        throw std::runtime_error("Must call setHandler() prior to serve()");

    listener.init(8, Tcp::Options::InstallSignalHandler);
    listener.setHandler(handler_);

    if (listener.bind()) {
        const auto& addr = listener.address();
        cout << "Now listening on " << "http://" + addr.host() << ":" << addr.port() << endl;
        listener.run();
    }
}

} // namespace Http

} // namespace Net
<commit_msg>The default handler now returns an HTTP 500 when an exception occurs<commit_after>/* http.cc
   Mathieu Stefani, 13 August 2015

   Http layer implementation
*/

#include <cstring>
#include <iostream>
#include <stdexcept>
#include "common.h"
#include "http.h"
#include "net.h"
#include "peer.h"

using namespace std;

namespace Net {

namespace Http {

static constexpr char CR = 0xD;
static constexpr char LF = 0xA;
static constexpr char CRLF[] = {CR, LF};

namespace Private {

    Parser::Buffer::Buffer()
        : len(0)
    {
        memset(data, sizeof data, 0);
    }

    void
    Parser::Buffer::reset() {
        memset(data, sizeof data, 0);
        len = 0;
    }

    bool
    Parser::Cursor::advance(size_t count)
    {
        if (value + count >= sizeof (buff.data)) {
            //parser->raise("Early EOF");
        }
        // Allowed to advance one past the end
        else if (value + count > buff.len) {
            return false;
        }

        value += count;
        return true;
    }

    bool
    Parser::Cursor::eol() const {
        return buff.data[value] == CR && next() == LF;
    }

    int
    Parser::Cursor::next() const {
        if (value + 1 >= sizeof (buff.data)) {
            //parser->raise("Early EOF");
        }

        else if (value + 1 >= buff.len) {
            return Eof;
        }

        return buff.data[value + 1];
    }

    char
    Parser::Cursor::current() const {
        return buff.data[value];
    }

    const char *
    Parser::Cursor::offset() const {
        return buff.data + value;
    }

    const char *
    Parser::Cursor::offset(size_t off) const {
        return buff.data + off;
    }

    size_t
    Parser::Cursor::diff(size_t other) const {
        return value - other;
    }

    size_t
    Parser::Cursor::diff(const Cursor& other) const {
        return value - other.value;
    }

    size_t
    Parser::Cursor::remaining() const {
        // assert(val <= buff.len);
        return buff.len - value;
    }

    void
    Parser::Cursor::reset() {
        value = 0;
    }

    void
    Parser::Step::raise(const char* msg, Code code /* = Code::Bad_Request */) {
        throw HttpError(code, msg);
    }

    Parser::State
    Parser::RequestLineStep::apply(Cursor& cursor) {
        Cursor::Revert revert(cursor);

        auto tryMatch = [&](const char* const str) {
            const size_t len = std::strlen(str);
            if (strncmp(cursor.offset(), str, len) == 0) {
                cursor.advance(len - 1);
                return true;
            }
            return false;
        };

        // Method

        if (tryMatch("OPTIONS")) {
           request->method = Method::Options;
        }
        else if (tryMatch("GET")) {
            request->method = Method::Get;
        }
        else if (tryMatch("POST")) {
            request->method = Method::Post;
        }
        else if (tryMatch("HEAD")) {
            request->method = Method::Head;
        }
        else if (tryMatch("PUT")) {
            request->method = Method::Put;
        }
        else if (tryMatch("DELETE")) {
            request->method = Method::Delete;
        }
        else {
            raise("Unknown HTTP request method");
        }

        auto n = cursor.next();
        if (n == Cursor::Eof) return State::Again;
        else if (n != ' ') raise("Malformed HTTP request after Method, expected SP");

        if (!cursor.advance(2)) return State::Again;

        size_t start = cursor;

        while ((n = cursor.next()) != Cursor::Eof && n != ' ') {
            if (!cursor.advance(1)) return State::Again;
        }

        request->resource = std::string(cursor.offset(start), cursor.diff(start) + 1);
        if ((n = cursor.next()) == Cursor::Eof) return State::Again;

        if (n != ' ')
            raise("Malformed HTTP request after Request-URI");

        // SP
        if (!cursor.advance(2)) return State::Again;

        // HTTP-Version
        start = cursor;

        while (!cursor.eol())
            if (!cursor.advance(1)) return State::Again;

        const size_t diff = cursor.diff(start);
        if (strncmp(cursor.offset(start), "HTTP/1.0", diff) == 0) {
            request->version = Version::Http10;
        }
        else if (strncmp(cursor.offset(start), "HTTP/1.1", diff) == 0) {
            request->version = Version::Http11;
        }
        else {
            raise("Encountered invalid HTTP version");
        }

        if (!cursor.advance(2)) return State::Again;

        revert.ignore();
        return State::Next;

    }

    Parser::State
    Parser::HeadersStep::apply(Cursor& cursor) {
        Cursor::Revert revert(cursor);

        while (!cursor.eol()) {
            Cursor::Revert headerRevert(cursor);

            // Read the header name
            size_t start = cursor;

            while (cursor.current() != ':')
                if (!cursor.advance(1)) return State::Again;

            // Skip the ':'
            if (!cursor.advance(1)) return State::Again;

            std::string name = std::string(cursor.offset(start), cursor.diff(start) - 1);

            // Ignore spaces
            while (cursor.current() == ' ')
                if (!cursor.advance(1)) return State::Again;

            // Read the header value
            start = cursor;
            while (!cursor.eol()) {
                if (!cursor.advance(1)) return State::Again;
            }

            if (HeaderRegistry::isRegistered(name)) {
                std::shared_ptr<Header> header = HeaderRegistry::makeHeader(name);
                header->parseRaw(cursor.offset(start), cursor.diff(start));
                request->headers.add(header);
            }

            // CRLF
            if (!cursor.advance(2)) return State::Again;

            headerRevert.ignore();
        }

        revert.ignore();
        return Parser::State::Next;
    }

    Parser::State
    Parser::BodyStep::apply(Cursor& cursor) {
        auto cl = request->headers.tryGet<ContentLength>();
        if (!cl) return Parser::State::Done;

        auto contentLength = cl->value();
        // We already started to read some bytes but we got an incomplete payload
        if (bytesRead > 0) {
            // How many bytes do we still need to read ?
            const size_t remaining = contentLength - bytesRead;
            auto start = cursor;

            // Could be refactored in a single function / lambda but I'm too lazy
            // for that right now
            if (!cursor.advance(remaining)) {
                const size_t available = cursor.remaining();

                request->body.append(cursor.offset(start), available);
                bytesRead += available;

                cursor.advance(available);
                return State::Again;
            }
            else {
                request->body.append(cursor.offset(), cursor.diff(start));
            }

        }
        // This is the first time we are reading the payload
        else {
            if (!cursor.advance(2)) return State::Again;

            request->body.reserve(contentLength);

            auto start = cursor;

            // We have an incomplete body, read what we can
            if (!cursor.advance(contentLength)) {
                const size_t available = cursor.remaining();

                request->body.append(cursor.offset(start), available);
                bytesRead += available;

                cursor.advance(available);
                return State::Again;
            }

            request->body.append(cursor.offset(start), cursor.diff(start));
        }

        bytesRead = 0;
        return Parser::State::Done;
    }

    Parser::State
    Parser::parse() {
        State state = State::Again;
        do {
            Step *step = allSteps[currentStep].get();
            state = step->apply(cursor);
            if (state == State::Next) {
                ++currentStep;
            }
        } while (state == State::Next);

        // Should be either Again or Done
        return state;
    }

    bool
    Parser::feed(const char* data, size_t len) {
        if (len + buffer.len >= sizeof (buffer.data)) {
            return false;
        }

        memcpy(buffer.data + buffer.len, data, len);
        buffer.len += len;

        return true;
    }

    void
    Parser::reset() {
        buffer.reset();
        cursor.reset();

        currentStep = 0;

        request.headers.clear();
        request.body.clear();
        request.resource.clear();
    }

    ssize_t
    Writer::writeRaw(const void* data, size_t len) {
        buf = static_cast<char *>(memcpy(buf, data, len));
        buf += len;

        return 0;
    }

    ssize_t
    Writer::writeString(const char* str) {
        const size_t len = std::strlen(str);
        return writeRaw(str, std::strlen(str));
    }

    ssize_t
    Writer::writeHeader(const char* name, const char* value) {
        writeString(name);
        writeChar(':');
        writeString(value);
        writeRaw(CRLF, 2);

        return 0;
    }

} // namespace Private

const char* methodString(Method method)
{
    switch (method) {
#define METHOD(name, str) \
    case Method::name: \
        return str;
    HTTP_METHODS
#undef METHOD
    }

    unreachable();
}

const char* codeString(Code code)
{
    switch (code) {
#define CODE(_, name, str) \
    case Code::name: \
         return str;
    STATUS_CODES
#undef CODE
    }

    return "";
}

HttpError::HttpError(Code code, std::string reason)
    : code_(static_cast<int>(code))
    , reason_(std::move(reason))
{ }

HttpError::HttpError(int code, std::string reason)
    : code_(code)
    , reason_(std::move(reason))
{ }

Message::Message()
    : version(Version::Http11)
{ }

Request::Request()
    : Message()
{ }

Response::Response(int code, std::string body)
{
    this->body = std::move(body);
    code_ = code;
}

Response::Response(Code code, std::string body)
    : Message()
{
    this->body = std::move(body);
    code_ = static_cast<int>(code);
}

void
Response::writeTo(Tcp::Peer& peer)
{
    int fd = peer.fd();

    char buffer[Const::MaxBuffer];
    std::memset(buffer, 0, Const::MaxBuffer);
    Private::Writer fmt(buffer, sizeof buffer);

    fmt.writeString("HTTP/1.1 ");
    fmt.writeInt(code_);
    fmt.writeChar(' ');
    fmt.writeString(codeString(static_cast<Code>(code_)));
    fmt.writeRaw(CRLF, 2);

    for (const auto& header: headers.list()) {
        std::ostringstream oss;
        header->write(oss);

        std::string str = oss.str();
        fmt.writeRaw(str.c_str(), str.size());
        fmt.writeRaw(CRLF, 2);
    }

    fmt.writeHeader("Content-Length", body.size());

    fmt.writeRaw(CRLF, 2);
    fmt.writeString(body.c_str());

    const size_t len = fmt.cursor() - buffer;

    ssize_t bytes = send(fd, buffer, len, 0);
}

void
Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) {
    try {
        auto& parser = getParser(peer);
        if (!parser.feed(buffer, len)) {
            throw HttpError(Code::Request_Entity_Too_Large, "Request exceeded maximum buffer size");
        }

        auto state = parser.parse();
        if (state == Private::Parser::State::Done) {
            onRequest(parser.request, peer);
            parser.reset();
        }
    } catch (const HttpError &err) {
        Response response(err.code(), err.reason());
        response.writeTo(peer);
    }
    catch (const std::exception& e) {
        Response response(Code::Internal_Server_Error, e.what());
        response.writeTo(peer);
    }
}

void
Handler::onOutput() {
}

void
Handler::onConnection(Tcp::Peer& peer) {
    peer.setData(std::make_shared<Private::Parser>());
}

void
Handler::onDisconnection(Tcp::Peer& peer) {
}

Private::Parser&
Handler::getParser(Tcp::Peer& peer) {
    auto data = peer.data();
    return *std::static_pointer_cast<Private::Parser>(data);
}

Endpoint::Endpoint()
{ }

Endpoint::Endpoint(const Net::Address& addr)
    : listener(addr)
{ }

void
Endpoint::setHandler(const std::shared_ptr<Handler>& handler) {
    handler_ = handler;
}

void
Endpoint::serve()
{
    if (!handler_)
        throw std::runtime_error("Must call setHandler() prior to serve()");

    listener.init(8, Tcp::Options::InstallSignalHandler);
    listener.setHandler(handler_);

    if (listener.bind()) {
        const auto& addr = listener.address();
        cout << "Now listening on " << "http://" + addr.host() << ":" << addr.port() << endl;
        listener.run();
    }
}

} // namespace Http

} // namespace Net
<|endoftext|>


<commit_before>#include "./MainWindow.h"
#include "../Search.h"
#include "../Processer.h"

#include <iostream>
#include <gdkmm/rgba.h>
#include <gtk/gtk.h>
#include "SettingsWindow.h"
#include <gdkmm/pixbuf.h>
#include <gtkmm/icontheme.h>

using namespace std;

MainWindow::MainWindow(Logic& logic)
    : mLogic(logic)
{
    //Load settings
    mIgnoreClipboardChange = !mLogic.mTranslateClipboardAtStart;

    // Sets the border width of the window.
    this->set_border_width(10);
    this->set_default_size(mLogic.mSizeX, mLogic.mSizeY);
    this->move(mLogic.mPositionX, mLogic.mPositionY);
    this->set_keep_above(mLogic.mAlwaysOnTop);
    this->set_title("Dictionary");

    //Icons
    Glib::RefPtr<Gdk::Pixbuf> imagePlus
        = Gdk::Pixbuf::create_from_file("./share/icons/ic_add_black_24dp_1x.png");
    imagePlus->get_height();
    Gtk::IconTheme::add_builtin_icon("custom_icon_add", 4, imagePlus);

    Glib::RefPtr<Gdk::Pixbuf> imageSettings
        = Gdk::Pixbuf::create_from_file("./share/icons/ic_settings_black_24dp_1x.png");
    imageSettings->get_height();
    Gtk::IconTheme::add_builtin_icon("custom_icon_settings", 4, imageSettings);

    //--------------------------------------------------------------------------
    // settings button clicked shows settings window
    mSettingsButton.set_image_from_icon_name("custom_icon_settings");
    mSettingsButton.signal_clicked().connect([this](){
            if(mSettingsWindow)
                return;
            mSettingsWindow.reset(new SettingsWindow(mLogic));
            this->set_keep_above(false);
            mSettingsWindow->show();

            //refresh on settings closed
            mSettingsWindow->signal_hide().connect([this](){
                    // delete mSettingsWindow;
                    mSettingsWindow.reset(); //destructor is called
                    this->executeSearch(mWordInput.get_text());
                    this->set_keep_above(mLogic.mAlwaysOnTop);
                });
        });

    //--------------------------------------------------------------------------
    // Add word button
    mAddWordButton.set_image_from_icon_name("custom_icon_add");
    mAddWordButton.signal_clicked().connect([this]() {

        string leastKnownWord = "";

        //find word with lowest number of translations
        auto leastKnown = min_element(mTranslationResult.begin(),
            mTranslationResult.end(), [](auto &a, auto &b) {
                return a.second.size() < b.second.size();
            });
        if(leastKnown != mTranslationResult.end()){
            std::cout<<"leastKnown->first = "<<leastKnown->first<<std::endl;
            leastKnownWord = leastKnown->first;
        }

        mNewWordWindow.reset(new NewWordWindow(mLogic, leastKnownWord));
        this->set_keep_above(false);
        mNewWordWindow->show();
        mNewWordWindow->set_transient_for(*this);
        mNewWordWindow->set_keep_above(true);

        mNewWordWindow->signal_hide().connect([this]() {
            mNewWordWindow.reset();
            this->executeSearch(mWordInput.get_text());
            this->set_keep_above(mLogic.mAlwaysOnTop);
        });

    });

    //Grid
    add(mGrid);
    mGrid.set_column_spacing(5);

    //Grid - first row
    mGrid.add(mWordInput);
    mGrid.add(mAddWordButton);
    mGrid.add(mSettingsButton);

    //scrolling area for results
    mGrid.attach(mScrollForResults, 0,2,3,1);
    mScrollForResults.set_hexpand();
    mScrollForResults.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC,
                                 Gtk::PolicyType::POLICY_ALWAYS);
    mScrollForResults.add(mTreeView);
    mScrollForResults.set_margin_top(10);
    mScrollForResults.set_min_content_width(400);
    mScrollForResults.set_min_content_height(200);

    //--------------------------------------------------------------------------
    //results treeView
    mRefListStore = Gtk::ListStore::create(mColumns);
    mTreeView.set_model(mRefListStore);
    mTreeView.set_hexpand();
    mTreeView.set_vexpand();

    //Word Culumn
    {
        mTreeView.append_column("Word", mColumns.mGerman);
        Gtk::TreeViewColumn *pColumn = mTreeView.get_column(0);
        pColumn->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_AUTOSIZE);
        Gdk::Color col("#ffaa00");
        static_cast<Gtk::CellRendererText *>(pColumn->get_first_cell())
            ->property_foreground_gdk()
            .set_value(col);
    }
    //Match Culumn
    {
        mTreeView.append_column("Match", mColumns.mGerman_found);
        Gtk::TreeViewColumn *pColumn = mTreeView.get_column(1);
        pColumn->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_AUTOSIZE);
        pColumn->set_cell_data_func(
            *pColumn->get_first_cell(),
            [this](Gtk::CellRenderer *renderer,
                   const Gtk::TreeModel::iterator &iter)
            {
                Gtk::TreeModel::Row row = *iter;
                Gdk::Color col("#ff0000");
                auto score = row[this->mColumns.mScore];
                if(score < 0)
                    score = 0;
                if(score > 4)
                    score = 4;
                switch (score)
                {
                    //TODO add more colors
                    case 0:
                        col.set("#40B640");
                        break;
                    case 1:
                        col.set("#82B640");
                        break;
                    case 2:
                        col.set("#AFB640");
                        break;
                    case 3:
                        col.set("#B67E40");
                        break;
                    case 4:
                        col.set("#B64640");
                        break;
                    default:
                        break;
                }
                static_cast<Gtk::CellRendererText *>(renderer)
                    ->property_foreground_gdk()
                    .set_value(col);
            });
    }
    //Translation Culumn
    {
        mTreeView.append_column("Translation", mColumns.mEnglish);
        Gtk::TreeViewColumn* pColumn = mTreeView.get_column(2);
        pColumn->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_AUTOSIZE);
        static_cast<Gtk::CellRendererText *>(pColumn->get_first_cell())
            ->property_wrap_mode().set_value(Pango::WRAP_WORD_CHAR);
    }
    // mTreeView.append_column("Score", mColumns.mScore);

    //deal with resizing
    this->signal_check_resize().connect([this]()
    {
        #ifdef _WIN32
        const int padding_for_wrap_def = 160;
        #else
        const int padding_for_wrap_def = 30;
        #endif
        //calculate remaining size
        Gtk::TreeViewColumn* pColumn = mTreeView.get_column(2);
        auto width = this->get_allocated_width()
            - mTreeView.get_column(0)->get_width()
            - mTreeView.get_column(1)->get_width()-padding_for_wrap_def;

        //minimum reasonable size for column
        if(width < 150)
            width = 150;

        static_cast<Gtk::CellRendererText *>(pColumn->get_first_cell())
            ->property_wrap_width().set_value(width);

        //debounce
        static auto oldsize = 0;
        if(oldsize != width)
        {
            oldsize = width;

            //trigger redraw of mTreeView
            unique_lock<mutex> guard{this->mSearchMutex};
            this->mRedrawNeeded = true;
        }
    });

    // mWordInput.set_text("Put here text to translation...");
    mWordInput.set_text("Das ist einee CKatze Katzeee abbestellt begeststellenai...");
    mWordInput.set_hexpand();

    this->show_all_children();

    //make pulse called repeatedly every 100ms
    sigc::slot<bool> my_slot = sigc::bind(
        sigc::mem_fun(*this, &MainWindow::pulse), 0);
    mPulseConnection = Glib::signal_timeout().connect(my_slot, 150);
}
//------------------------------------------------------------------------------
MainWindow::~MainWindow()
{
    // present refreshes window position
    this->present();

    //saves data to logic, this is then saved to json config file
    this->get_position(mLogic.mPositionX, mLogic.mPositionY);
    this->get_size(mLogic.mSizeX, mLogic.mSizeY);
}
//-----------------------------------------------------------------------------------
bool MainWindow::pulse(int num)
{
    ignore_arg(num);

    //check if text has changed
    Glib::ustring tmp = mWordInput.get_text();
    if( mOldTextInEntry != tmp)
    {
        mOldTextInEntry = tmp;
        std::cout << "changed..." << std::endl;
        //todo max size of the text

        executeSearch(tmp);
    }

    Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
    refClipboard->request_text(
        sigc::mem_fun(*this, &MainWindow::on_clipboard_received) );

    unique_lock<mutex> guard{mSearchMutex};
    if(mNewTranslationAvailable || mRedrawNeeded)
    {
        mRefListStore->clear();

        //for all words, push results to ListStore
        for(auto &&w : mTranslationWords)
        {
            auto &rr = mTranslationResult[w];
            bool first = true;
            for(auto &&r : rr)
            {
                Gtk::TreeModel::iterator iter = mRefListStore->append();
                Gtk::TreeModel::Row row = *iter;
                if (first)
                    row[mColumns.mGerman] = w;
                first = false;
                row[mColumns.mGerman_found] = r.match;
                row[mColumns.mEnglish] = r.words;
                row[mColumns.mScore] = r.score;
            }
            //if no match found, still display atleast the word
            if (first){
                Gtk::TreeModel::iterator iter = mRefListStore->append();
                (*iter)[mColumns.mGerman] = w;
            }
        }
        mNewTranslationAvailable = false;
        mRedrawNeeded = false;
    }

    return true;
}
//------------------------------------------------------------------------------
void MainWindow::executeSearch(Glib::ustring text)
{
    unique_lock<mutex> guard{mSearchMutex};
    mWaitingToTranslate = text;

    if(!mSearchInProgress)
    {
        mSearchInProgress = true;
        guard.unlock();
        std::thread thread {&MainWindow::searchThread, this};
        thread.detach();
    }

}
//------------------------------------------------------------------------------
void MainWindow::searchThread()
{
    string text;

    unique_lock<mutex> guard(mSearchMutex);
    while(true)
    {
        //load string and set it to empty
        text = mWaitingToTranslate;
        mWaitingToTranslate = "";
        guard.unlock();

        //translate, during translation can Pulse add new string to translate
        int numthreads = std::thread::hardware_concurrency();
        numthreads = (numthreads > 1) ? numthreads : 1;
        std::vector<string> words = Processer::splitToWords(text.c_str());

        workerResult results = _search(mLogic.mDicts, numthreads, words, false);
        cout << "results are here" << endl;
        // for(auto &&w : words)
        // {
        //     auto &rr = results[w];
        //     cout << w << endl;
        //     for(auto &&r : rr)
        //     {
        //         cout << "  " << r.score << ":" << r.match << " -" << r.words
        //              << endl;
        //     }
        // }

        //lock and test if there is another string to translate
        guard.lock();
        mTranslationResult = results;
        mTranslationWords = words;
        mNewTranslationAvailable = true;
        if(mWaitingToTranslate == "")
            break;
    }

    cout<<"Finish"<<endl;
    mSearchInProgress = false;
}
//------------------------------------------------------------------------------
void MainWindow::on_clipboard_received(const Glib::ustring &data)
{
    // check if new text is in the clipboard
    Glib::ustring text =  data;
    if (text.size() > 256)
        text = text.substr(0, 256);

    if(mOldClipboard != text)
    {
        mOldClipboard = text;
        if(!mIgnoreClipboardChange)
        {
            std::cout << "Clipboard changed..." << std::endl;
            mWordInput.set_text(text);
            // we do not need to execute search, since pulse does that for us
            // when text is changed.
        }
        mIgnoreClipboardChange = false;
    }
}
//------------------------------------------------------------------------------
<commit_msg>glitches with resizing fixed<commit_after>#include "./MainWindow.h"
#include "../Search.h"
#include "../Processer.h"

#include <iostream>
#include <gdkmm/rgba.h>
#include <gtk/gtk.h>
#include "SettingsWindow.h"
#include <gdkmm/pixbuf.h>
#include <gtkmm/icontheme.h>

using namespace std;

MainWindow::MainWindow(Logic& logic)
    : mLogic(logic)
{
    //Load settings
    mIgnoreClipboardChange = !mLogic.mTranslateClipboardAtStart;

    // Sets the border width of the window.
    this->set_border_width(10);
    this->set_default_size(mLogic.mSizeX, mLogic.mSizeY);
    this->move(mLogic.mPositionX, mLogic.mPositionY);
    this->set_keep_above(mLogic.mAlwaysOnTop);
    this->set_title("Dictionary");

    //Icons
    Glib::RefPtr<Gdk::Pixbuf> imagePlus
        = Gdk::Pixbuf::create_from_file("./share/icons/ic_add_black_24dp_1x.png");
    imagePlus->get_height();
    Gtk::IconTheme::add_builtin_icon("custom_icon_add", 4, imagePlus);

    Glib::RefPtr<Gdk::Pixbuf> imageSettings
        = Gdk::Pixbuf::create_from_file("./share/icons/ic_settings_black_24dp_1x.png");
    imageSettings->get_height();
    Gtk::IconTheme::add_builtin_icon("custom_icon_settings", 4, imageSettings);

    //--------------------------------------------------------------------------
    // settings button clicked shows settings window
    mSettingsButton.set_image_from_icon_name("custom_icon_settings");
    mSettingsButton.signal_clicked().connect([this](){
            if(mSettingsWindow)
                return;
            mSettingsWindow.reset(new SettingsWindow(mLogic));
            this->set_keep_above(false);
            mSettingsWindow->show();

            //refresh on settings closed
            mSettingsWindow->signal_hide().connect([this](){
                    // delete mSettingsWindow;
                    mSettingsWindow.reset(); //destructor is called
                    this->executeSearch(mWordInput.get_text());
                    this->set_keep_above(mLogic.mAlwaysOnTop);
                });
        });

    //--------------------------------------------------------------------------
    // Add word button
    mAddWordButton.set_image_from_icon_name("custom_icon_add");
    mAddWordButton.signal_clicked().connect([this]() {

        string leastKnownWord = "";

        //find word with lowest number of translations
        auto leastKnown = min_element(mTranslationResult.begin(),
            mTranslationResult.end(), [](auto &a, auto &b) {
                return a.second.size() < b.second.size();
            });
        if(leastKnown != mTranslationResult.end()){
            std::cout<<"leastKnown->first = "<<leastKnown->first<<std::endl;
            leastKnownWord = leastKnown->first;
        }

        mNewWordWindow.reset(new NewWordWindow(mLogic, leastKnownWord));
        this->set_keep_above(false);
        mNewWordWindow->show();
        mNewWordWindow->set_transient_for(*this);
        mNewWordWindow->set_keep_above(true);

        mNewWordWindow->signal_hide().connect([this]() {
            mNewWordWindow.reset();
            this->executeSearch(mWordInput.get_text());
            this->set_keep_above(mLogic.mAlwaysOnTop);
        });

    });

    //Grid
    add(mGrid);
    mGrid.set_column_spacing(5);

    //Grid - first row
    mGrid.add(mWordInput);
    mGrid.add(mAddWordButton);
    mGrid.add(mSettingsButton);

    //scrolling area for results
    mGrid.attach(mScrollForResults, 0,2,3,1);
    mScrollForResults.set_hexpand();
    mScrollForResults.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC,
                                 Gtk::PolicyType::POLICY_ALWAYS);
    mScrollForResults.add(mTreeView);
    mScrollForResults.set_margin_top(10);
    mScrollForResults.set_min_content_width(400);
    mScrollForResults.set_min_content_height(200);

    //--------------------------------------------------------------------------
    //results treeView
    mRefListStore = Gtk::ListStore::create(mColumns);
    mTreeView.set_model(mRefListStore);
    mTreeView.set_hexpand();
    mTreeView.set_vexpand();

    //Word Culumn
    {
        mTreeView.append_column("Word", mColumns.mGerman);
        Gtk::TreeViewColumn *pColumn = mTreeView.get_column(0);
        // pColumn->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_AUTOSIZE);
        // neccessary to prevent glitches
        pColumn->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_GROW_ONLY);
        Gdk::Color col("#ffaa00");
        static_cast<Gtk::CellRendererText *>(pColumn->get_first_cell())
            ->property_foreground_gdk()
            .set_value(col);
    }
    //Match Culumn
    {
        mTreeView.append_column("Match", mColumns.mGerman_found);
        Gtk::TreeViewColumn *pColumn = mTreeView.get_column(1);
        pColumn->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_AUTOSIZE);
        pColumn->set_cell_data_func(
            *pColumn->get_first_cell(),
            [this](Gtk::CellRenderer *renderer,
                   const Gtk::TreeModel::iterator &iter)
            {
                Gtk::TreeModel::Row row = *iter;
                Gdk::Color col("#ff0000");
                auto score = row[this->mColumns.mScore];
                if(score < 0)
                    score = 0;
                if(score > 4)
                    score = 4;
                switch (score)
                {
                    //TODO add more colors
                    case 0:
                        col.set("#40B640");
                        break;
                    case 1:
                        col.set("#82B640");
                        break;
                    case 2:
                        col.set("#AFB640");
                        break;
                    case 3:
                        col.set("#B67E40");
                        break;
                    case 4:
                        col.set("#B64640");
                        break;
                    default:
                        break;
                }
                static_cast<Gtk::CellRendererText *>(renderer)
                    ->property_foreground_gdk()
                    .set_value(col);
            });
    }
    //Translation Culumn
    {
        mTreeView.append_column("Translation", mColumns.mEnglish);
        Gtk::TreeViewColumn* pColumn = mTreeView.get_column(2);
        pColumn->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_AUTOSIZE);
        static_cast<Gtk::CellRendererText *>(pColumn->get_first_cell())
            ->property_wrap_mode().set_value(Pango::WRAP_WORD_CHAR);
    }
    // mTreeView.append_column("Score", mColumns.mScore);

    //deal with resizing
    this->signal_check_resize().connect([this]()
    {
        #ifdef _WIN32
        const int padding_for_wrap_def = 160;
        #else
        const int padding_for_wrap_def = 30;
        #endif
        //calculate remaining size
        Gtk::TreeViewColumn* pColumn = mTreeView.get_column(2);
        auto width = this->get_allocated_width()
            - mTreeView.get_column(0)->get_width()
            - mTreeView.get_column(1)->get_width()-padding_for_wrap_def;

        //minimum reasonable size for column
        if(width < 150)
            width = 150;

        static_cast<Gtk::CellRendererText *>(pColumn->get_first_cell())
            ->property_wrap_width().set_value(width);

        //debounce
        static auto oldsize = 0;
        if(oldsize != width)
        {
            oldsize = width;

            //trigger redraw of mTreeView
            unique_lock<mutex> guard{this->mSearchMutex};
            this->mRedrawNeeded = true;
        }
    });

    // mWordInput.set_text("Put here text to translation...");
    mWordInput.set_text("Das ist einee CKatze Katzeee abbestellt begeststellenai...");
    mWordInput.set_hexpand();

    this->show_all_children();

    //make pulse called repeatedly every 100ms
    sigc::slot<bool> my_slot = sigc::bind(
        sigc::mem_fun(*this, &MainWindow::pulse), 0);
    mPulseConnection = Glib::signal_timeout().connect(my_slot, 150);
}
//------------------------------------------------------------------------------
MainWindow::~MainWindow()
{
    // present refreshes window position
    this->present();

    //saves data to logic, this is then saved to json config file
    this->get_position(mLogic.mPositionX, mLogic.mPositionY);
    this->get_size(mLogic.mSizeX, mLogic.mSizeY);
}
//-----------------------------------------------------------------------------------
bool MainWindow::pulse(int num)
{
    ignore_arg(num);

    //check if text has changed
    Glib::ustring tmp = mWordInput.get_text();
    if( mOldTextInEntry != tmp)
    {
        mOldTextInEntry = tmp;
        std::cout << "changed..." << std::endl;
        //todo max size of the text

        executeSearch(tmp);
    }

    Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
    refClipboard->request_text(
        sigc::mem_fun(*this, &MainWindow::on_clipboard_received) );

    // If there is new translation, fill the treeview with new data
    unique_lock<mutex> guard{mSearchMutex};
    if(mNewTranslationAvailable || mRedrawNeeded)
    {
        mRefListStore->clear();

        //for all words, push results to ListStore
        for(auto &&w : mTranslationWords)
        {
            auto &rr = mTranslationResult[w];
            bool first = true;
            for(auto &&r : rr)
            {
                Gtk::TreeModel::iterator iter = mRefListStore->append();
                Gtk::TreeModel::Row row = *iter;
                if (first)
                    row[mColumns.mGerman] = w;
                first = false;
                row[mColumns.mGerman_found] = r.match;
                row[mColumns.mEnglish] = r.words;
                row[mColumns.mScore] = r.score;
            }
            //if no match found, still display atleast the word
            if (first){
                Gtk::TreeModel::iterator iter = mRefListStore->append();
                (*iter)[mColumns.mGerman] = w;
            }
        }
        //shrink culumns to fit the size
        this->mTreeView.columns_autosize();
        mNewTranslationAvailable = false;
        mRedrawNeeded = false;
    }

    return true;
}
//------------------------------------------------------------------------------
void MainWindow::executeSearch(Glib::ustring text)
{
    unique_lock<mutex> guard{mSearchMutex};
    mWaitingToTranslate = text;

    if(!mSearchInProgress)
    {
        mSearchInProgress = true;
        guard.unlock();
        std::thread thread {&MainWindow::searchThread, this};
        thread.detach();
    }

}
//------------------------------------------------------------------------------
void MainWindow::searchThread()
{
    string text;

    unique_lock<mutex> guard(mSearchMutex);
    while(true)
    {
        //load string and set it to empty
        text = mWaitingToTranslate;
        mWaitingToTranslate = "";
        guard.unlock();

        //translate, during translation can Pulse add new string to translate
        int numthreads = std::thread::hardware_concurrency();
        numthreads = (numthreads > 1) ? numthreads : 1;
        std::vector<string> words = Processer::splitToWords(text.c_str());

        workerResult results = _search(mLogic.mDicts, numthreads, words, false);
        cout << "results are here" << endl;
        // for(auto &&w : words)
        // {
        //     auto &rr = results[w];
        //     cout << w << endl;
        //     for(auto &&r : rr)
        //     {
        //         cout << "  " << r.score << ":" << r.match << " -" << r.words
        //              << endl;
        //     }
        // }

        //lock and test if there is another string to translate
        guard.lock();
        mTranslationResult = results;
        mTranslationWords = words;
        mNewTranslationAvailable = true;
        if(mWaitingToTranslate == "")
            break;
    }

    cout<<"Finish"<<endl;
    mSearchInProgress = false;
}
//------------------------------------------------------------------------------
void MainWindow::on_clipboard_received(const Glib::ustring &data)
{
    // check if new text is in the clipboard
    Glib::ustring text =  data;
    if (text.size() > 256)
        text = text.substr(0, 256);

    if(mOldClipboard != text)
    {
        mOldClipboard = text;
        if(!mIgnoreClipboardChange)
        {
            std::cout << "Clipboard changed..." << std::endl;
            mWordInput.set_text(text);
            // we do not need to execute search, since pulse does that for us
            // when text is changed.
        }
        mIgnoreClipboardChange = false;
    }
}
//------------------------------------------------------------------------------
<|endoftext|>