<commit_before>#pragma once

#include <string>
#include <ctime>
#include <glm/glm.hpp>
#include "linking.hpp"

/// Logging class.
/**
 * Usage:
 * @code{.cpp}
 * Log() << "Testing: " << 5 << "\n";
 * @endcode
 */
class Log {
    public:
        UTILITY_API const enum Channel {
            DEFAULT = 0,    ///< Default channel.
            INFO,           ///< Information.
            WARNING,        ///< Warnings.
            ERR,            ///< Error.
            CONSOLE,        ///< Console.
            MAX             ///< Maximum number of channels, ensure this is the last element of the enum if adding channels.
        };

        /// Destructor.
        UTILITY_API ~Log();

        /// Output some text to stderr.
        /**
         * @param text Text to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(std::string text);

        /// Output an integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(int value);

        /// Output an unsigned integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(unsigned int value);

        /// Output a float to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(float value);

        /// Output a double to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(double value);

        /// Output a time to stderr.
        /**
         * Formatted Y-m-d H:M:S.
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(time_t value);

        /// Output a vec2 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec2& value);

        /// Output a vec3 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec3& value);

        /// Output a vec4 to stderr.
        /**
        * @param value Value to output.
        * @return The %Log instance.
        */
        UTILITY_API Log& operator<<(const glm::vec4& value);
};
<commit_msg>Changed name of max to number of channels.<commit_after>#pragma once

#include <string>
#include <ctime>
#include <glm/glm.hpp>
#include "linking.hpp"

/// Logging class.
/**
 * Usage:
 * @code{.cpp}
 * Log() << "Testing: " << 5 << "\n";
 * @endcode
 */
class Log {
    public:
        UTILITY_API const enum Channel {
            DEFAULT = 0,        ///< Default channel.
            INFO,               ///< Information.
            WARNING,            ///< Warnings.
            ERR,                ///< Error.
            CONSOLE,            ///< Console.
            NUMBER_OF_CHANNELS  ///< Maximum number of channels, ensure this is the last element of the enum if adding channels.
        };

        /// Destructor.
        UTILITY_API ~Log();

        /// Output some text to stderr.
        /**
         * @param text Text to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(std::string text);

        /// Output an integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(int value);

        /// Output an unsigned integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(unsigned int value);

        /// Output a float to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(float value);

        /// Output a double to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(double value);

        /// Output a time to stderr.
        /**
         * Formatted Y-m-d H:M:S.
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(time_t value);

        /// Output a vec2 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec2& value);

        /// Output a vec3 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec3& value);

        /// Output a vec4 to stderr.
        /**
        * @param value Value to output.
        * @return The %Log instance.
        */
        UTILITY_API Log& operator<<(const glm::vec4& value);
};
<|endoftext|>


<commit_before>#include "VideoDevice.hpp"
#include <opencv2/opencv.hpp>
using namespace cv;

VideoDevice::VideoDevice(){
    //does absolutely nothing
}

void VideoDevice::startCapture(int id){
    camera = VideoCapture(id);
}

Mat VideoDevice:: getImage(){
    takeImage();
    return image;
}

void VideoDevice::takeImage(){
    camera >> image;
}
<commit_msg>Deleting old files<commit_after><|endoftext|>


<commit_before>/*
TPC DA for online calibration

Contact: Haavard.Helstrup@cern.ch
Link:
Run Type: PULSER_RUN
DA Type: LDC
Number of events needed: 100
Input Files:
Output Files: tpcPulser.root, to be exported to the DAQ FXS
fileId:   pulser
Trigger types used: CALIBRATION_EVENT

*/

/*

TPCda_pulser.cxx - calibration algorithm for TPC pulser events

10/06/2007  sylvain.chapeland@cern.ch :  first version - clean skeleton based on DAQ DA case1
30/09/2007  haavard.helstrup@cern.ch  :  created pulser DA based on pedestal code

contact: marian.ivanov@cern.ch

This process reads RAW data from the files provided as command line arguments
and save results in a file (named from RESULT_FILE define - see below).

*/

#define RESULT_FILE "tpcPulser.root"
#define FILE_ID "pulser"
#define MAPPING_FILE "tpcMapping.root"
#define AliDebugLevel() -1

#include <daqDA.h>
#include "event.h"
#include "monitor.h"
#include <stdio.h>
#include <stdlib.h>

//
//Root includes
//
#include <TFile.h>
#include "TROOT.h"
#include "TPluginManager.h"
//
//AliRoot includes
//
#include "AliRawReader.h"
#include "AliRawReaderDate.h"
#include "AliTPCmapper.h"
#include "AliTPCRawStream.h"
#include "AliTPCROC.h"
#include "AliTPCCalROC.h"
#include "AliTPCCalPad.h"
#include "AliMathBase.h"
#include "TTreeStream.h"
#include "AliLog.h"
#include "TSystem.h"

//
// TPC calibration algorithm includes
//
#include "AliTPCCalibPulser.h"

/* Main routine
      Arguments: list of DATE raw data files
*/
int main(int argc, char **argv) {
  AliLog::SetClassDebugLevel("AliTPCRawStream",-5);
  AliLog::SetClassDebugLevel("AliRawReaderDate",-5);
  AliLog::SetClassDebugLevel("AliTPCAltroMapping",-5);
  AliLog::SetModuleDebugLevel("RAW",-5);

 gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo",
                                         "*",
                                         "TStreamerInfo",
                                         "RIO",
                                         "TStreamerInfo()");

  int i,status;
  AliTPCmapper *mapping = 0;   // The TPC mapping
  // if  test setup get parameters from $DAQDA_TEST_DIR

  if (!mapping){
    /* copy locally the mapping file from daq detector config db */
    status = daqDA_DB_getFile(MAPPING_FILE,"./tpcMapping.root");
    if (status) {
      printf("Failed to get mapping file (%s) from DAQdetDB, status=%d\n", MAPPING_FILE, status);
      printf("Continue anyway ... maybe it works?\n");              // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      return -1;   // temporarily uncommented for testing on pcald47 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    }

    /* open the mapping file and retrieve mapping object */
    TFile *fileMapping = new TFile(MAPPING_FILE, "read");
    mapping = (AliTPCmapper*) fileMapping->Get("tpcMapping");
    delete fileMapping;
  }

  if (mapping == 0) {
    printf("Failed to get mapping object from %s.  ...\n", MAPPING_FILE);
    //return -1;
  } else {
    printf("Got mapping object from %s\n", MAPPING_FILE);
  }

  AliTPCCalibPulser calibPulser;   // pedestal and noise calibration

  if (argc<2) {
    printf("Wrong number of arguments\n");
    return -1;
  }

  /* log start of process */
  printf("TPC Pulser DA started - %s\n",__FILE__);

  /* set time bin range */
  calibPulser.SetRangeTime(400,500);
  calibPulser.SetAltroMapping(mapping->GetAltroMapping()); // Use altro mapping we got from daqDetDb
  /* declare monitoring program */
  status=monitorDeclareMp( __FILE__ );
  if (status!=0) {
    printf("monitorDeclareMp() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* loop over RAW data files */
  int nevents=0;
  for(i=1;i<argc;i++) {

    /* define data source : this is argument i */
    printf("Processing file %s\n", argv[i]);
    status=monitorSetDataSource( argv[i] );
    if (status!=0) {
      printf("monitorSetDataSource() failed : %s\n",monitorDecodeError(status));
      return -1;
    }

    /* read until EOF */
    while (true) {
      struct eventHeaderStruct *event;

      /* check shutdown condition */
      if (daqDA_checkShutdown()) {break;}

      /* get next event (blocking call until timeout) */
      status=monitorGetEventDynamic((void **)&event);
      if (status==MON_ERR_EOF) {
        printf ("End of File %d detected\n",i);
        break; /* end of monitoring file has been reached */
      }

      if (status!=0) {
        printf("monitorGetEventDynamic() failed : %s\n",monitorDecodeError(status));
        break;
      }

      /* retry if got no event */
      if (event==NULL) {
        continue;
      }
      nevents++;

      //  Pulser calibration

      AliRawReader *rawReader = new AliRawReaderDate((void*)event);
//      calibPulser.ProcessEvent(rawReader);
      calibPulser.ProcessEventFast(rawReader);
      delete rawReader;

      /* free resources */
      free(event);
    }
  }

  calibPulser.Analyse();
  printf ("%d events processed\n",nevents);

  TFile * fileTPC = new TFile (RESULT_FILE,"recreate");
  calibPulser.Write("tpcCalibPulser");
  delete fileTPC;
  printf("Wrote %s\n",RESULT_FILE);

  /* store the result file on FES */

  status=daqDA_FES_storeFile(RESULT_FILE,FILE_ID);
  if (status) {
    status = -2;
  }

  return status;
}
<commit_msg>Updated run type specification (CALIBRATION_PULSER)<commit_after>/*
TPC DA for online calibration

Contact: Haavard.Helstrup@cern.ch
Link:
Run Type: CALIBRATION_PULSER
DA Type: LDC
Number of events needed: 100
Input Files:
Output Files: tpcPulser.root, to be exported to the DAQ FXS
fileId:   pulser
Trigger types used: CALIBRATION_EVENT

*/

/*

TPCda_pulser.cxx - calibration algorithm for TPC pulser events

10/06/2007  sylvain.chapeland@cern.ch :  first version - clean skeleton based on DAQ DA case1
30/09/2007  haavard.helstrup@cern.ch  :  created pulser DA based on pedestal code

contact: marian.ivanov@cern.ch

This process reads RAW data from the files provided as command line arguments
and save results in a file (named from RESULT_FILE define - see below).

*/

#define RESULT_FILE "tpcPulser.root"
#define FILE_ID "pulser"
#define MAPPING_FILE "tpcMapping.root"
#define AliDebugLevel() -1

#include <daqDA.h>
#include "event.h"
#include "monitor.h"
#include <stdio.h>
#include <stdlib.h>

//
//Root includes
//
#include <TFile.h>
#include "TROOT.h"
#include "TPluginManager.h"
//
//AliRoot includes
//
#include "AliRawReader.h"
#include "AliRawReaderDate.h"
#include "AliTPCmapper.h"
#include "AliTPCRawStream.h"
#include "AliTPCROC.h"
#include "AliTPCCalROC.h"
#include "AliTPCCalPad.h"
#include "AliMathBase.h"
#include "TTreeStream.h"
#include "AliLog.h"
#include "TSystem.h"

//
// TPC calibration algorithm includes
//
#include "AliTPCCalibPulser.h"

/* Main routine
      Arguments: list of DATE raw data files
*/
int main(int argc, char **argv) {
  AliLog::SetClassDebugLevel("AliTPCRawStream",-5);
  AliLog::SetClassDebugLevel("AliRawReaderDate",-5);
  AliLog::SetClassDebugLevel("AliTPCAltroMapping",-5);
  AliLog::SetModuleDebugLevel("RAW",-5);

 gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo",
                                         "*",
                                         "TStreamerInfo",
                                         "RIO",
                                         "TStreamerInfo()");

  int i,status;
  AliTPCmapper *mapping = 0;   // The TPC mapping
  // if  test setup get parameters from $DAQDA_TEST_DIR

  if (!mapping){
    /* copy locally the mapping file from daq detector config db */
    status = daqDA_DB_getFile(MAPPING_FILE,"./tpcMapping.root");
    if (status) {
      printf("Failed to get mapping file (%s) from DAQdetDB, status=%d\n", MAPPING_FILE, status);
      printf("Continue anyway ... maybe it works?\n");              // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      return -1;   // temporarily uncommented for testing on pcald47 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    }

    /* open the mapping file and retrieve mapping object */
    TFile *fileMapping = new TFile(MAPPING_FILE, "read");
    mapping = (AliTPCmapper*) fileMapping->Get("tpcMapping");
    delete fileMapping;
  }

  if (mapping == 0) {
    printf("Failed to get mapping object from %s.  ...\n", MAPPING_FILE);
    //return -1;
  } else {
    printf("Got mapping object from %s\n", MAPPING_FILE);
  }

  AliTPCCalibPulser calibPulser;   // pedestal and noise calibration

  if (argc<2) {
    printf("Wrong number of arguments\n");
    return -1;
  }

  /* log start of process */
  printf("TPC Pulser DA started - %s\n",__FILE__);

  /* set time bin range */
  calibPulser.SetRangeTime(400,500);
  calibPulser.SetAltroMapping(mapping->GetAltroMapping()); // Use altro mapping we got from daqDetDb
  /* declare monitoring program */
  status=monitorDeclareMp( __FILE__ );
  if (status!=0) {
    printf("monitorDeclareMp() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* loop over RAW data files */
  int nevents=0;
  for(i=1;i<argc;i++) {

    /* define data source : this is argument i */
    printf("Processing file %s\n", argv[i]);
    status=monitorSetDataSource( argv[i] );
    if (status!=0) {
      printf("monitorSetDataSource() failed : %s\n",monitorDecodeError(status));
      return -1;
    }

    /* read until EOF */
    while (true) {
      struct eventHeaderStruct *event;

      /* check shutdown condition */
      if (daqDA_checkShutdown()) {break;}

      /* get next event (blocking call until timeout) */
      status=monitorGetEventDynamic((void **)&event);
      if (status==MON_ERR_EOF) {
        printf ("End of File %d detected\n",i);
        break; /* end of monitoring file has been reached */
      }

      if (status!=0) {
        printf("monitorGetEventDynamic() failed : %s\n",monitorDecodeError(status));
        break;
      }

      /* retry if got no event */
      if (event==NULL) {
        continue;
      }
      nevents++;

      //  Pulser calibration

      AliRawReader *rawReader = new AliRawReaderDate((void*)event);
//      calibPulser.ProcessEvent(rawReader);
      calibPulser.ProcessEventFast(rawReader);
      delete rawReader;

      /* free resources */
      free(event);
    }
  }

  calibPulser.Analyse();
  printf ("%d events processed\n",nevents);

  TFile * fileTPC = new TFile (RESULT_FILE,"recreate");
  calibPulser.Write("tpcCalibPulser");
  delete fileTPC;
  printf("Wrote %s\n",RESULT_FILE);

  /* store the result file on FES */

  status=daqDA_FES_storeFile(RESULT_FILE,FILE_ID);
  if (status) {
    status = -2;
  }

  return status;
}
<|endoftext|>


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

#include <graphene/chain/database.hpp>

#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <fc/io/fstream.hpp>

#include <fstream>
#include <functional>
#include <iostream>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database()
{
   clear_pending();
}

void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
{ try {
   ilog( "reindexing blockchain" );
   wipe(data_dir, false);
   open(data_dir, [&initial_allocation]{return initial_allocation;});

   auto start = fc::time_point::now();
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }

   const auto last_block_num = last_block->block_num();

   ilog( "Replaying blocks..." );
   _undo_db.disable();
   for( uint32_t i = 1; i <= last_block_num; ++i )
   {
      if( i % 2000 == 0 ) std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      fc::optional< signed_block > block = _block_id_to_block.fetch_by_number(i);
      if( !block.valid() )
      {
         wlog( "Reindexing terminated due to gap:  Block ${i} does not exist!", ("i", i) );
         uint32_t dropped_count = 0;
         while( true )
         {
            fc::optional< block_id_type > last_id = _block_id_to_block.last_id();
            // this can trigger if we attempt to e.g. read a file that has block #2 but no block #1
            if( !last_id.valid() )
               break;
            // we've caught up to the gap
            if( block_header::num_from_id( *last_id ) <= i )
               break;
            _block_id_to_block.remove( *last_id );
            dropped_count++;
         }
         wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
         break;
      }
      apply_block(*block, skip_witness_signature |
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_witness_schedule_check |
                          skip_authority_check);
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   close();
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader)
{
   try
   {
      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());

      fc::optional<signed_block> last_block = _block_id_to_block.last();
      if( last_block.valid() )
      {
         _fork_db.start_block( *last_block );
         idump((last_block->id())(last_block->block_num()));
         idump((head_block_id())(head_block_num()));
         if( last_block->id() != head_block_id() )
         {
              FC_ASSERT( head_block_num() == 0, "last block ID does not match current chain state",
                         ("last_block->id", last_block->id())("head_block_num",head_block_num()) );
         }
      }
   }
   FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )
}

void database::close(bool rewind)
{
   // TODO:  Save pending tx's on close()
   clear_pending();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   if( rewind )
   {
      try
      {
         uint32_t cutoff = get_dynamic_global_properties().last_irreversible_block_num;

         while( head_block_num() > cutoff )
         {
         //   elog("pop");
            block_id_type popped_block_id = head_block_id();
            pop_block();
            _fork_db.remove(popped_block_id); // doesn't throw on missing
            try
            {
               _block_id_to_block.remove(popped_block_id);
            }
            catch (const fc::key_not_found_exception&)
            {
            }
         }
      }
      catch (...)
      {
      }
   }

   // Since pop_block() will move tx's in the popped blocks into pending,
   // we have to clear_pending() after we're done popping to get a clean
   // DB state (issue #336).
   clear_pending();

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();
}

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

#include <graphene/chain/database.hpp>

#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <fc/io/fstream.hpp>

#include <fstream>
#include <functional>
#include <iostream>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database()
{
   clear_pending();
}

void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
{ try {
   ilog( "reindexing blockchain" );
   wipe(data_dir, false);
   open(data_dir, [&initial_allocation]{return initial_allocation;});

   auto start = fc::time_point::now();
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }

   const auto last_block_num = last_block->block_num();

   ilog( "Replaying blocks..." );
   _undo_db.disable();
   for( uint32_t i = 1; i <= last_block_num; ++i )
   {
      if( i % 5000 == 0 ) std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      fc::optional< signed_block > block = _block_id_to_block.fetch_by_number(i);
      if( !block.valid() )
      {
         wlog( "Reindexing terminated due to gap:  Block ${i} does not exist!", ("i", i) );
         uint32_t dropped_count = 0;
         while( true )
         {
            fc::optional< block_id_type > last_id = _block_id_to_block.last_id();
            // this can trigger if we attempt to e.g. read a file that has block #2 but no block #1
            if( !last_id.valid() )
               break;
            // we've caught up to the gap
            if( block_header::num_from_id( *last_id ) <= i )
               break;
            _block_id_to_block.remove( *last_id );
            dropped_count++;
         }
         wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
         break;
      }
      apply_block(*block, skip_witness_signature |
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_witness_schedule_check |
                          skip_authority_check);
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   close();
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader)
{
   try
   {
      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());

      fc::optional<signed_block> last_block = _block_id_to_block.last();
      if( last_block.valid() )
      {
         _fork_db.start_block( *last_block );
         idump((last_block->id())(last_block->block_num()));
         idump((head_block_id())(head_block_num()));
         if( last_block->id() != head_block_id() )
         {
              FC_ASSERT( head_block_num() == 0, "last block ID does not match current chain state",
                         ("last_block->id", last_block->id())("head_block_num",head_block_num()) );
         }
      }
   }
   FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )
}

void database::close(bool rewind)
{
   // TODO:  Save pending tx's on close()
   clear_pending();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   if( rewind )
   {
      try
      {
         uint32_t cutoff = get_dynamic_global_properties().last_irreversible_block_num;

         while( head_block_num() > cutoff )
         {
         //   elog("pop");
            block_id_type popped_block_id = head_block_id();
            pop_block();
            _fork_db.remove(popped_block_id); // doesn't throw on missing
            try
            {
               _block_id_to_block.remove(popped_block_id);
            }
            catch (const fc::key_not_found_exception&)
            {
            }
         }
      }
      catch (...)
      {
      }
   }

   // Since pop_block() will move tx's in the popped blocks into pending,
   // we have to clear_pending() after we're done popping to get a clean
   // DB state (issue #336).
   clear_pending();

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();
}

} }
<|endoftext|>


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

namespace graphene { namespace chain {
fork_database::fork_database()
{
}
void fork_database::reset()
{
   _head.reset();
   _index.clear();
}

void fork_database::pop_block()
{
   FC_ASSERT( _head, "no block to pop" );
   auto prev = _head->prev.lock();
   FC_ASSERT( prev, "popping block would leave head block null" );
    _head = prev;
}

void     fork_database::start_block(signed_block b)
{
   auto item = std::make_shared<fork_item>(std::move(b));
   _index.insert(item);
   _head = item;
}

/**
 * Pushes the block into the fork database and caches it if it doesn't link
 *
 */
shared_ptr<fork_item>  fork_database::push_block(const signed_block& b)
{
   auto item = std::make_shared<fork_item>(b);
   try {
      _push_block(item);
   }
   catch ( const unlinkable_block_exception& e )
   {
      wlog( "Pushing block to fork database that failed to link: ${id}, ${num}", ("id",b.id())("num",b.block_num()) );
      wlog( "Head: ${num}, ${id}", ("num",_head->data.block_num())("id",_head->data.id()) );
      throw;
      _unlinked_index.insert( item );
   }
   return _head;
}

void  fork_database::_push_block(const item_ptr& item)
{
   if( _head ) // make sure the block is within the range that we are caching
   {
      FC_ASSERT( item->num > std::max<int64_t>( 0, int64_t(_head->num) - (_max_size) ),
                 "attempting to push a block that is too old",
                 ("item->num",item->num)("head",_head->num)("max_size",_max_size));
   }

   if( _head && item->previous_id() != block_id_type() )
   {
      auto& index = _index.get<block_id>();
      auto itr = index.find(item->previous_id());
      GRAPHENE_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain");
      item->prev = *itr;
   }

   _index.insert(item);
   if( !_head ) _head = item;
   else if( item->num > _head->num )
   {
      _head = item;
      uint32_t min_num = _head->num - std::min( _max_size, _head->num );
//      ilog( "min block in fork DB ${n}, max_size: ${m}", ("n",min_num)("m",_max_size) );
      auto& num_idx = _index.get<block_num>();
      while( num_idx.size() && (*num_idx.begin())->num < min_num )
         num_idx.erase( num_idx.begin() );

      _unlinked_index.get<block_num>().erase(_head->num - _max_size);
   }
   //_push_next( item );
}

/**
 *  Iterate through the unlinked cache and insert anything that
 *  links to the newly inserted item.  This will start a recursive
 *  set of calls performing a depth-first insertion of pending blocks as
 *  _push_next(..) calls _push_block(...) which will in turn call _push_next
 */
void fork_database::_push_next( const item_ptr& new_item )
{
    auto& prev_idx = _unlinked_index.get<by_previous>();

    auto itr = prev_idx.find( new_item->id );
    while( itr != prev_idx.end() )
    {
       auto tmp = *itr;
       prev_idx.erase( itr );
       _push_block( tmp );

       itr = prev_idx.find( new_item->id );
    }
}

void fork_database::set_max_size( uint32_t s )
{
   _max_size = s;
   if( !_head ) return;

   { /// index
      auto& by_num_idx = _index.get<block_num>();
      auto itr = by_num_idx.begin();
      while( itr != by_num_idx.end() )
      {
         if( (*itr)->num < std::max(int64_t(0),int64_t(_head->num) - _max_size) )
            by_num_idx.erase(itr);
         else
            break;
         itr = by_num_idx.begin();
      }
   }
   { /// unlinked_index
      auto& by_num_idx = _unlinked_index.get<block_num>();
      auto itr = by_num_idx.begin();
      while( itr != by_num_idx.end() )
      {
         if( (*itr)->num < std::max(int64_t(0),int64_t(_head->num) - _max_size) )
            by_num_idx.erase(itr);
         else
            break;
         itr = by_num_idx.begin();
      }
   }
}

bool fork_database::is_known_block(const block_id_type& id)const
{
   auto& index = _index.get<block_id>();
   auto itr = index.find(id);
   if( itr != index.end() )
      return true;
   auto& unlinked_index = _unlinked_index.get<block_id>();
   auto unlinked_itr = unlinked_index.find(id);
   return unlinked_itr != unlinked_index.end();
}

item_ptr fork_database::fetch_block(const block_id_type& id)const
{
   auto& index = _index.get<block_id>();
   auto itr = index.find(id);
   if( itr != index.end() )
      return *itr;
   auto& unlinked_index = _unlinked_index.get<block_id>();
   auto unlinked_itr = unlinked_index.find(id);
   if( unlinked_itr != unlinked_index.end() )
      return *unlinked_itr;
   return item_ptr();
}

vector<item_ptr> fork_database::fetch_block_by_number(uint32_t num)const
{
   vector<item_ptr> result;
   auto itr = _index.get<block_num>().find(num);
   while( itr != _index.get<block_num>().end() )
   {
      if( (*itr)->num == num )
         result.push_back( *itr );
      else
         break;
      ++itr;
   }
   return result;
}

pair<fork_database::branch_type,fork_database::branch_type>
  fork_database::fetch_branch_from(block_id_type first, block_id_type second)const
{ try {
   // This function gets a branch (i.e. vector<fork_item>) leading
   // back to the most recent common ancestor.
   pair<branch_type,branch_type> result;
   auto first_branch_itr = _index.get<block_id>().find(first);
   FC_ASSERT(first_branch_itr != _index.get<block_id>().end());
   auto first_branch = *first_branch_itr;

   auto second_branch_itr = _index.get<block_id>().find(second);
   FC_ASSERT(second_branch_itr != _index.get<block_id>().end());
   auto second_branch = *second_branch_itr;

   while( first_branch->data.block_num() > second_branch->data.block_num() )
   {
      result.first.push_back(first_branch);
      first_branch = first_branch->prev.lock();
      FC_ASSERT(first_branch);
   }
   while( second_branch->data.block_num() > first_branch->data.block_num() )
   {
      result.second.push_back( second_branch );
      second_branch = second_branch->prev.lock();
      FC_ASSERT(second_branch);
   }
   while( first_branch->data.previous != second_branch->data.previous )
   {
      result.first.push_back(first_branch);
      result.second.push_back(second_branch);
      first_branch = first_branch->prev.lock();
      FC_ASSERT(first_branch);
      second_branch = second_branch->prev.lock();
      FC_ASSERT(second_branch);
   }
   if( first_branch && second_branch )
   {
      result.first.push_back(first_branch);
      result.second.push_back(second_branch);
   }
   return result;
} FC_CAPTURE_AND_RETHROW( (first)(second) ) }

void fork_database::set_head(shared_ptr<fork_item> h)
{
   _head = h;
}

void fork_database::remove(block_id_type id)
{
   _index.get<block_id>().erase(id);
   // If we're removing head, try to pop it
   if( _head && _head->id == id )
   {
      try
      {
         pop_block();
      }
      catch( fc::exception& e ) // If unable to pop normally, E.G. if head's prev is null, reset it
      {
         _head.reset();
      }
   }
}

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

#include <fc/smart_ref_impl.hpp>

namespace graphene { namespace chain {
fork_database::fork_database()
{
}
void fork_database::reset()
{
   _head.reset();
   _index.clear();
}

void fork_database::pop_block()
{
   FC_ASSERT( _head, "no block to pop" );
   auto prev = _head->prev.lock();
   FC_ASSERT( prev, "popping block would leave head block null" );
    _head = prev;
}

void     fork_database::start_block(signed_block b)
{
   auto item = std::make_shared<fork_item>(std::move(b));
   _index.insert(item);
   _head = item;
}

/**
 * Pushes the block into the fork database and caches it if it doesn't link
 *
 */
shared_ptr<fork_item>  fork_database::push_block(const signed_block& b)
{
   auto item = std::make_shared<fork_item>(b);
   try {
      _push_block(item);
   }
   catch ( const unlinkable_block_exception& e )
   {
      wlog( "Pushing block to fork database that failed to link: ${id}, ${num}", ("id",b.id())("num",b.block_num()) );
      wlog( "Head: ${num}, ${id}", ("num",_head->data.block_num())("id",_head->data.id()) );
      throw;
      _unlinked_index.insert( item );
   }
   return _head;
}

void  fork_database::_push_block(const item_ptr& item)
{
   if( _head ) // make sure the block is within the range that we are caching
   {
      FC_ASSERT( item->num > std::max<int64_t>( 0, int64_t(_head->num) - (_max_size) ),
                 "attempting to push a block that is too old",
                 ("item->num",item->num)("head",_head->num)("max_size",_max_size));
   }

   if( _head && item->previous_id() != block_id_type() )
   {
      auto& index = _index.get<block_id>();
      auto itr = index.find(item->previous_id());
      GRAPHENE_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain");
      item->prev = *itr;
   }

   _index.insert(item);
   if( !_head ) _head = item;
   else if( item->num > _head->num )
   {
      _head = item;
      uint32_t min_num = _head->num - std::min( _max_size, _head->num );
//      ilog( "min block in fork DB ${n}, max_size: ${m}", ("n",min_num)("m",_max_size) );
      auto& num_idx = _index.get<block_num>();
      while( num_idx.size() && (*num_idx.begin())->num < min_num )
         num_idx.erase( num_idx.begin() );

      _unlinked_index.get<block_num>().erase(_head->num - _max_size);
   }
   //_push_next( item );
}

/**
 *  Iterate through the unlinked cache and insert anything that
 *  links to the newly inserted item.  This will start a recursive
 *  set of calls performing a depth-first insertion of pending blocks as
 *  _push_next(..) calls _push_block(...) which will in turn call _push_next
 */
void fork_database::_push_next( const item_ptr& new_item )
{
    auto& prev_idx = _unlinked_index.get<by_previous>();

    auto itr = prev_idx.find( new_item->id );
    while( itr != prev_idx.end() )
    {
       auto tmp = *itr;
       prev_idx.erase( itr );
       _push_block( tmp );

       itr = prev_idx.find( new_item->id );
    }
}

void fork_database::set_max_size( uint32_t s )
{
   _max_size = s;
   if( !_head ) return;

   { /// index
      auto& by_num_idx = _index.get<block_num>();
      auto itr = by_num_idx.begin();
      while( itr != by_num_idx.end() )
      {
         if( (*itr)->num < std::max(int64_t(0),int64_t(_head->num) - _max_size) )
            by_num_idx.erase(itr);
         else
            break;
         itr = by_num_idx.begin();
      }
   }
   { /// unlinked_index
      auto& by_num_idx = _unlinked_index.get<block_num>();
      auto itr = by_num_idx.begin();
      while( itr != by_num_idx.end() )
      {
         if( (*itr)->num < std::max(int64_t(0),int64_t(_head->num) - _max_size) )
            by_num_idx.erase(itr);
         else
            break;
         itr = by_num_idx.begin();
      }
   }
}

bool fork_database::is_known_block(const block_id_type& id)const
{
   auto& index = _index.get<block_id>();
   auto itr = index.find(id);
   if( itr != index.end() )
      return true;
   auto& unlinked_index = _unlinked_index.get<block_id>();
   auto unlinked_itr = unlinked_index.find(id);
   return unlinked_itr != unlinked_index.end();
}

item_ptr fork_database::fetch_block(const block_id_type& id)const
{
   auto& index = _index.get<block_id>();
   auto itr = index.find(id);
   if( itr != index.end() )
      return *itr;
   auto& unlinked_index = _unlinked_index.get<block_id>();
   auto unlinked_itr = unlinked_index.find(id);
   if( unlinked_itr != unlinked_index.end() )
      return *unlinked_itr;
   return item_ptr();
}

vector<item_ptr> fork_database::fetch_block_by_number(uint32_t num)const
{
   vector<item_ptr> result;
   auto itr = _index.get<block_num>().find(num);
   while( itr != _index.get<block_num>().end() )
   {
      if( (*itr)->num == num )
         result.push_back( *itr );
      else
         break;
      ++itr;
   }
   return result;
}

pair<fork_database::branch_type,fork_database::branch_type>
  fork_database::fetch_branch_from(block_id_type first, block_id_type second)const
{ try {
   // This function gets a branch (i.e. vector<fork_item>) leading
   // back to the most recent common ancestor.
   pair<branch_type,branch_type> result;
   auto first_branch_itr = _index.get<block_id>().find(first);
   FC_ASSERT(first_branch_itr != _index.get<block_id>().end());
   auto first_branch = *first_branch_itr;

   auto second_branch_itr = _index.get<block_id>().find(second);
   FC_ASSERT(second_branch_itr != _index.get<block_id>().end());
   auto second_branch = *second_branch_itr;

   while( first_branch->data.block_num() > second_branch->data.block_num() )
   {
      result.first.push_back(first_branch);
      first_branch = first_branch->prev.lock();
      FC_ASSERT(first_branch);
   }
   while( second_branch->data.block_num() > first_branch->data.block_num() )
   {
      result.second.push_back( second_branch );
      second_branch = second_branch->prev.lock();
      FC_ASSERT(second_branch);
   }
   while( first_branch->data.previous != second_branch->data.previous )
   {
      result.first.push_back(first_branch);
      result.second.push_back(second_branch);
      first_branch = first_branch->prev.lock();
      FC_ASSERT(first_branch);
      second_branch = second_branch->prev.lock();
      FC_ASSERT(second_branch);
   }
   if( first_branch && second_branch )
   {
      result.first.push_back(first_branch);
      result.second.push_back(second_branch);
   }
   return result;
} FC_CAPTURE_AND_RETHROW( (first)(second) ) }

void fork_database::set_head(shared_ptr<fork_item> h)
{
   _head = h;
}

void fork_database::remove(block_id_type id)
{
   _index.get<block_id>().erase(id);
   // If we're removing head, try to pop it
   if( _head && _head->id == id )
   {
      try
      {
         pop_block();
      }
      catch( fc::exception& e ) // If unable to pop normally, E.G. if head's prev is null, reset it
      {
         _head.reset();
      }
   }
}

} } // graphene::chain
<|endoftext|>


<commit_before>#include <StdAfx.h>
#include <UI/FakeSplitter.h>
#include <UI/UIFunctions.h>
#include <UI/DoubleBuffer.h>

namespace controls
{
	static std::wstring CLASS = L"CFakeSplitter";

	enum FakesSplitHitTestValue
	{
		noHit = 0,
		SplitterHit = 1
	};

	CFakeSplitter::~CFakeSplitter()
	{
		TRACE_DESTRUCTOR(CLASS);
		delete m_ViewPaneOne;
		delete m_ViewPaneTwo;
		(void) DestroyCursor(m_hSplitCursorH);
		(void) DestroyCursor(m_hSplitCursorV);
		CWnd::DestroyWindow();
	}

	void CFakeSplitter::Init(HWND hWnd)
	{
		m_hwndParent = hWnd;
		WNDCLASSEX wc = {};
		const auto hInst = AfxGetInstanceHandle();
		if (!::GetClassInfoEx(hInst, _T("FakeSplitter"), &wc)) // STRING_OK
		{
			wc.cbSize = sizeof wc;
			wc.style = 0; // not passing CS_VREDRAW | CS_HREDRAW fixes flicker
			wc.lpszClassName = _T("FakeSplitter"); // STRING_OK
			wc.lpfnWndProc = ::DefWindowProc;
			wc.hbrBackground = GetSysBrush(ui::cBackground); // helps spot flashing

			RegisterClassEx(&wc);
		}

		// WS_CLIPCHILDREN is used to reduce flicker
		EC_B_S(CreateEx(
			0,
			_T("FakeSplitter"), // STRING_OK
			_T("FakeSplitter"), // STRING_OK
			WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
			0,
			0,
			0,
			0,
			m_hwndParent,
			reinterpret_cast<HMENU>(static_cast<INT_PTR>(IDC_FAKE_SPLITTER)),
			nullptr));

		// Necessary for TAB to work. Without this, all TABS get stuck on the fake splitter control
		// instead of passing to the children. Haven't tested with nested splitters.
		EC_B_S(ModifyStyleEx(0, WS_EX_CONTROLPARENT));

		// Load split cursors
		m_hSplitCursorV = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITV)));
		m_hSplitCursorH = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITH)));
	}

	BEGIN_MESSAGE_MAP(CFakeSplitter, CWnd)
	ON_WM_MOUSEMOVE()
	ON_WM_SIZE()
	ON_WM_PAINT()
	END_MESSAGE_MAP()

	LRESULT CFakeSplitter::WindowProc(const UINT message, const WPARAM wParam, const LPARAM lParam)
	{
		LRESULT lRes = 0;
		if (ui::HandleControlUI(message, wParam, lParam, &lRes)) return lRes;

		switch (message)
		{
		case WM_HELP:
			return true;
		case WM_LBUTTONUP:
		case WM_CANCELMODE: // Called if focus changes while we're adjusting the splitter
			StopTracking();
			return NULL;
		case WM_LBUTTONDOWN:
			if (m_bTracking) return true;
			StartTracking(HitTest(LOWORD(lParam), HIWORD(lParam)));
			return NULL;
		case WM_SETCURSOR:
			if (LOWORD(lParam) == HTCLIENT && reinterpret_cast<HWND>(wParam) == this->m_hWnd && !m_bTracking)
				return true; // we will handle it in the mouse move
			break;
		case WM_COMMAND:
		{
			const auto nCode = HIWORD(wParam);
			if (EN_CHANGE == nCode || CBN_SELCHANGE == nCode || CBN_EDITCHANGE == nCode || BN_CLICKED == nCode)
			{
				::SendMessage(m_hwndParent, message, wParam, lParam);
			}

			break;
		}
		}

		return CWnd::WindowProc(message, wParam, lParam);
	}

	void CFakeSplitter::SetPaneOne(HWND paneOne)
	{
		m_PaneOne = paneOne;
		if (m_PaneOne)
		{
			m_iSplitWidth = 7;
		}
		else
		{
			m_iSplitWidth = 0;
		}
	}

	void CFakeSplitter::SetPaneTwo(HWND paneTwo) { m_PaneTwo = paneTwo; }

	void CFakeSplitter::OnSize(UINT /*nType*/, const int cx, const int cy)
	{
		CalcSplitPos();

		const auto hdwp = WC_D(HDWP, BeginDeferWindowPos(2));
		if (hdwp)
		{
			InvalidateRect(CRect(0, 0, cx, cy), false);
			if (m_PaneOne || m_ViewPaneOne)
			{
				CRect r1;
				if (SplitHorizontal == m_SplitType)
				{
					r1.SetRect(0, 0, m_iSplitPos, cy);
				}
				else
				{
					r1.SetRect(0, 0, cx, m_iSplitPos);
				}

				if (m_PaneOne)
				{
					DeferWindowPos(hdwp, m_PaneOne, nullptr, 0, 0, r1.Width(), r1.Height(), SWP_NOZORDER);
				}

				if (m_ViewPaneOne)
				{
					m_ViewPaneOne->DeferWindowPos(hdwp, 0, 0, r1.Width(), r1.Height());
				}
			}

			if (m_PaneTwo || m_ViewPaneTwo)
			{
				CRect r2;
				if (SplitHorizontal == m_SplitType)
				{
					r2.SetRect(
						m_iSplitPos + m_iSplitWidth, // new x
						0, // new y
						cx, // bottom right corner
						cy); // bottom right corner
				}
				else
				{
					r2.SetRect(
						0, // new x
						m_iSplitPos + m_iSplitWidth, // new y
						cx, // bottom right corner
						cy); // bottom right corner
				}

				if (m_PaneTwo)
				{
					DeferWindowPos(hdwp, m_PaneTwo, nullptr, r2.left, r2.top, r2.Width(), r2.Height(), SWP_NOZORDER);
				}

				if (m_ViewPaneTwo)
				{
					m_ViewPaneTwo->DeferWindowPos(hdwp, r2.left, r2.top, r2.Width(), r2.Height());
				}
			}

			EC_B_S(EndDeferWindowPos(hdwp));
		}
	}

	void CFakeSplitter::CalcSplitPos()
	{
		if (!m_PaneOne && !m_ViewPaneOne)
		{
			m_iSplitPos = 0;
			return;
		}

		int iCurSpan;
		CRect rect;
		GetClientRect(rect);
		if (SplitHorizontal == m_SplitType)
		{
			iCurSpan = rect.Width();
		}
		else
		{
			iCurSpan = rect.Height();
		}

		m_iSplitPos = static_cast<int>(static_cast<FLOAT>(iCurSpan) * m_flSplitPercent);
		if (m_iSplitPos + m_iSplitWidth + 1 >= iCurSpan)
		{
			m_iSplitPos = m_iSplitPos - m_iSplitWidth - 1;
		}
	}

	void CFakeSplitter::SetPercent(const FLOAT iNewPercent)
	{
		if (iNewPercent < 0.0 || iNewPercent > 1.0) return;
		m_flSplitPercent = iNewPercent;

		CalcSplitPos();

		CRect rect;
		GetClientRect(rect);

		// Recalculate our layout
		OnSize(0, rect.Width(), rect.Height());
	}

	void CFakeSplitter::SetSplitType(const SplitType stSplitType) { m_SplitType = stSplitType; }

	_Check_return_ int CFakeSplitter::HitTest(const LONG x, const LONG y) const
	{
		if (!m_PaneOne && !m_ViewPaneOne) return noHit;

		LONG lTestPos;

		if (SplitHorizontal == m_SplitType)
		{
			lTestPos = x;
		}
		else
		{
			lTestPos = y;
		}

		if (lTestPos >= m_iSplitPos && lTestPos <= m_iSplitPos + m_iSplitWidth) return SplitterHit;

		return noHit;
	}

	void CFakeSplitter::OnMouseMove(UINT /*nFlags*/, const CPoint point)
	{
		if (!m_PaneOne && !m_ViewPaneOne) return;

		// If we don't have GetCapture, then we don't want to track right now.
		if (GetCapture() != this) StopTracking();

		if (SplitterHit == HitTest(point.x, point.y))
		{
			// This looks backwards, but it is not. A horizontal split needs the vertical cursor
			SetCursor(SplitHorizontal == m_SplitType ? m_hSplitCursorV : m_hSplitCursorH);
		}

		if (m_bTracking)
		{
			CRect Rect;
			FLOAT flNewPercent;
			GetWindowRect(Rect);

			if (SplitHorizontal == m_SplitType)
			{
				flNewPercent = point.x / static_cast<FLOAT>(Rect.Width());
			}
			else
			{
				flNewPercent = point.y / static_cast<FLOAT>(Rect.Height());
			}
			SetPercent(flNewPercent);

			// Force child windows to refresh now
			EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));
		}
	}

	void CFakeSplitter::StartTracking(const int ht)
	{
		if (ht == noHit) return;

		// steal focus and capture
		SetCapture();
		SetFocus();

		// make sure no updates are pending
		// CSplitterWnd does this...not sure why
		EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));

		// set tracking state and appropriate cursor
		m_bTracking = true;

		// Force redraw to get our tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::StopTracking()
	{
		if (!m_bTracking) return;

		ReleaseCapture();

		m_bTracking = false;

		// Force redraw to get our non-tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::OnPaint()
	{
		auto ps = PAINTSTRUCT{};
		::BeginPaint(m_hWnd, &ps);
		if (ps.hdc)
		{
			auto rcWin = RECT{};
			::GetClientRect(m_hWnd, &rcWin);
			ui::CDoubleBuffer db;
			auto hdc = ps.hdc;
			db.Begin(hdc, rcWin);

			auto rcSplitter = rcWin;
			FillRect(hdc, &rcSplitter, GetSysBrush(ui::cBackground));

			POINT pts[2]; // 0 is left top, 1 is right bottom
			if (SplitHorizontal == m_SplitType)
			{
				pts[0].x = m_iSplitPos + m_iSplitWidth / 2;
				pts[0].y = rcSplitter.top;
				pts[1].x = pts[0].x;
				pts[1].y = rcSplitter.bottom;
			}
			else
			{
				pts[0].x = rcSplitter.left;
				pts[0].y = m_iSplitPos + m_iSplitWidth / 2;
				pts[1].x = rcSplitter.right;
				pts[1].y = pts[0].y;
			}

			// Draw the splitter bar
			const auto hpenOld = SelectObject(hdc, GetPen(m_bTracking ? ui::cSolidPen : ui::cDashedPen));
			MoveToEx(hdc, pts[0].x, pts[0].y, nullptr);
			LineTo(hdc, pts[1].x, pts[1].y);
			(void) SelectObject(hdc, hpenOld);

			db.End(hdc);
		}

		::EndPaint(m_hWnd, &ps);
	}
} // namespace controls<commit_msg>esc should close the editor, not the fake splitter<commit_after>#include <StdAfx.h>
#include <UI/FakeSplitter.h>
#include <UI/UIFunctions.h>
#include <UI/DoubleBuffer.h>

namespace controls
{
	static std::wstring CLASS = L"CFakeSplitter";

	enum FakesSplitHitTestValue
	{
		noHit = 0,
		SplitterHit = 1
	};

	CFakeSplitter::~CFakeSplitter()
	{
		TRACE_DESTRUCTOR(CLASS);
		delete m_ViewPaneOne;
		delete m_ViewPaneTwo;
		(void) DestroyCursor(m_hSplitCursorH);
		(void) DestroyCursor(m_hSplitCursorV);
		CWnd::DestroyWindow();
	}

	void CFakeSplitter::Init(HWND hWnd)
	{
		m_hwndParent = hWnd;
		WNDCLASSEX wc = {};
		const auto hInst = AfxGetInstanceHandle();
		if (!::GetClassInfoEx(hInst, _T("FakeSplitter"), &wc)) // STRING_OK
		{
			wc.cbSize = sizeof wc;
			wc.style = 0; // not passing CS_VREDRAW | CS_HREDRAW fixes flicker
			wc.lpszClassName = _T("FakeSplitter"); // STRING_OK
			wc.lpfnWndProc = ::DefWindowProc;
			wc.hbrBackground = GetSysBrush(ui::cBackground); // helps spot flashing

			RegisterClassEx(&wc);
		}

		// WS_CLIPCHILDREN is used to reduce flicker
		EC_B_S(CreateEx(
			0,
			_T("FakeSplitter"), // STRING_OK
			_T("FakeSplitter"), // STRING_OK
			WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
			0,
			0,
			0,
			0,
			m_hwndParent,
			reinterpret_cast<HMENU>(static_cast<INT_PTR>(IDC_FAKE_SPLITTER)),
			nullptr));

		// Necessary for TAB to work. Without this, all TABS get stuck on the fake splitter control
		// instead of passing to the children. Haven't tested with nested splitters.
		EC_B_S(ModifyStyleEx(0, WS_EX_CONTROLPARENT));

		// Load split cursors
		m_hSplitCursorV = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITV)));
		m_hSplitCursorH = EC_D(HCURSOR, ::LoadCursor(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDC_SPLITH)));
	}

	BEGIN_MESSAGE_MAP(CFakeSplitter, CWnd)
	ON_WM_MOUSEMOVE()
	ON_WM_SIZE()
	ON_WM_PAINT()
	END_MESSAGE_MAP()

	LRESULT CFakeSplitter::WindowProc(const UINT message, const WPARAM wParam, const LPARAM lParam)
	{
		LRESULT lRes = 0;
		if (ui::HandleControlUI(message, wParam, lParam, &lRes)) return lRes;

		switch (message)
		{
		case WM_CLOSE:
			::SendMessage(m_hwndParent, message, wParam, lParam);
			return true;
		case WM_HELP:
			return true;
		case WM_LBUTTONUP:
		case WM_CANCELMODE: // Called if focus changes while we're adjusting the splitter
			StopTracking();
			return NULL;
		case WM_LBUTTONDOWN:
			if (m_bTracking) return true;
			StartTracking(HitTest(LOWORD(lParam), HIWORD(lParam)));
			return NULL;
		case WM_SETCURSOR:
			if (LOWORD(lParam) == HTCLIENT && reinterpret_cast<HWND>(wParam) == this->m_hWnd && !m_bTracking)
				return true; // we will handle it in the mouse move
			break;
		case WM_COMMAND:
		{
			const auto nCode = HIWORD(wParam);
			if (EN_CHANGE == nCode || CBN_SELCHANGE == nCode || CBN_EDITCHANGE == nCode || BN_CLICKED == nCode)
			{
				::SendMessage(m_hwndParent, message, wParam, lParam);
			}

			break;
		}
		}

		return CWnd::WindowProc(message, wParam, lParam);
	}

	void CFakeSplitter::SetPaneOne(HWND paneOne)
	{
		m_PaneOne = paneOne;
		if (m_PaneOne)
		{
			m_iSplitWidth = 7;
		}
		else
		{
			m_iSplitWidth = 0;
		}
	}

	void CFakeSplitter::SetPaneTwo(HWND paneTwo) { m_PaneTwo = paneTwo; }

	void CFakeSplitter::OnSize(UINT /*nType*/, const int cx, const int cy)
	{
		CalcSplitPos();

		const auto hdwp = WC_D(HDWP, BeginDeferWindowPos(2));
		if (hdwp)
		{
			InvalidateRect(CRect(0, 0, cx, cy), false);
			if (m_PaneOne || m_ViewPaneOne)
			{
				CRect r1;
				if (SplitHorizontal == m_SplitType)
				{
					r1.SetRect(0, 0, m_iSplitPos, cy);
				}
				else
				{
					r1.SetRect(0, 0, cx, m_iSplitPos);
				}

				if (m_PaneOne)
				{
					DeferWindowPos(hdwp, m_PaneOne, nullptr, 0, 0, r1.Width(), r1.Height(), SWP_NOZORDER);
				}

				if (m_ViewPaneOne)
				{
					m_ViewPaneOne->DeferWindowPos(hdwp, 0, 0, r1.Width(), r1.Height());
				}
			}

			if (m_PaneTwo || m_ViewPaneTwo)
			{
				CRect r2;
				if (SplitHorizontal == m_SplitType)
				{
					r2.SetRect(
						m_iSplitPos + m_iSplitWidth, // new x
						0, // new y
						cx, // bottom right corner
						cy); // bottom right corner
				}
				else
				{
					r2.SetRect(
						0, // new x
						m_iSplitPos + m_iSplitWidth, // new y
						cx, // bottom right corner
						cy); // bottom right corner
				}

				if (m_PaneTwo)
				{
					DeferWindowPos(hdwp, m_PaneTwo, nullptr, r2.left, r2.top, r2.Width(), r2.Height(), SWP_NOZORDER);
				}

				if (m_ViewPaneTwo)
				{
					m_ViewPaneTwo->DeferWindowPos(hdwp, r2.left, r2.top, r2.Width(), r2.Height());
				}
			}

			EC_B_S(EndDeferWindowPos(hdwp));
		}
	}

	void CFakeSplitter::CalcSplitPos()
	{
		if (!m_PaneOne && !m_ViewPaneOne)
		{
			m_iSplitPos = 0;
			return;
		}

		int iCurSpan;
		CRect rect;
		GetClientRect(rect);
		if (SplitHorizontal == m_SplitType)
		{
			iCurSpan = rect.Width();
		}
		else
		{
			iCurSpan = rect.Height();
		}

		m_iSplitPos = static_cast<int>(static_cast<FLOAT>(iCurSpan) * m_flSplitPercent);
		if (m_iSplitPos + m_iSplitWidth + 1 >= iCurSpan)
		{
			m_iSplitPos = m_iSplitPos - m_iSplitWidth - 1;
		}
	}

	void CFakeSplitter::SetPercent(const FLOAT iNewPercent)
	{
		if (iNewPercent < 0.0 || iNewPercent > 1.0) return;
		m_flSplitPercent = iNewPercent;

		CalcSplitPos();

		CRect rect;
		GetClientRect(rect);

		// Recalculate our layout
		OnSize(0, rect.Width(), rect.Height());
	}

	void CFakeSplitter::SetSplitType(const SplitType stSplitType) { m_SplitType = stSplitType; }

	_Check_return_ int CFakeSplitter::HitTest(const LONG x, const LONG y) const
	{
		if (!m_PaneOne && !m_ViewPaneOne) return noHit;

		LONG lTestPos;

		if (SplitHorizontal == m_SplitType)
		{
			lTestPos = x;
		}
		else
		{
			lTestPos = y;
		}

		if (lTestPos >= m_iSplitPos && lTestPos <= m_iSplitPos + m_iSplitWidth) return SplitterHit;

		return noHit;
	}

	void CFakeSplitter::OnMouseMove(UINT /*nFlags*/, const CPoint point)
	{
		if (!m_PaneOne && !m_ViewPaneOne) return;

		// If we don't have GetCapture, then we don't want to track right now.
		if (GetCapture() != this) StopTracking();

		if (SplitterHit == HitTest(point.x, point.y))
		{
			// This looks backwards, but it is not. A horizontal split needs the vertical cursor
			SetCursor(SplitHorizontal == m_SplitType ? m_hSplitCursorV : m_hSplitCursorH);
		}

		if (m_bTracking)
		{
			CRect Rect;
			FLOAT flNewPercent;
			GetWindowRect(Rect);

			if (SplitHorizontal == m_SplitType)
			{
				flNewPercent = point.x / static_cast<FLOAT>(Rect.Width());
			}
			else
			{
				flNewPercent = point.y / static_cast<FLOAT>(Rect.Height());
			}
			SetPercent(flNewPercent);

			// Force child windows to refresh now
			EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));
		}
	}

	void CFakeSplitter::StartTracking(const int ht)
	{
		if (ht == noHit) return;

		// steal focus and capture
		SetCapture();
		SetFocus();

		// make sure no updates are pending
		// CSplitterWnd does this...not sure why
		EC_B_S(RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_UPDATENOW));

		// set tracking state and appropriate cursor
		m_bTracking = true;

		// Force redraw to get our tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::StopTracking()
	{
		if (!m_bTracking) return;

		ReleaseCapture();

		m_bTracking = false;

		// Force redraw to get our non-tracking gripper
		SetPercent(m_flSplitPercent);
	}

	void CFakeSplitter::OnPaint()
	{
		auto ps = PAINTSTRUCT{};
		::BeginPaint(m_hWnd, &ps);
		if (ps.hdc)
		{
			auto rcWin = RECT{};
			::GetClientRect(m_hWnd, &rcWin);
			ui::CDoubleBuffer db;
			auto hdc = ps.hdc;
			db.Begin(hdc, rcWin);

			auto rcSplitter = rcWin;
			FillRect(hdc, &rcSplitter, GetSysBrush(ui::cBackground));

			POINT pts[2]; // 0 is left top, 1 is right bottom
			if (SplitHorizontal == m_SplitType)
			{
				pts[0].x = m_iSplitPos + m_iSplitWidth / 2;
				pts[0].y = rcSplitter.top;
				pts[1].x = pts[0].x;
				pts[1].y = rcSplitter.bottom;
			}
			else
			{
				pts[0].x = rcSplitter.left;
				pts[0].y = m_iSplitPos + m_iSplitWidth / 2;
				pts[1].x = rcSplitter.right;
				pts[1].y = pts[0].y;
			}

			// Draw the splitter bar
			const auto hpenOld = SelectObject(hdc, GetPen(m_bTracking ? ui::cSolidPen : ui::cDashedPen));
			MoveToEx(hdc, pts[0].x, pts[0].y, nullptr);
			LineTo(hdc, pts[1].x, pts[1].y);
			(void) SelectObject(hdc, hpenOld);

			db.End(hdc);
		}

		::EndPaint(m_hWnd, &ps);
	}
} // namespace controls<|endoftext|>


<commit_before>#include "kernel.h"
#include "ilwisdata.h"
#include "domain.h"
#include "range.h"
#include "datadefinition.h"
#include "columndefinition.h"
#include "connectorinterface.h"
#include "table.h"
#include "basetable.h"
#include "domainitem.h"
#include "itemdomain.h"
#include "tablemerger.h"

using namespace Ilwis;

BaseTable::BaseTable() : Table(), _rows(0), _columns(0), _dataloaded(false)
{
}

BaseTable::BaseTable(const Resource& resource) : Table(resource), _rows(0), _columns(0),_dataloaded(false) {

}

BaseTable::~BaseTable()
{
}

quint32 BaseTable::recordCount() const
{
    return _rows;
}

quint32 BaseTable::columnCount() const
{
    return _columns;
}

void BaseTable::recordCount(quint32 r)
{
    _rows = r;
}

bool BaseTable::createTable()
{
    if (!isValid()) {
        kernel()->issues()->log(TR("Not created, Table %1 already exists").arg(name()), IssueObject::itWarning);
        return false;
    }
    if ( _columnDefinitionsByName.size() ==  0) {
        kernel()->issues()->log(TR("Trying to create table %1 with zero columns").arg(name()));
        return false;
    }
    return true;
}

bool BaseTable::addColumn(const ColumnDefinition& def){
    if ( _columnDefinitionsByName.contains(def.name())) {
        kernel()->issues()->log(TR("Adding duplicate column %1").arg(name()),IssueObject::itWarning);
        return false;
    }
    ColumnDefinition coldef = def;
    coldef.columnindex(_columnDefinitionsByIndex.size());
    _columnDefinitionsByName[coldef.name()] = coldef;
    _columnDefinitionsByIndex[coldef.columnindex()] = _columnDefinitionsByName[coldef.name()];
    _columns = _columnDefinitionsByName.size();

    return true;
}

bool BaseTable::addColumn(const QString &name, const IDomain& domain)
{
    if ( _columnDefinitionsByName.contains(name)) {
        kernel()->issues()->log(TR("Adding duplicate column %1").arg(name),IssueObject::itWarning);
        return false;
    }
    _columnDefinitionsByName[name] = ColumnDefinition(name, domain,_columnDefinitionsByName.size());
    _columnDefinitionsByIndex[_columnDefinitionsByName[name].id()] = _columnDefinitionsByName[name];
    _columns = _columnDefinitionsByName.size();

    return true;
}

bool BaseTable::addColumn(const QString &name, const QString &domainname)
{
    IDomain dom;
    if(!dom.prepare(domainname))
        return false;
    return addColumn(name, dom);
}

IlwisTypes BaseTable::ilwisType() const
{
    return itTABLE;
}

ColumnDefinition BaseTable::columndefinition(const QString &nme) const
{
    auto iter = _columnDefinitionsByName.find(nme);
    if ( iter != _columnDefinitionsByName.end()) {
        if (iter.value().isChanged()) {
            int index = columnIndex(nme);
            const_cast<BaseTable *>(this)->adjustRange(index);
        }
       return iter.value();
    }
    return ColumnDefinition();
}

ColumnDefinition BaseTable::columndefinition(quint32 index) const
{
    auto iter = _columnDefinitionsByIndex.find(index);
    if ( iter != _columnDefinitionsByIndex.end()) {
        if (iter.value().isChanged()) {
            const_cast<BaseTable *>(this)->adjustRange(index);
        }
        return iter.value();
    }
    return ColumnDefinition();
}

ColumnDefinition &BaseTable::columndefinition(quint32 index)
{
    if ( _columnDefinitionsByIndex[index].isChanged()) {
        adjustRange(index);
    }
    return _columnDefinitionsByIndex[index];
}

void BaseTable::columndefinition(const ColumnDefinition &coldef)
{
    if ( coldef.id() >=  _columnDefinitionsByIndex.size())     {
        addColumn(coldef.name(), coldef.datadef().domain());
    } else {
        auto iter1 = _columnDefinitionsByIndex.find(coldef.id());
        auto iter2 = _columnDefinitionsByName.find(coldef.name());
        if ( iter1 != _columnDefinitionsByIndex.end()) {
            _columnDefinitionsByName.remove(iter1.value().name());
            _columnDefinitionsByIndex.remove(coldef.id());

        }else if ( iter2 != _columnDefinitionsByName.end()) {
            _columnDefinitionsByIndex.remove(iter2.value().id());
            _columnDefinitionsByName.remove(coldef.name());
        }
        _columnDefinitionsByName[coldef.name()] = coldef;
        _columnDefinitionsByIndex[coldef.id()] = coldef;
    }
}

bool BaseTable::prepare()
{
    if (!IlwisObject::prepare())
        return false;

    return true;
}

bool BaseTable::isValid() const
{
    return _rows != 0 && _columns != 0;
}

bool  BaseTable::initLoad() {
    if ( !this->isValid()) {
        kernel()->issues()->log(TR(ERR_NO_INITIALIZED_1).arg("table"));
        return false;
    }
    if (!_dataloaded) {
        _dataloaded = true; // to prevent other inits to pass through here
        if (!connector().isNull() && ! connector()->loadBinaryData(this)) {
            kernel()->issues()->log(TR(ERR_COULD_NOT_LOAD_2).arg("table", name()));
             _dataloaded = false;
            return false;
        }
    }
    return true;
}

void BaseTable::copyTo(IlwisObject *obj)
{
    IlwisObject::copyTo(obj);
    BaseTable *btable = static_cast<BaseTable *>(obj);
    btable->_columns = _columns;
    btable->_columnDefinitionsByIndex = _columnDefinitionsByIndex;
    btable->_columnDefinitionsByName = _columnDefinitionsByName;
    btable->_dataloaded = _dataloaded;

    for(const auto& def : _columnDefinitionsByIndex) {
        std::vector<QVariant> colvalues = column(def.name());
        btable->column(def.name(), colvalues);
    }
    btable->_rows = _rows;
}

quint32 BaseTable::columnIndex(const QString &nme) const
{
    auto iter = _columnDefinitionsByName.find(nme);
    if ( iter == _columnDefinitionsByName.end()) {
        //kernel()->issues()->log(TR(ERR_COLUMN_MISSING_2).arg(nme).arg(name()),IssueObject::itWarning);
        return iUNDEF;
    }
    return iter.value().id();
}

bool BaseTable::merge(const IlwisObject *obj, int options)
{
    if (obj == 0 || ! hasType(obj->ilwisType(), itTABLE))
        return false;
    ITable tblTarget(this);
    ITable tblSource(static_cast<Table *>(const_cast<IlwisObject *>(obj)));

    TableMerger merger;
    merger.copyColumns(tblSource, tblTarget, options);

    return true;
}

void BaseTable::adjustRange(int index) {

    ColumnDefinition& coldef = _columnDefinitionsByIndex[index];
    if( hasType(coldef.datadef().domain()->ilwisType(), itNUMERICDOMAIN)) {
        SPNumericRange rng = coldef.datadef().range<NumericRange>();
        std::vector<QVariant> values = column(coldef.id());
        if ( values.size() > 0 && !rng.isNull()) {
            double vmin=1e208, vmax=-1e208;
            for(const QVariant& var : values ){
                double v = var.toDouble();
                if ( !isNumericalUndef(v))
                    vmin = std::min(vmin, v) ;
                v = var.toDouble();
                if (!isNumericalUndef(v))                         {
                    vmax = std::max(vmax, v)    ;
                }

            }
            if ( vmin != 1e208 && vmax != -1e208) { //something has changed
                rng->min(vmin);
                rng->max(vmax);
                _columnDefinitionsByName[coldef.name()] = coldef;
            }
        }
    } else if ( hasType(coldef.datadef().domain()->ilwisType(), itITEMDOMAIN)) {
        SPItemRange rng = coldef.datadef().range<ItemRange>();
        std::vector<QVariant> values = column(coldef.id());
        if ( values.size() > 0 && !rng.isNull()) {
            rng->clear();
            for(auto qval : values) {
                quint32 id = qval.toUInt();
                SPDomainItem item = rng->item(id);
                if ( !item.isNull()) {
                    rng->add(item);
                }
            }
            _columnDefinitionsByName[coldef.name()] = coldef;
        }
    }
    coldef.changed(false);

}

<commit_msg>added guard<commit_after>#include "kernel.h"
#include "ilwisdata.h"
#include "domain.h"
#include "range.h"
#include "datadefinition.h"
#include "columndefinition.h"
#include "connectorinterface.h"
#include "table.h"
#include "basetable.h"
#include "domainitem.h"
#include "itemdomain.h"
#include "tablemerger.h"

using namespace Ilwis;

BaseTable::BaseTable() : Table(), _rows(0), _columns(0), _dataloaded(false)
{
}

BaseTable::BaseTable(const Resource& resource) : Table(resource), _rows(0), _columns(0),_dataloaded(false) {

}

BaseTable::~BaseTable()
{
}

quint32 BaseTable::recordCount() const
{
    return _rows;
}

quint32 BaseTable::columnCount() const
{
    return _columns;
}

void BaseTable::recordCount(quint32 r)
{
    _rows = r;
}

bool BaseTable::createTable()
{
    if (!isValid()) {
        kernel()->issues()->log(TR("Not created, Table %1 already exists").arg(name()), IssueObject::itWarning);
        return false;
    }
    if ( _columnDefinitionsByName.size() ==  0) {
        kernel()->issues()->log(TR("Trying to create table %1 with zero columns").arg(name()));
        return false;
    }
    return true;
}

bool BaseTable::addColumn(const ColumnDefinition& def){
    if ( _columnDefinitionsByName.contains(def.name())) {
        kernel()->issues()->log(TR("Adding duplicate column %1").arg(name()),IssueObject::itWarning);
        return false;
    }
    ColumnDefinition coldef = def;
    coldef.columnindex(_columnDefinitionsByIndex.size());
    _columnDefinitionsByName[coldef.name()] = coldef;
    _columnDefinitionsByIndex[coldef.columnindex()] = _columnDefinitionsByName[coldef.name()];
    _columns = _columnDefinitionsByName.size();

    return true;
}

bool BaseTable::addColumn(const QString &name, const IDomain& domain)
{
    if ( _columnDefinitionsByName.contains(name)) {
        kernel()->issues()->log(TR("Adding duplicate column %1").arg(name),IssueObject::itWarning);
        return false;
    }
    _columnDefinitionsByName[name] = ColumnDefinition(name, domain,_columnDefinitionsByName.size());
    _columnDefinitionsByIndex[_columnDefinitionsByName[name].id()] = _columnDefinitionsByName[name];
    _columns = _columnDefinitionsByName.size();

    return true;
}

bool BaseTable::addColumn(const QString &name, const QString &domainname)
{
    IDomain dom;
    if(!dom.prepare(domainname))
        return false;
    return addColumn(name, dom);
}

IlwisTypes BaseTable::ilwisType() const
{
    return itTABLE;
}

ColumnDefinition BaseTable::columndefinition(const QString &nme) const
{
    auto iter = _columnDefinitionsByName.find(nme);
    if ( iter != _columnDefinitionsByName.end()) {
        if (iter.value().isChanged()) {
            int index = columnIndex(nme);
            const_cast<BaseTable *>(this)->adjustRange(index);
        }
       return iter.value();
    }
    return ColumnDefinition();
}

ColumnDefinition BaseTable::columndefinition(quint32 index) const
{
    auto iter = _columnDefinitionsByIndex.find(index);
    if ( iter != _columnDefinitionsByIndex.end()) {
        if (iter.value().isChanged()) {
            const_cast<BaseTable *>(this)->adjustRange(index);
        }
        return iter.value();
    }
    return ColumnDefinition();
}

ColumnDefinition &BaseTable::columndefinition(quint32 index)
{
    if ( _columnDefinitionsByIndex[index].isChanged()) {
        adjustRange(index);
    }
    return _columnDefinitionsByIndex[index];
}

void BaseTable::columndefinition(const ColumnDefinition &coldef)
{
    if ( coldef.id() >=  _columnDefinitionsByIndex.size())     {
        addColumn(coldef.name(), coldef.datadef().domain());
    } else {
        auto iter1 = _columnDefinitionsByIndex.find(coldef.id());
        auto iter2 = _columnDefinitionsByName.find(coldef.name());
        if ( iter1 != _columnDefinitionsByIndex.end()) {
            _columnDefinitionsByName.remove(iter1.value().name());
            _columnDefinitionsByIndex.remove(coldef.id());

        }else if ( iter2 != _columnDefinitionsByName.end()) {
            _columnDefinitionsByIndex.remove(iter2.value().id());
            _columnDefinitionsByName.remove(coldef.name());
        }
        _columnDefinitionsByName[coldef.name()] = coldef;
        _columnDefinitionsByIndex[coldef.id()] = coldef;
    }
}

bool BaseTable::prepare()
{
    if (!IlwisObject::prepare())
        return false;

    return true;
}

bool BaseTable::isValid() const
{
    return _rows != 0 && _columns != 0;
}

bool  BaseTable::initLoad() {
    if ( !this->isValid()) {
        kernel()->issues()->log(TR(ERR_NO_INITIALIZED_1).arg("table"));
        return false;
    }
    if (!_dataloaded) {
        _dataloaded = true; // to prevent other inits to pass through here
        if (!connector().isNull() && ! connector()->loadBinaryData(this)) {
            kernel()->issues()->log(TR(ERR_COULD_NOT_LOAD_2).arg("table", name()));
             _dataloaded = false;
            return false;
        }
    }
    return true;
}

void BaseTable::copyTo(IlwisObject *obj)
{
    IlwisObject::copyTo(obj);
    BaseTable *btable = static_cast<BaseTable *>(obj);
    btable->_columns = _columns;
    btable->_columnDefinitionsByIndex = _columnDefinitionsByIndex;
    btable->_columnDefinitionsByName = _columnDefinitionsByName;
    btable->_dataloaded = _dataloaded;

    for(const auto& def : _columnDefinitionsByIndex) {
        std::vector<QVariant> colvalues = column(def.name());
        btable->column(def.name(), colvalues);
    }
    btable->_rows = _rows;
}

quint32 BaseTable::columnIndex(const QString &nme) const
{
    auto iter = _columnDefinitionsByName.find(nme);
    if ( iter == _columnDefinitionsByName.end()) {
        //kernel()->issues()->log(TR(ERR_COLUMN_MISSING_2).arg(nme).arg(name()),IssueObject::itWarning);
        return iUNDEF;
    }
    return iter.value().id();
}

bool BaseTable::merge(const IlwisObject *obj, int options)
{
    if (obj == 0 || ! hasType(obj->ilwisType(), itTABLE))
        return false;
    ITable tblTarget(this);
    ITable tblSource(static_cast<Table *>(const_cast<IlwisObject *>(obj)));

    TableMerger merger;
    merger.copyColumns(tblSource, tblTarget, options);

    return true;
}

void BaseTable::adjustRange(int index) {

    ColumnDefinition& coldef = _columnDefinitionsByIndex[index];
    if (!coldef.isValid())
        return;

    if( hasType(coldef.datadef().domain()->ilwisType(), itNUMERICDOMAIN)) {
        SPNumericRange rng = coldef.datadef().range<NumericRange>();
        std::vector<QVariant> values = column(coldef.id());
        if ( values.size() > 0 && !rng.isNull()) {
            double vmin=1e208, vmax=-1e208;
            for(const QVariant& var : values ){
                double v = var.toDouble();
                if ( !isNumericalUndef(v))
                    vmin = std::min(vmin, v) ;
                v = var.toDouble();
                if (!isNumericalUndef(v))                         {
                    vmax = std::max(vmax, v)    ;
                }

            }
            if ( vmin != 1e208 && vmax != -1e208) { //something has changed
                rng->min(vmin);
                rng->max(vmax);
                _columnDefinitionsByName[coldef.name()] = coldef;
            }
        }
    } else if ( hasType(coldef.datadef().domain()->ilwisType(), itITEMDOMAIN)) {
        SPItemRange rng = coldef.datadef().range<ItemRange>();
        std::vector<QVariant> values = column(coldef.id());
        if ( values.size() > 0 && !rng.isNull()) {
            rng->clear();
            for(auto qval : values) {
                quint32 id = qval.toUInt();
                SPDomainItem item = rng->item(id);
                if ( !item.isNull()) {
                    rng->add(item);
                }
            }
            _columnDefinitionsByName[coldef.name()] = coldef;
        }
    }
    coldef.changed(false);

}

<|endoftext|>


<commit_before>#include "clientGeoJsonSource.h"
#define GEOJSONVT_CUSTOM_TAGS
#include "mapbox/geojsonvt/geojsonvt_types.hpp"
#include "mapbox/geojsonvt/geojsonvt.hpp"
#include "mapbox/geojsonvt/geojsonvt_convert.hpp"
#include "platform.h"
#include "tile/tileTask.h"
#include "util/geom.h"
#include "data/propertyItem.h"
#include "data/tileData.h"
#include "tile/tile.h"
#include "view/view.h"

using namespace mapbox::util;

namespace Tangram {

const double extent = 4096;
const uint32_t indexMaxPoints = 100000;
double tolerance = 1E-8;

std::shared_ptr<TileTask> ClientGeoJsonSource::createTask(TileID _tileId, int _subTask) {
    return std::make_shared<TileTask>(_tileId, shared_from_this(), _subTask);
}

// Transform a geojsonvt::TilePoint into the corresponding Tangram::Point
Point transformPoint(geojsonvt::TilePoint pt) {
    return { pt.x / extent, 1. - pt.y / extent, 0 };
}

// TODO: pass scene's resourcePath to constructor to be used with `stringFromFile`
ClientGeoJsonSource::ClientGeoJsonSource(const std::string& _name, const std::string& _url,
        const std::string& _resourceRoot, int32_t _maxZoom)
    : DataSource(_name, _url, _maxZoom) {

    // TODO: handle network url for client datasource data
    // TODO: generic uri handling
    m_generateGeometry = true;
    if (!_url.empty()) {
        // Load from file
        const auto& string = stringFromFile(_url.c_str(), PathType::resource, _resourceRoot.c_str());
        addData(string);
    }
}

ClientGeoJsonSource::~ClientGeoJsonSource() {}

void ClientGeoJsonSource::addData(const std::string& _data) {

    auto features = geojsonvt::GeoJSONVT::convertFeatures(_data);

    for (auto& f : features) {
        m_features.push_back(std::move(f));
    }

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;

}

bool ClientGeoJsonSource::loadTileData(std::shared_ptr<TileTask>&& _task, TileTaskCb _cb) {

    _cb.func(std::move(_task));

    return true;
}

void ClientGeoJsonSource::clearData() {

    m_features.clear();

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store.reset();
    m_generation++;
}

void ClientGeoJsonSource::addPoint(const Properties& _tags, LngLat _point) {

    auto container = geojsonvt::Convert::project({ geojsonvt::LonLat(_point.longitude, _point.latitude) }, tolerance);

    geojsonvt::Tags tags;

    auto feature = geojsonvt::Convert::create(geojsonvt::Tags{std::make_shared<Properties>(_tags)},
                                              geojsonvt::ProjectedFeatureType::Point,
                                              container.members);

    m_features.push_back(std::move(feature));

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;
}

void ClientGeoJsonSource::addLine(const Properties& _tags, const Coordinates& _line) {
    auto& line = reinterpret_cast<const std::vector<geojsonvt::LonLat>&>(_line);

    std::vector<geojsonvt::ProjectedGeometry> geometry = { geojsonvt::Convert::project(line, tolerance) };

    auto feature = geojsonvt::Convert::create(geojsonvt::Tags{std::make_shared<Properties>(_tags)},
                                              geojsonvt::ProjectedFeatureType::LineString,
                                              geometry);

    m_features.push_back(std::move(feature));

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;
}

void ClientGeoJsonSource::addPoly(const Properties& _tags, const std::vector<Coordinates>& _poly) {

    geojsonvt::ProjectedGeometryContainer geometry;
    for (auto& _ring : _poly) {
        auto& ring = reinterpret_cast<const std::vector<geojsonvt::LonLat>&>(_ring);
        geometry.members.push_back(geojsonvt::Convert::project(ring, tolerance));
    }

    auto feature = geojsonvt::Convert::create(geojsonvt::Tags{std::make_shared<Properties>(_tags)},
                                              geojsonvt::ProjectedFeatureType::Polygon,
                                              geometry);

    m_features.push_back(std::move(feature));

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;
}

std::shared_ptr<TileData> ClientGeoJsonSource::parse(const TileTask& _task,
                                                     const MapProjection& _projection) const {

    auto data = std::make_shared<TileData>();

    geojsonvt::Tile tile;
    {
        std::lock_guard<std::mutex> lock(m_mutexStore);
        if (!m_store) { return nullptr; }
        tile = m_store->getTile(_task.tileId().z, _task.tileId().x, _task.tileId().y);
    }

    Layer layer(""); // empty name will skip filtering by 'collection'

    for (auto& it : tile.features) {

        Feature feat(m_id);

        const auto& geom = it.tileGeometry;
        const auto type = it.type;

        switch (type) {
            case geojsonvt::TileFeatureType::Point: {
                feat.geometryType = GeometryType::points;
                for (const auto& pt : geom) {
                    const auto& point = pt.get<geojsonvt::TilePoint>();
                    feat.points.push_back(transformPoint(point));
                }
                break;
            }
            case geojsonvt::TileFeatureType::LineString: {
                feat.geometryType = GeometryType::lines;
                for (const auto& r : geom) {
                    Line line;
                    for (const auto& pt : r.get<geojsonvt::TileRing>().points) {
                        line.push_back(transformPoint(pt));
                    }
                    feat.lines.emplace_back(std::move(line));
                }
                break;
            }
            case geojsonvt::TileFeatureType::Polygon: {
                feat.geometryType = GeometryType::polygons;
                for (const auto& r : geom) {
                    Line line;
                    for (const auto& pt : r.get<geojsonvt::TileRing>().points) {
                        line.push_back(transformPoint(pt));
                    }
                    // Polygons are in a flat list of rings, with ccw rings indicating
                    // the beginning of a new polygon
                    if (signedArea(line.begin(), line.end()) >= 0 || feat.polygons.empty()) {
                        feat.polygons.emplace_back();
                    }
                    feat.polygons.back().push_back(std::move(line));
                }
                break;
            }
            default: break;
        }

        feat.props = *it.tags.map;
        layer.features.emplace_back(std::move(feat));

    }

    data->layers.emplace_back(std::move(layer));

    return data;

}

}
<commit_msg>Network requests for clientGeoJsonDataSource<commit_after>#include "clientGeoJsonSource.h"
#define GEOJSONVT_CUSTOM_TAGS
#include "mapbox/geojsonvt/geojsonvt_types.hpp"
#include "mapbox/geojsonvt/geojsonvt.hpp"
#include "mapbox/geojsonvt/geojsonvt_convert.hpp"
#include "platform.h"
#include "tangram.h"
#include "tile/tileTask.h"
#include "util/geom.h"
#include "data/propertyItem.h"
#include "data/tileData.h"
#include "tile/tile.h"
#include "view/view.h"

#include <regex>

using namespace mapbox::util;

namespace Tangram {

const double extent = 4096;
const uint32_t indexMaxPoints = 100000;
double tolerance = 1E-8;

std::shared_ptr<TileTask> ClientGeoJsonSource::createTask(TileID _tileId, int _subTask) {
    return std::make_shared<TileTask>(_tileId, shared_from_this(), _subTask);
}

// Transform a geojsonvt::TilePoint into the corresponding Tangram::Point
Point transformPoint(geojsonvt::TilePoint pt) {
    return { pt.x / extent, 1. - pt.y / extent, 0 };
}

// TODO: pass scene's resourcePath to constructor to be used with `stringFromFile`
ClientGeoJsonSource::ClientGeoJsonSource(const std::string& _name, const std::string& _url,
        const std::string& _resourceRoot, int32_t _maxZoom)
    : DataSource(_name, _url, _maxZoom) {

    // TODO: handle network url for client datasource data
    // TODO: generic uri handling
    m_generateGeometry = true;
    if (!_url.empty()) {
        std::regex r("^(http|https):/");
        std::smatch match;
        if (std::regex_search(_url, match, r)) {
            startUrlRequest(_url,
                    [&, this](std::vector<char>&& rawData) {
                        addData(std::string(rawData.begin(), rawData.end()));
                        // delete all no-data tiles for this datasource and redo
                        clearDataSource(*this, false, true);
                    });
        } else {
            // Load from file
            const auto& string = stringFromFile(_url.c_str(), PathType::resource, _resourceRoot.c_str());
            addData(string);
        }
    }
}

ClientGeoJsonSource::~ClientGeoJsonSource() {}

void ClientGeoJsonSource::addData(const std::string& _data) {

    auto features = geojsonvt::GeoJSONVT::convertFeatures(_data);

    for (auto& f : features) {
        m_features.push_back(std::move(f));
    }

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;

}

bool ClientGeoJsonSource::loadTileData(std::shared_ptr<TileTask>&& _task, TileTaskCb _cb) {

    _cb.func(std::move(_task));

    return true;
}

void ClientGeoJsonSource::clearData() {

    m_features.clear();

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store.reset();
    m_generation++;
}

void ClientGeoJsonSource::addPoint(const Properties& _tags, LngLat _point) {

    auto container = geojsonvt::Convert::project({ geojsonvt::LonLat(_point.longitude, _point.latitude) }, tolerance);

    geojsonvt::Tags tags;

    auto feature = geojsonvt::Convert::create(geojsonvt::Tags{std::make_shared<Properties>(_tags)},
                                              geojsonvt::ProjectedFeatureType::Point,
                                              container.members);

    m_features.push_back(std::move(feature));

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;
}

void ClientGeoJsonSource::addLine(const Properties& _tags, const Coordinates& _line) {
    auto& line = reinterpret_cast<const std::vector<geojsonvt::LonLat>&>(_line);

    std::vector<geojsonvt::ProjectedGeometry> geometry = { geojsonvt::Convert::project(line, tolerance) };

    auto feature = geojsonvt::Convert::create(geojsonvt::Tags{std::make_shared<Properties>(_tags)},
                                              geojsonvt::ProjectedFeatureType::LineString,
                                              geometry);

    m_features.push_back(std::move(feature));

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;
}

void ClientGeoJsonSource::addPoly(const Properties& _tags, const std::vector<Coordinates>& _poly) {

    geojsonvt::ProjectedGeometryContainer geometry;
    for (auto& _ring : _poly) {
        auto& ring = reinterpret_cast<const std::vector<geojsonvt::LonLat>&>(_ring);
        geometry.members.push_back(geojsonvt::Convert::project(ring, tolerance));
    }

    auto feature = geojsonvt::Convert::create(geojsonvt::Tags{std::make_shared<Properties>(_tags)},
                                              geojsonvt::ProjectedFeatureType::Polygon,
                                              geometry);

    m_features.push_back(std::move(feature));

    std::lock_guard<std::mutex> lock(m_mutexStore);
    m_store = std::make_unique<GeoJSONVT>(m_features, m_maxZoom, m_maxZoom, indexMaxPoints, tolerance);
    m_generation++;
}

std::shared_ptr<TileData> ClientGeoJsonSource::parse(const TileTask& _task,
                                                     const MapProjection& _projection) const {

    auto data = std::make_shared<TileData>();

    geojsonvt::Tile tile;
    {
        std::lock_guard<std::mutex> lock(m_mutexStore);
        if (!m_store) { return nullptr; }
        tile = m_store->getTile(_task.tileId().z, _task.tileId().x, _task.tileId().y);
    }

    Layer layer(""); // empty name will skip filtering by 'collection'

    for (auto& it : tile.features) {

        Feature feat(m_id);

        const auto& geom = it.tileGeometry;
        const auto type = it.type;

        switch (type) {
            case geojsonvt::TileFeatureType::Point: {
                feat.geometryType = GeometryType::points;
                for (const auto& pt : geom) {
                    const auto& point = pt.get<geojsonvt::TilePoint>();
                    feat.points.push_back(transformPoint(point));
                }
                break;
            }
            case geojsonvt::TileFeatureType::LineString: {
                feat.geometryType = GeometryType::lines;
                for (const auto& r : geom) {
                    Line line;
                    for (const auto& pt : r.get<geojsonvt::TileRing>().points) {
                        line.push_back(transformPoint(pt));
                    }
                    feat.lines.emplace_back(std::move(line));
                }
                break;
            }
            case geojsonvt::TileFeatureType::Polygon: {
                feat.geometryType = GeometryType::polygons;
                for (const auto& r : geom) {
                    Line line;
                    for (const auto& pt : r.get<geojsonvt::TileRing>().points) {
                        line.push_back(transformPoint(pt));
                    }
                    // Polygons are in a flat list of rings, with ccw rings indicating
                    // the beginning of a new polygon
                    if (signedArea(line.begin(), line.end()) >= 0 || feat.polygons.empty()) {
                        feat.polygons.emplace_back();
                    }
                    feat.polygons.back().push_back(std::move(line));
                }
                break;
            }
            default: break;
        }

        feat.props = *it.tags.map;
        layer.features.emplace_back(std::move(feat));

    }

    data->layers.emplace_back(std::move(layer));

    return data;

}

}
<|endoftext|>