<commit_before>#include <QDebug>
#include "create_app_zip_task.h"
#include "vt-log.h"
#include "zlib.h"
#include "zip.h"

#ifdef _WIN32
#elif defined(unix) || defined(__APPLE__)
#include <sys/stat.h>
#endif

#define MAXFILENAME (256)

CreateAppZipTask::CreateAppZipTask(QVtFile *f)
{
  vtfile = f;
  total_size  = 0;
  processed_size = 0;
}

void CreateAppZipTask::OpenZip(QString filename)
{
    #ifdef USEWIN32IOAPI
    zlib_filefunc64_def ffunc;
    fill_win32_filefunc64A(&ffunc);
    zf = zipOpen2_64(filename.toStdString().c_str(),0,NULL,&ffunc);
    #else
    zf = zipOpen64(filename.toStdString().c_str(), 0);
    #endif

}

void CreateAppZipTask::SumDir(QString path, unsigned int depth)
{
  QDir dir(path);
  QFileInfoList file_info_list;
  int length;

  if (depth > 16)
    return;  // avoid too much recursion

  file_info_list = dir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
  length = file_info_list.length();
  for (int i = 0; i < length; i++) {
    QFileInfo file_info = file_info_list[i];
    QString file_path = file_info.canonicalFilePath();

    // If the file does not exist, canonicalFilePath() returns an empty string.
    if (file_path.isEmpty())
      continue;

    qDebug() <<  path << " file "<< i << "/" << length << " = " << file_path;
    SumSizePath(file_info, depth);

  }
}

#ifdef _WIN32
uLong filetime(f, tmzip, dt)
    char *f;                /* name of file to get info on */
    tm_zip *tmzip;             /* return value: access, modific. and creation times */
    uLong *dt;             /* dostime */
{
  int ret = 0;
  {
      FILETIME ftLocal;
      HANDLE hFind;
      WIN32_FIND_DATAA ff32;

      hFind = FindFirstFileA(f,&ff32);
      if (hFind != INVALID_HANDLE_VALUE)
      {
        FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
        FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
        FindClose(hFind);
        ret = 1;
      }
  }
  return ret;
}
#elif defined(unix) || defined(__APPLE__)
uLong filetime(char *f, tm_zip *tmzip, uLong *dt)
            /* name of file to get info on */
       /* return value: access, modific. and creation times */
      /* dostime */
{
  int ret=0;
  struct stat s;        /* results of stat() */
  struct tm* filedate;
  time_t tm_t=0;
  *dt = 0;

  if (strcmp(f,"-")!=0)
  {
    char name[MAXFILENAME+1];
    int len = strlen(f);
    if (len > MAXFILENAME)
      len = MAXFILENAME;

    strncpy(name, f,MAXFILENAME);
    /* strncpy doesnt append the trailing NULL, of the string is too long. */
    name[ MAXFILENAME ] = '\0';

    if (name[len - 1] == '/')
      name[len - 1] = '\0';
    /* not all systems allow stat'ing a file with / appended */
    if (stat(name,&s)==0)
    {
      tm_t = s.st_mtime;
      ret = 1;
    }
  }
  filedate = localtime(&tm_t);

  tmzip->tm_sec  = filedate->tm_sec;
  tmzip->tm_min  = filedate->tm_min;
  tmzip->tm_hour = filedate->tm_hour;
  tmzip->tm_mday = filedate->tm_mday;
  tmzip->tm_mon  = filedate->tm_mon ;
  tmzip->tm_year = filedate->tm_year;

  return ret;
}
#else
uLong filetime(char *f, tm_zip *tmzip, uLong dt)
                 /* name of file to get info on */
            /* return value: access, modific. and creation times */
      /* dostime */
{
    return 0;
}
#endif

#define BUF_SIZE 65536
void CreateAppZipTask::AddZipPath(QFileInfo file_info, unsigned int depth)
{
  QString file_path = file_info.canonicalFilePath();
  unsigned char buf[BUF_SIZE];

  // If the file does not exist, canonicalFilePath() returns an empty string.
  if (file_path.isEmpty())
    return;

  if (file_info.isDir()) {
    AddZipDir(file_path, depth+1);
    return;
  }
  // Add file to zip
  FILE * fin;
  int size_read;
  char* filenameinzip = strdup(file_path.toStdString().c_str());
  const char *savefilenameinzip;
  zip_fileinfo zi;
  unsigned long crcFile=0;
  int zip64 = 0;
  int err = 0;

  zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
  zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
  zi.dosDate = 0;
  zi.internal_fa = 0;
  zi.external_fa = 0;

  filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);

  if ( (savefilenameinzip = strstr(filenameinzip, ".app/")) ) {
    // find the Directory of the .app in the path
    while (savefilenameinzip > filenameinzip && *savefilenameinzip != '/')
      savefilenameinzip--;

  } else {
    savefilenameinzip = filenameinzip;
  }

  /* The path name saved, should not include a leading slash. */
  /*if it did, windows/xp and dynazip couldn't read the zip file. */

//  printf("filenameinzip=%s\n", filenameinzip);
  while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
  {
     savefilenameinzip++;
  }

 // qDebug() << "Add file1 " << file_path;
 // emit LogMsg(VT_LOG_DEBUG, 0 , "Add file " + QString(savefilenameinzip));
 // printf("savefilenameinzip=%s\n", savefilenameinzip);

   /**/
  err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
                   NULL,0,NULL,0,NULL /* comment*/,
                    Z_DEFLATED,
                   9, // compress level
                   0,
                   /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
                   -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
                   NULL,crcFile, zip64);

  if (err != ZIP_OK)
      emit LogMsg(VT_LOG_ERR, 0 , "error opening " + QString(filenameinzip) + " in zipfile");
  else
  {
      fin = fopen(filenameinzip,"r");
      if (fin==NULL)
      {
          err=ZIP_ERRNO;
          printf("error in opening %s for reading\n",filenameinzip);
      }
  }

  if (err == ZIP_OK) {
    do
    {
      err = ZIP_OK;
      size_read = (int)fread(buf,1,BUF_SIZE,fin);
      if (size_read < BUF_SIZE)
          if (feof(fin)==0)
      {
          printf("error in reading %s\n",filenameinzip);
          err = ZIP_ERRNO;
      }

      if (size_read>0)
      {

          err = zipWriteInFileInZip (zf,buf,size_read);
          if (err<0)
          {
              printf("error in writing %s in the zipfile\n",
                               filenameinzip);
          }
          processed_size += size_read;

      }
    } while ((err == ZIP_OK) && (size_read>0));
  }

  if (fin)
      fclose(fin);

  if (err<0)
      err=ZIP_ERRNO;
  else
  {
      err = zipCloseFileInZip(zf);
      if (err!=ZIP_OK)
          printf("error in closing %s in the zipfile\n",
                      filenameinzip);
  }
  free(filenameinzip);
}

void CreateAppZipTask::AddZipDir(QString path, unsigned int depth)
{
  QDir dir(path);
  QFileInfoList file_info_list;
  int length;

  if (depth > 16)
    return;  // avoid too much recursion

  file_info_list = dir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
  length = file_info_list.length();
  for (int i = 0; i < length; i++) {
    QFileInfo file_info = file_info_list[i];
    QString file_path = file_info.canonicalFilePath();

    // If the file does not exist, canonicalFilePath() returns an empty string.
    if (file_path.isEmpty())
      continue;

    qDebug() <<  path << " file "<< i << "/" << length << " = " << file_path;
    AddZipPath(file_info, depth);
    vtfile->SetProgress( ((float) i / (float) length) * 100.0);

  }
}

void CreateAppZipTask::SumSizePath(QFileInfo file_info, unsigned int depth)
{
    QString file_path = file_info.canonicalFilePath();

    // If the file does not exist, canonicalFilePath() returns an empty string.
    if (file_path.isEmpty())
      return;

    if (file_info.isDir()) {
      SumDir(file_path, depth+1);
    } else
      total_size += file_info.size();
}

void CreateAppZipTask::run(void)
{
  SumSizePath(vtfile->GetBundlePath(), 0);
  OpenZip(vtfile->fileName());
  AddZipPath(vtfile->GetBundlePath(), 0);

  zipClose(zf,NULL);
  vtfile->SetState(kNew);
}
<commit_msg>go depth first in .app directory parsing<commit_after>#include <QDebug>
#include "create_app_zip_task.h"
#include "vt-log.h"
#include "zlib.h"
#include "zip.h"

#ifdef _WIN32
#elif defined(unix) || defined(__APPLE__)
#include <sys/stat.h>
#endif

#define MAXFILENAME (512)

CreateAppZipTask::CreateAppZipTask(QVtFile *f)
{
  vtfile = f;
  total_size  = 0;
  processed_size = 0;
}

void CreateAppZipTask::OpenZip(QString filename)
{
    #ifdef USEWIN32IOAPI
    zlib_filefunc64_def ffunc;
    fill_win32_filefunc64A(&ffunc);
    zf = zipOpen2_64(filename.toStdString().c_str(),0,NULL,&ffunc);
    #else
    zf = zipOpen64(filename.toStdString().c_str(), 0);
    #endif

}

void CreateAppZipTask::SumDir(QString path, unsigned int depth)
{
  QDir dir(path);
  QFileInfoList file_info_list;
  int length;

  if (depth > 16)
    return;  // avoid too much recursion

  file_info_list = dir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
  length = file_info_list.length();
  for (int i = 0; i < length; i++) {
    QFileInfo file_info = file_info_list[i];
    QString file_path = file_info.canonicalFilePath();

    // If the file does not exist, canonicalFilePath() returns an empty string.
    if (file_path.isEmpty())
      continue;

    qDebug() <<  path << " file "<< i << "/" << length << " = " << file_path;
    SumSizePath(file_info, depth);

  }
}

#ifdef _WIN32
uLong filetime(f, tmzip, dt)
    char *f;                /* name of file to get info on */
    tm_zip *tmzip;             /* return value: access, modific. and creation times */
    uLong *dt;             /* dostime */
{
  int ret = 0;
  {
      FILETIME ftLocal;
      HANDLE hFind;
      WIN32_FIND_DATAA ff32;

      hFind = FindFirstFileA(f,&ff32);
      if (hFind != INVALID_HANDLE_VALUE)
      {
        FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
        FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
        FindClose(hFind);
        ret = 1;
      }
  }
  return ret;
}
#elif defined(unix) || defined(__APPLE__)
uLong filetime(char *f, tm_zip *tmzip, uLong *dt)
            /* name of file to get info on */
       /* return value: access, modific. and creation times */
      /* dostime */
{
  int ret=0;
  struct stat s;        /* results of stat() */
  struct tm* filedate;
  time_t tm_t=0;
  *dt = 0;

  if (strcmp(f,"-")!=0)
  {
    char name[MAXFILENAME+1];
    int len = strlen(f);
    if (len > MAXFILENAME)
      len = MAXFILENAME;

    strncpy(name, f,MAXFILENAME);
    /* strncpy doesnt append the trailing NULL, of the string is too long. */
    name[ MAXFILENAME ] = '\0';

    if (name[len - 1] == '/')
      name[len - 1] = '\0';
    /* not all systems allow stat'ing a file with / appended */
    if (stat(name,&s)==0)
    {
      tm_t = s.st_mtime;
      ret = 1;
    }
  }
  filedate = localtime(&tm_t);

  tmzip->tm_sec  = filedate->tm_sec;
  tmzip->tm_min  = filedate->tm_min;
  tmzip->tm_hour = filedate->tm_hour;
  tmzip->tm_mday = filedate->tm_mday;
  tmzip->tm_mon  = filedate->tm_mon ;
  tmzip->tm_year = filedate->tm_year;

  return ret;
}
#else
uLong filetime(char *f, tm_zip *tmzip, uLong dt)
                 /* name of file to get info on */
            /* return value: access, modific. and creation times */
      /* dostime */
{
    return 0;
}
#endif

#define BUF_SIZE 65536
void CreateAppZipTask::AddZipPath(QFileInfo file_info, unsigned int depth)
{
	// Add file to zip
  FILE * fin = NULL;
  int size_read = 0;
  QString file_path = "";
  unsigned char buf[BUF_SIZE];
  const char *savefilenameinzip;
  zip_fileinfo zi;
  unsigned long crcFile=0;
  int zip64 = 0;
  int err = 0;
  qDebug() << "file_info =" << file_info.path();

  file_path = file_info.canonicalFilePath();
  // If the file does not exist, canonicalFilePath() returns an empty string.
  if (file_path.isEmpty())
    return;

  if (file_info.isDir()) {
    AddZipDir(file_path, depth+1);
    return;
  }

  char* filenameinzip = strdup(file_path.toStdString().c_str());

  zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
  zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
  zi.dosDate = 0;
  zi.internal_fa = 0;
  zi.external_fa = 0;

  filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);

  if ( (savefilenameinzip = strstr(filenameinzip, ".app/")) ) {
    // find the Directory of the .app in the path
    while (savefilenameinzip > filenameinzip && *savefilenameinzip != '/')
      savefilenameinzip--;

  } else {
    savefilenameinzip = filenameinzip;
  }

  /* The path name saved, should not include a leading slash. */
  /*if it did, windows/xp and dynazip couldn't read the zip file. */

//  printf("filenameinzip=%s\n", filenameinzip);
  while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
  {
     savefilenameinzip++;
  }

 // qDebug() << "Add file1 " << file_path;
 // emit LogMsg(VT_LOG_DEBUG, 0 , "Add file " + QString(savefilenameinzip));
 // printf("savefilenameinzip=%s\n", savefilenameinzip);

   /**/
  err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
                   NULL,0,NULL,0,NULL /* comment*/,
                    Z_DEFLATED,
                   9, // compress level
                   0,
                   /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
                   -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
                   NULL,crcFile, zip64);

  if (err != ZIP_OK)
      emit LogMsg(VT_LOG_ERR, 0 , "error opening " + QString(filenameinzip) + " in zipfile");
  else
  {
      fin = fopen(filenameinzip,"r");
      if (fin==NULL)
      {
          err=ZIP_ERRNO;
          printf("error in opening %s for reading\n",filenameinzip);
      }
  }

  if (err == ZIP_OK) {
    do
    {
      err = ZIP_OK;
      size_read = (int)fread(buf,1,BUF_SIZE,fin);
      if (size_read < BUF_SIZE)
          if (feof(fin)==0)
      {
          printf("error in reading %s\n",filenameinzip);
          err = ZIP_ERRNO;
      }

      if (size_read>0)
      {

          err = zipWriteInFileInZip (zf,buf,size_read);
          if (err<0)
          {
              printf("error in writing %s in the zipfile\n",
                               filenameinzip);
          }
          processed_size += size_read;

      }
    } while ((err == ZIP_OK) && (size_read>0));
  }

  if (fin)
      fclose(fin);

  if (err<0)
      err=ZIP_ERRNO;
  else
  {
      err = zipCloseFileInZip(zf);
      if (err!=ZIP_OK)
          printf("error in closing %s in the zipfile\n",
                      filenameinzip);
  }
  free(filenameinzip);
}

void CreateAppZipTask::AddZipDir(QString path, unsigned int depth)
{
  QDir dir(path);
  QFileInfoList file_info_list;
  int length;

  if (depth >10)
    return;  // avoid too much recursion

  file_info_list = dir.entryInfoList(QDir::AllDirs
  | QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Readable);
  length = file_info_list.length();

  // 1st go through and get all dirs
  for (int i = 0; i < length; i++) {
    QFileInfo file_info = file_info_list[i];
    QString file_path = file_info.canonicalFilePath();
    if (file_path.isEmpty())
      continue;

    if (file_info.isDir()) {
      AddZipDir(file_path, depth+1);
    }
  }

  for (int i = 0; i < length; i++) {
    QFileInfo file_info = file_info_list[i];
    QString file_path = file_info.canonicalFilePath();

    if (file_info.isDir()) {
      continue;
    }

    // If the file does not exist, canonicalFilePath() returns an empty string.
    if (file_path.isEmpty())
      continue;

    qDebug() <<  path << " file "<< i << "/" << length << " = " << file_path
    << " depth= " << depth  << " total_size= " << total_size;
    AddZipPath(file_info, depth);
    vtfile->SetProgress( ((float) i / (float) length) * 100.0);

  }
}

void CreateAppZipTask::SumSizePath(QFileInfo file_info, unsigned int depth)
{
    QString file_path = file_info.canonicalFilePath();

    // If the file does not exist, canonicalFilePath() returns an empty string.
    if (file_path.isEmpty())
      return;

    if (file_info.isDir()) {
      SumDir(file_path, depth+1);
    } else
      total_size += file_info.size();
}

void CreateAppZipTask::run(void)
{
  SumSizePath(vtfile->GetBundlePath(), 0);
  OpenZip(vtfile->fileName());
  AddZipPath(vtfile->GetBundlePath(), 0);

  zipClose(zf,NULL);
  vtfile->SetState(kNew);
}
<|endoftext|>


<commit_before>#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"
#include "message_results.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *>, ps_compare> proc_loc_dict;
static list<server_function_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/

void registration_request_handler(RegisterRequestMessage * message, int sock){
	const char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  procedure_signature key(name, argTypes);

  int status = 0;

  //if 'key' dosnt exist in map, add it to the map and round robin
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //The purpose of this function is so we can have copy of the argTypes that not the original
    int *memArgTypes = copyArgTypes(argTypes);

    key = procedure_signature(name, memArgTypes);
    proc_loc_dict[key] = list<server_info *>();

    //This is bad we shouldn't need a newKey and we should be able to use the key above
    //due to &* reasones I made a variable newKey for the 'info' object
    procedure_signature * newKey = new procedure_signature(name, memArgTypes);
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    server_function_info * info = new server_function_info(entry, newKey);
    roundRobinList.push_back(info);

  } else {
    bool sameLoc = false;
    list<server_info *> hostList = proc_loc_dict[key];
    //list<server_info *> *hostList = proc_loc_dict.find(key);

    for (list<server_info *>::iterator it = hostList->begin(); it != hostList->end(); it++) {
      if((*it)->socket == sock){ //if they have the same socket, then must be same server_address/port
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something, maybe we should keep
        sameLoc = true;
      }
    }

  	if(!sameLoc){ //same procedure different socket
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList->push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

    //If the name are the same
    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){
      exist = true;
      LocSuccessMessage * success_message = new LocSuccessMessage((*it)->si->server_identifier, (*it)->si->port);
      success_message->send(sock);

      //When we have identified the correct procedure_signature use splice and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
      break;
 		}
	}

  if(!exist){
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

// Returns the binder address
string getBinderAddress() {
   char hostname[MAXHOSTNAMELEN + 1] = {'\0'};
   gethostname(hostname, sizeof(hostname));
   return string(hostname);
}

// Returns the binder port
int getBinderPort(int welcomeSocket) {
   struct sockaddr_in binderAddress;
   socklen_t binderAddressLength = sizeof(binderAddress);

   int result = getsockname(welcomeSocket, (struct sockaddr*) &binderAddress,
      &binderAddressLength);
   if (result < 0) {
      exit(-1);
   } // if

   return ntohs(binderAddress.sin_port);
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, SOMAXCONN);

  cout << "BINDER_ADDRESS " << getBinderAddress() << endl;
  cout << "BINDER_PORT " << getBinderPort(sock) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            status = Segment::receive(sock, segment);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return status;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return status;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<commit_msg>changes<commit_after>#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"
#include "message_results.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *>, ps_compare> proc_loc_dict;
static list<server_function_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/

void registration_request_handler(RegisterRequestMessage * message, int sock){
	const char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  procedure_signature key(name, argTypes);

  int status = 0;

  //if 'key' dosnt exist in map, add it to the map and round robin
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //The purpose of this function is so we can have copy of the argTypes that not the original
    int *memArgTypes = copyArgTypes(argTypes);

    key = procedure_signature(name, memArgTypes);
    proc_loc_dict[key] = list<server_info *>();

    //This is bad we shouldn't need a newKey and we should be able to use the key above
    //due to &* reasones I made a variable newKey for the 'info' object
    procedure_signature * newKey = new procedure_signature(name, memArgTypes);
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    server_function_info * info = new server_function_info(entry, newKey);
    roundRobinList.push_back(info);

  } else {
    bool sameLoc = false;
    list<server_info *> hostList = proc_loc_dict[key];
    //list<server_info *> *hostList = proc_loc_dict.find(key);

    for (list<server_info *>::iterator it = hostList.begin(); it != hostList.end(); it++) {
      if((*it)->socket == sock){ //if they have the same socket, then must be same server_address/port
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something, maybe we should keep
        sameLoc = true;
      }
    }

  	if(!sameLoc){ //same procedure different socket
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList.push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

    //If the name are the same
    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){
      exist = true;
      LocSuccessMessage * success_message = new LocSuccessMessage((*it)->si->server_identifier, (*it)->si->port);
      success_message->send(sock);

      //When we have identified the correct procedure_signature use splice and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
      break;
 		}
	}

  if(!exist){
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

// Returns the binder address
string getBinderAddress() {
   char hostname[MAXHOSTNAMELEN + 1] = {'\0'};
   gethostname(hostname, sizeof(hostname));
   return string(hostname);
}

// Returns the binder port
int getBinderPort(int welcomeSocket) {
   struct sockaddr_in binderAddress;
   socklen_t binderAddressLength = sizeof(binderAddress);

   int result = getsockname(welcomeSocket, (struct sockaddr*) &binderAddress,
      &binderAddressLength);
   if (result < 0) {
      exit(-1);
   } // if

   return ntohs(binderAddress.sin_port);
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, SOMAXCONN);

  cout << "BINDER_ADDRESS " << getBinderAddress() << endl;
  cout << "BINDER_PORT " << getBinderPort(sock) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            status = Segment::receive(sock, segment);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return status;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return status;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<|endoftext|>


<commit_before>extern "C"{
#include "UI.h"
#include "SYSTEM.h"
#include "DISPLAY.h"
}
#include "../fff.h"

#include <gtest/gtest.h>

/* SYSTEM.h */
FAKE_VOID_FUNC2(SYSTEM_register_irq, irq_func_t, unsigned int);
/* DISPLAY.h */
FAKE_VOID_FUNC0(DISPLAY_init);
FAKE_VOID_FUNC0(DISPLAY_clear);
FAKE_VOID_FUNC1(DISPLAY_output, char *);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_capacity);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_insert_index);

FAKE_VOID_FUNC0(button_press_cbk);

class UITests : public testing::Test
{
public:

	void SetUp()
	{
		// Register resets
		RESET_FAKES();
		RESET_HISTORY();
		// non default init
		DISPLAY_get_line_capacity_return_val = 2;
	}
};

/* Tests go here */
TEST_F(UITests, init_will_initialise_display)
{
	UI_init();
	ASSERT_EQ(DISPLAY_init_call_count, 1);
}

TEST_F(UITests, init_will_register_interrupt_gpio2)
{
	UI_init();
    ASSERT_EQ(SYSTEM_register_irq_call_count, 1);
    ASSERT_EQ((void *)SYSTEM_register_irq_arg0_val, (void *)UI_button_irq_handler);
    ASSERT_EQ(SYSTEM_register_irq_arg1_val, IRQ_GPIO_2);
}

TEST_F(UITests, when_no_irq_then_missed_irq_counter_zero)
{
    ASSERT_EQ(UI_get_missed_irqs(), 0);
}

TEST_F(UITests, when_one_irq_and_no_handler_then_missed_irq_counter_one)
{
	UI_button_irq_handler();
    ASSERT_EQ(UI_get_missed_irqs(), 1);
}

TEST_F(UITests, when_one_irq_and_valid_callback_then_missed_irq_counter_zero)
{
	UI_init();
	UI_register_button_cbk(button_press_cbk);
	UI_button_irq_handler();
    ASSERT_EQ(UI_get_missed_irqs(), 0);
}

TEST_F(UITests, when_one_irq_and_valid_callback_then_callback_called)
{
	UI_register_button_cbk(button_press_cbk);
	UI_button_irq_handler();
	ASSERT_EQ(button_press_cbk_call_count, 1);
}

TEST_F(UITests, write_line_outputs_lines_to_display)
{
	char msg[] = "helloworld";
	UI_write_line(msg);
	ASSERT_EQ(DISPLAY_output_call_count, 1);
	ASSERT_EQ(strncmp(DISPLAY_output_arg0_val, msg, 26), 0);
}

TEST_F(UITests, when_no_empty_lines_write_line_clears_screen_and_outputs_lines_to_display)
{
	DISPLAY_get_line_insert_index_return_val = 2;
	char msg[] = "helloworld";

	UI_write_line(msg);

	ASSERT_EQ(DISPLAY_clear_call_count, 1);
	ASSERT_EQ(DISPLAY_output_call_count, 1);
	// Check the order of the calls:  Don't care about the first two:
	// DISPLAY_get_line_capacity and DISPLAY_get_line_insert_index
	ASSERT_EQ(call_history_idx, 4);
	ASSERT_EQ(call_history[2], (void *) DISPLAY_clear);
	ASSERT_EQ(call_history[3], (void *) DISPLAY_output);
}

TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
	// given
	DISPLAY_get_line_insert_index_return_val = 1;
	char msg[] = "helloworld";
	// when
	UI_write_line(msg);
	// then
	ASSERT_EQ(DISPLAY_clear_call_count, 0);
}

TEST_F(UITests, when_string_longer_than_26_then_truncated_string_output)
{
	// given
	char input[] = "abcdefghijklmnopqrstuvwxyz0123456789";
	char expected[] = "abcdefghijklmnopqrstuvwxyz";
	// when
	UI_write_line(input);
	// then
	ASSERT_EQ(strncmp(expected, DISPLAY_output_arg0_val, 37), 0);
}

//TEST_F(UITests, when_outputting_to_full_display_then_previous_inserted)
//{
//	// given
//	DISPLAY_get_line_insert_index_return_val = 1;
//	char oldest[] = "oldest";
//	char newest[] = "newest";
//	// when
//	UI_write_line(oldest);
//	UI_write_line(newest);
//	// then
//
//	ASSERT_EQ(DISPLAY_output_call_count, 2);
//
//	// fills last line
//	ASSERT_EQ(strncmp(oldest, DISPLAY_output_arg0_val_history[0], 37), 0);
//	//clears
//	ASSERT_EQ(DISPLAY_clear_call_count, 1);
//	// inserts old line at first
//	ASSERT_EQ(strncmp(oldest, DISPLAY_output_arg0_val_history[1], 37), 0);
//	// then inserts new line
//	ASSERT_EQ(strncmp(newest, DISPLAY_output_arg0_val_history[2], 37), 0);
//}

<commit_msg>Cleaned up example<commit_after>extern "C"{
#include "UI.h"
#include "SYSTEM.h"
#include "DISPLAY.h"
}
#include "../fff.h"

#include <gtest/gtest.h>

/* SYSTEM.h */
FAKE_VOID_FUNC2(SYSTEM_register_irq, irq_func_t, unsigned int);
/* DISPLAY.h */
FAKE_VOID_FUNC0(DISPLAY_init);
FAKE_VOID_FUNC0(DISPLAY_clear);
FAKE_VOID_FUNC1(DISPLAY_output, char *);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_capacity);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_insert_index);

FAKE_VOID_FUNC0(button_press_cbk);

class UITests : public testing::Test
{
public:

	void SetUp()
	{
		// Register resets
		RESET_FAKES();
		RESET_HISTORY();
		// non default init
		DISPLAY_get_line_capacity_return_val = 2;
	}
};

/* Tests go here */
TEST_F(UITests, init_will_initialise_display)
{
	UI_init();
	ASSERT_EQ(DISPLAY_init_call_count, 1);
}

TEST_F(UITests, init_will_register_interrupt_gpio2)
{
	UI_init();
    ASSERT_EQ(SYSTEM_register_irq_call_count, 1);
    ASSERT_EQ((void *)SYSTEM_register_irq_arg0_val, (void *)UI_button_irq_handler);
    ASSERT_EQ(SYSTEM_register_irq_arg1_val, IRQ_GPIO_2);
}

TEST_F(UITests, when_no_irq_then_missed_irq_counter_zero)
{
    ASSERT_EQ(UI_get_missed_irqs(), 0);
}

TEST_F(UITests, when_one_irq_and_no_handler_then_missed_irq_counter_one)
{
	UI_button_irq_handler();
    ASSERT_EQ(UI_get_missed_irqs(), 1);
}

TEST_F(UITests, when_one_irq_and_valid_callback_then_missed_irq_counter_zero)
{
	UI_init();
	UI_register_button_cbk(button_press_cbk);
	UI_button_irq_handler();
    ASSERT_EQ(UI_get_missed_irqs(), 0);
}

TEST_F(UITests, when_one_irq_and_valid_callback_then_callback_called)
{
	UI_register_button_cbk(button_press_cbk);
	UI_button_irq_handler();
	ASSERT_EQ(button_press_cbk_call_count, 1);
}

TEST_F(UITests, write_line_outputs_lines_to_display)
{
	char msg[] = "helloworld";
	UI_write_line(msg);
	ASSERT_EQ(DISPLAY_output_call_count, 1);
	ASSERT_EQ(strncmp(DISPLAY_output_arg0_val, msg, 26), 0);
}

TEST_F(UITests, when_no_empty_lines_write_line_clears_screen_and_outputs_lines_to_display)
{
	DISPLAY_get_line_insert_index_return_val = 2;
	char msg[] = "helloworld";

	UI_write_line(msg);

	ASSERT_EQ(DISPLAY_clear_call_count, 1);
	ASSERT_EQ(DISPLAY_output_call_count, 1);
	// Check the order of the calls:  Don't care about the first two:
	// DISPLAY_get_line_capacity and DISPLAY_get_line_insert_index
	ASSERT_EQ(call_history_idx, 4);
	ASSERT_EQ(call_history[2], (void *) DISPLAY_clear);
	ASSERT_EQ(call_history[3], (void *) DISPLAY_output);
}

TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
	// given
	DISPLAY_get_line_insert_index_return_val = 1;
	char msg[] = "helloworld";
	// when
	UI_write_line(msg);
	// then
	ASSERT_EQ(DISPLAY_clear_call_count, 0);
}

TEST_F(UITests, when_string_longer_than_26_then_truncated_string_output)
{
	// given
	char input[] = "abcdefghijklmnopqrstuvwxyz0123456789";
	char expected[] = "abcdefghijklmnopqrstuvwxyz";
	// when
	UI_write_line(input);
	// then
	ASSERT_EQ(strncmp(expected, DISPLAY_output_arg0_val, 37), 0);
}

<|endoftext|>


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

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "CentralWidget.h"
#include "ui_CentralWidget.h"

#include <vtkFloatArray.h>
#include <vtkImageData.h>
#include <vtkIntArray.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>
#include <vtkTable.h>
#include <vtkTrivialProducer.h>
#include <vtkVector.h>

#include <vtkPVDiscretizableColorTransferFunction.h>

#include <QThread>
#include <QTimer>

#include "ComputeHistogram.h"
#include "DataSource.h"
#include "Module.h"
#include "ModuleManager.h"
#include "Utilities.h"

#ifdef DAX_DEVICE_ADAPTER
#include "dax/ModuleStreamingContour.h"
#endif

Q_DECLARE_METATYPE(vtkSmartPointer<vtkImageData>)
Q_DECLARE_METATYPE(vtkSmartPointer<vtkTable>)

namespace tomviz {

// This is just here for now - quick and dirty historgram calculations...
void PopulateHistogram(vtkImageData* input, vtkTable* output)
{
  // The output table will have the twice the number of columns, they will be
  // the x and y for input column. This is the bin centers, and the population.
  double minmax[2] = { 0.0, 0.0 };
  const int numberOfBins = 256;

  // Keep the array we are working on around even if the user shallow copies
  // over the input image data by incrementing the reference count here.
  vtkSmartPointer<vtkDataArray> arrayPtr = input->GetPointData()->GetScalars();

  // The bin values are the centers, extending +/- half an inc either side
  switch (arrayPtr->GetDataType()) {
    vtkTemplateMacro(tomviz::GetScalarRange(
      reinterpret_cast<VTK_TT*>(arrayPtr->GetVoidPointer(0)),
      input->GetPointData()->GetScalars()->GetNumberOfTuples(), minmax));
    default:
      break;
  }
  if (minmax[0] == minmax[1]) {
    minmax[1] = minmax[0] + 1.0;
  }

  double inc = (minmax[1] - minmax[0]) / numberOfBins;
  double halfInc = inc / 2.0;
  vtkSmartPointer<vtkFloatArray> extents = vtkFloatArray::SafeDownCast(
    output->GetColumnByName(vtkStdString("image_extents").c_str()));
  if (!extents) {
    extents = vtkSmartPointer<vtkFloatArray>::New();
    extents->SetName(vtkStdString("image_extents").c_str());
  }
  extents->SetNumberOfTuples(numberOfBins);
  double min = minmax[0] + halfInc;
  for (int j = 0; j < numberOfBins; ++j) {
    extents->SetValue(j, min + j * inc);
  }
  vtkSmartPointer<vtkIntArray> populations = vtkIntArray::SafeDownCast(
    output->GetColumnByName(vtkStdString("image_pops").c_str()));
  if (!populations) {
    populations = vtkSmartPointer<vtkIntArray>::New();
    populations->SetName(vtkStdString("image_pops").c_str());
  }
  populations->SetNumberOfTuples(numberOfBins);
  auto pops = static_cast<int*>(populations->GetVoidPointer(0));
  for (int k = 0; k < numberOfBins; ++k) {
    pops[k] = 0;
  }
  int invalid = 0;

  switch (arrayPtr->GetDataType()) {
    vtkTemplateMacro(tomviz::CalculateHistogram(
      reinterpret_cast<VTK_TT*>(arrayPtr->GetVoidPointer(0)),
      arrayPtr->GetNumberOfTuples(), minmax[0], pops, inc, numberOfBins,
      invalid));
    default:
      cout << "UpdateFromFile: Unknown data type" << endl;
  }

#ifndef NDEBUG
  vtkIdType total = invalid;
  for (int i = 0; i < numberOfBins; ++i)
    total += pops[i];
  assert(total == arrayPtr->GetNumberOfTuples());
#endif
  if (invalid) {
    cout << "Warning: NaN or infinite value in dataset" << endl;
  }

  output->AddColumn(extents.Get());
  output->AddColumn(populations.Get());
}

// This is a QObject that will be owned by the background thread
// and use signals/slots to create histograms
class HistogramMaker : public QObject
{
  Q_OBJECT

  void run();

public:
  HistogramMaker(QObject* p = nullptr) : QObject(p) {}

public slots:
  void makeHistogram(vtkSmartPointer<vtkImageData> input,
                     vtkSmartPointer<vtkTable> output);

signals:
  void histogramDone(vtkSmartPointer<vtkImageData> image,
                     vtkSmartPointer<vtkTable> output);
};

void HistogramMaker::makeHistogram(vtkSmartPointer<vtkImageData> input,
                                   vtkSmartPointer<vtkTable> output)
{
  // make the histogram and notify observers (the main thread) that it
  // is done.
  if (input && output) {
    PopulateHistogram(input.Get(), output.Get());
  }
  emit histogramDone(input, output);
}

CentralWidget::CentralWidget(QWidget* parentObject, Qt::WindowFlags wflags)
  : QWidget(parentObject, wflags), m_ui(new Ui::CentralWidget),
    m_timer(new QTimer(this)), m_histogramGen(new HistogramMaker),
    m_worker(new QThread(this))
{
  m_ui->setupUi(this);

  qRegisterMetaType<vtkSmartPointer<vtkImageData>>();
  qRegisterMetaType<vtkSmartPointer<vtkTable>>();

  QList<int> sizes;
  sizes << 200 << 200;
  m_ui->splitter->setSizes(sizes);
  m_ui->splitter->setStretchFactor(0, 0);
  m_ui->splitter->setStretchFactor(1, 1);

  connect(m_ui->histogramWidget, SIGNAL(colorMapUpdated()),
          SLOT(onColorMapUpdated()));
  connect(m_ui->histogramWidget, SIGNAL(gradientVisibilityChanged(bool)),
          m_ui->gradientOpacityWidget, SLOT(setVisible(bool)));
  connect(m_ui->gradientOpacityWidget, SIGNAL(mapUpdated()),
          SLOT(onColorMapUpdated()));
  m_ui->gradientOpacityWidget->hide();

  // Start the worker thread and give it ownership of the HistogramMaker
  // object. Also connect the HistogramMaker's signal to the histogramReady
  // slot on this object. This slot will be called on the GUI thread when the
  // histogram has been finished on the background thread.
  m_worker->start();
  m_histogramGen->moveToThread(m_worker);
  connect(m_histogramGen, SIGNAL(histogramDone(vtkSmartPointer<vtkImageData>,
                                               vtkSmartPointer<vtkTable>)),
          SLOT(histogramReady(vtkSmartPointer<vtkImageData>,
                              vtkSmartPointer<vtkTable>)));
  m_timer->setInterval(200);
  m_timer->setSingleShot(true);
  connect(m_timer.data(), SIGNAL(timeout()), SLOT(refreshHistogram()));
  layout()->setMargin(0);
  layout()->setSpacing(0);
}

CentralWidget::~CentralWidget()
{
  // disconnect all signals/slots
  disconnect(m_histogramGen, nullptr, nullptr, nullptr);
  // when the HistogramMaker is deleted, kill the background thread
  connect(m_histogramGen, SIGNAL(destroyed()), m_worker, SLOT(quit()));
  // I can't remember if deleteLater must be called on the owning thread
  // play it safe and let the owning thread call it.
  QMetaObject::invokeMethod(m_histogramGen, "deleteLater");
  // Wait for the background thread to clean up the object and quit
  while (m_worker->isRunning()) {
    QCoreApplication::processEvents();
  }
}

void CentralWidget::setActiveDataSource(DataSource* source)
{
  if (m_activeModule) {
    m_activeModule->disconnect(this);
    m_activeModule = nullptr;
  }
  setDataSource(source);
}

void CentralWidget::setActiveModule(Module* module)
{
  if (m_activeModule) {
    m_activeModule->disconnect(this);
  }
  m_activeModule = module;
  if (m_activeModule) {
    connect(m_activeModule, SIGNAL(colorMapChanged()),
            SLOT(onDataSourceChanged()));
    setDataSource(module->dataSource());
  } else {
    setDataSource(nullptr);
  }
}

void CentralWidget::setDataSource(DataSource* source)
{
  if (m_activeDataSource) {
    m_activeDataSource->disconnect(this);
    m_ui->histogramWidget->disconnect(m_activeDataSource);
  }
  m_activeDataSource = source;

  if (source) {
    m_ui->histogramWidget->setGradientOpacityChecked(
      source->isGradientOpacityVisible());

    connect(source, SIGNAL(dataChanged()), SLOT(onDataSourceChanged()));

    connect(m_ui->histogramWidget, SIGNAL(gradientVisibilityChanged(bool)),
            source, SLOT(setGradientOpacityVisibility(bool)));
  }

  if (!source) {
    m_ui->histogramWidget->setInputData(nullptr, "", "");
    m_ui->gradientOpacityWidget->setInputData(nullptr, "", "");
    return;
  }

  // Get the actual data source, build a histogram out of it.
  auto t =
    vtkTrivialProducer::SafeDownCast(source->producer()->GetClientSideObject());
  auto image = vtkImageData::SafeDownCast(t->GetOutputDataObject(0));

  if (image->GetPointData()->GetScalars() == nullptr) {
    return;
  }

  // Get the current color map
  if (m_activeModule) {
    m_ui->histogramWidget->setLUTProxy(m_activeModule->colorMap());
    if (m_activeModule->supportsGradientOpacity()) {
      m_ui->gradientOpacityWidget->setLUT(m_activeModule->gradientOpacityMap());
    }
  } else {
    m_ui->histogramWidget->setLUTProxy(source->colorMap());
    m_ui->gradientOpacityWidget->setLUT(source->gradientOpacityMap());
  }

  // Check our cache, and use that if appopriate (or update it).
  if (m_histogramCache.contains(image)) {
    auto cachedTable = m_histogramCache[image];
    if (cachedTable->GetMTime() > image->GetMTime()) {
      setHistogramTable(cachedTable);
      return;
    } else {
      // Need to recalculate, clear the plots, and remove the cached data.
      m_histogramCache.remove(image);
    }
  }

  // Calculate a histogram.
  auto table = vtkSmartPointer<vtkTable>::New();
  m_histogramCache[image] = table.Get();
  vtkSmartPointer<vtkImageData> const imageSP = image;

  // This fakes a Qt signal to the background thread (without exposing the
  // class internals as a signal).  The background thread will then call
  // makeHistogram on the HistogramMaker object with the parameters we
  // gave here.
  QMetaObject::invokeMethod(m_histogramGen, "makeHistogram",
                            Q_ARG(vtkSmartPointer<vtkImageData>, imageSP),
                            Q_ARG(vtkSmartPointer<vtkTable>, table));
}

void CentralWidget::onColorMapUpdated()
{
  this->onDataSourceChanged();
}

void CentralWidget::onDataSourceChanged()
{
  // This starts/restarts the internal timer so that several events occurring
  // within a few milliseconds of each other only result in one call to
  // refreshHistogram()
  m_timer->start();
}

void CentralWidget::refreshHistogram()
{
  setDataSource(m_activeDataSource);
}

void CentralWidget::histogramReady(vtkSmartPointer<vtkImageData> input,
                                   vtkSmartPointer<vtkTable> output)
{
  if (!input || !output) {
    return;
  }

  // If we no longer have an active datasource, ignore showing the histogram
  // since the data has been deleted
  if (!m_activeDataSource) {
    return;
  }

  auto t = vtkTrivialProducer::SafeDownCast(
    m_activeDataSource->producer()->GetClientSideObject());
  auto image = vtkImageData::SafeDownCast(t->GetOutputDataObject(0));

  // The current dataset has changed since the histogram was requested,
  // ignore this histogram and wait for the next one queued...
  if (image != input.Get()) {
    return;
  }

  setHistogramTable(output.Get());
}

void CentralWidget::setHistogramTable(vtkTable* table)
{
  auto arr = vtkDataArray::SafeDownCast(table->GetColumnByName("image_pops"));
  if (!arr) {
    return;
  }

  m_ui->histogramWidget->setInputData(table, "image_extents", "image_pops");
  m_ui->gradientOpacityWidget->setInputData(table, "image_extents",
                                            "image_pops");
}
} // end of namespace tomviz

#include "CentralWidget.moc"
<commit_msg>Hide layout tabs to save some vertical space<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "CentralWidget.h"
#include "ui_CentralWidget.h"

#include <vtkFloatArray.h>
#include <vtkImageData.h>
#include <vtkIntArray.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>
#include <vtkTable.h>
#include <vtkTrivialProducer.h>
#include <vtkVector.h>

#include <vtkPVDiscretizableColorTransferFunction.h>

#include <QThread>
#include <QTimer>

#include "ComputeHistogram.h"
#include "DataSource.h"
#include "Module.h"
#include "ModuleManager.h"
#include "Utilities.h"

#ifdef DAX_DEVICE_ADAPTER
#include "dax/ModuleStreamingContour.h"
#endif

Q_DECLARE_METATYPE(vtkSmartPointer<vtkImageData>)
Q_DECLARE_METATYPE(vtkSmartPointer<vtkTable>)

namespace tomviz {

// This is just here for now - quick and dirty historgram calculations...
void PopulateHistogram(vtkImageData* input, vtkTable* output)
{
  // The output table will have the twice the number of columns, they will be
  // the x and y for input column. This is the bin centers, and the population.
  double minmax[2] = { 0.0, 0.0 };
  const int numberOfBins = 256;

  // Keep the array we are working on around even if the user shallow copies
  // over the input image data by incrementing the reference count here.
  vtkSmartPointer<vtkDataArray> arrayPtr = input->GetPointData()->GetScalars();

  // The bin values are the centers, extending +/- half an inc either side
  switch (arrayPtr->GetDataType()) {
    vtkTemplateMacro(tomviz::GetScalarRange(
      reinterpret_cast<VTK_TT*>(arrayPtr->GetVoidPointer(0)),
      input->GetPointData()->GetScalars()->GetNumberOfTuples(), minmax));
    default:
      break;
  }
  if (minmax[0] == minmax[1]) {
    minmax[1] = minmax[0] + 1.0;
  }

  double inc = (minmax[1] - minmax[0]) / numberOfBins;
  double halfInc = inc / 2.0;
  vtkSmartPointer<vtkFloatArray> extents = vtkFloatArray::SafeDownCast(
    output->GetColumnByName(vtkStdString("image_extents").c_str()));
  if (!extents) {
    extents = vtkSmartPointer<vtkFloatArray>::New();
    extents->SetName(vtkStdString("image_extents").c_str());
  }
  extents->SetNumberOfTuples(numberOfBins);
  double min = minmax[0] + halfInc;
  for (int j = 0; j < numberOfBins; ++j) {
    extents->SetValue(j, min + j * inc);
  }
  vtkSmartPointer<vtkIntArray> populations = vtkIntArray::SafeDownCast(
    output->GetColumnByName(vtkStdString("image_pops").c_str()));
  if (!populations) {
    populations = vtkSmartPointer<vtkIntArray>::New();
    populations->SetName(vtkStdString("image_pops").c_str());
  }
  populations->SetNumberOfTuples(numberOfBins);
  auto pops = static_cast<int*>(populations->GetVoidPointer(0));
  for (int k = 0; k < numberOfBins; ++k) {
    pops[k] = 0;
  }
  int invalid = 0;

  switch (arrayPtr->GetDataType()) {
    vtkTemplateMacro(tomviz::CalculateHistogram(
      reinterpret_cast<VTK_TT*>(arrayPtr->GetVoidPointer(0)),
      arrayPtr->GetNumberOfTuples(), minmax[0], pops, inc, numberOfBins,
      invalid));
    default:
      cout << "UpdateFromFile: Unknown data type" << endl;
  }

#ifndef NDEBUG
  vtkIdType total = invalid;
  for (int i = 0; i < numberOfBins; ++i)
    total += pops[i];
  assert(total == arrayPtr->GetNumberOfTuples());
#endif
  if (invalid) {
    cout << "Warning: NaN or infinite value in dataset" << endl;
  }

  output->AddColumn(extents.Get());
  output->AddColumn(populations.Get());
}

// This is a QObject that will be owned by the background thread
// and use signals/slots to create histograms
class HistogramMaker : public QObject
{
  Q_OBJECT

  void run();

public:
  HistogramMaker(QObject* p = nullptr) : QObject(p) {}

public slots:
  void makeHistogram(vtkSmartPointer<vtkImageData> input,
                     vtkSmartPointer<vtkTable> output);

signals:
  void histogramDone(vtkSmartPointer<vtkImageData> image,
                     vtkSmartPointer<vtkTable> output);
};

void HistogramMaker::makeHistogram(vtkSmartPointer<vtkImageData> input,
                                   vtkSmartPointer<vtkTable> output)
{
  // make the histogram and notify observers (the main thread) that it
  // is done.
  if (input && output) {
    PopulateHistogram(input.Get(), output.Get());
  }
  emit histogramDone(input, output);
}

CentralWidget::CentralWidget(QWidget* parentObject, Qt::WindowFlags wflags)
  : QWidget(parentObject, wflags), m_ui(new Ui::CentralWidget),
    m_timer(new QTimer(this)), m_histogramGen(new HistogramMaker),
    m_worker(new QThread(this))
{
  m_ui->setupUi(this);

  // Hide the layout tabs
  m_ui->tabbedMultiViewWidget->setTabVisibility(false);

  qRegisterMetaType<vtkSmartPointer<vtkImageData>>();
  qRegisterMetaType<vtkSmartPointer<vtkTable>>();

  QList<int> sizes;
  sizes << 200 << 200;
  m_ui->splitter->setSizes(sizes);
  m_ui->splitter->setStretchFactor(0, 0);
  m_ui->splitter->setStretchFactor(1, 1);

  connect(m_ui->histogramWidget, SIGNAL(colorMapUpdated()),
          SLOT(onColorMapUpdated()));
  connect(m_ui->histogramWidget, SIGNAL(gradientVisibilityChanged(bool)),
          m_ui->gradientOpacityWidget, SLOT(setVisible(bool)));
  connect(m_ui->gradientOpacityWidget, SIGNAL(mapUpdated()),
          SLOT(onColorMapUpdated()));
  m_ui->gradientOpacityWidget->hide();

  // Start the worker thread and give it ownership of the HistogramMaker
  // object. Also connect the HistogramMaker's signal to the histogramReady
  // slot on this object. This slot will be called on the GUI thread when the
  // histogram has been finished on the background thread.
  m_worker->start();
  m_histogramGen->moveToThread(m_worker);
  connect(m_histogramGen, SIGNAL(histogramDone(vtkSmartPointer<vtkImageData>,
                                               vtkSmartPointer<vtkTable>)),
          SLOT(histogramReady(vtkSmartPointer<vtkImageData>,
                              vtkSmartPointer<vtkTable>)));
  m_timer->setInterval(200);
  m_timer->setSingleShot(true);
  connect(m_timer.data(), SIGNAL(timeout()), SLOT(refreshHistogram()));
  layout()->setMargin(0);
  layout()->setSpacing(0);
}

CentralWidget::~CentralWidget()
{
  // disconnect all signals/slots
  disconnect(m_histogramGen, nullptr, nullptr, nullptr);
  // when the HistogramMaker is deleted, kill the background thread
  connect(m_histogramGen, SIGNAL(destroyed()), m_worker, SLOT(quit()));
  // I can't remember if deleteLater must be called on the owning thread
  // play it safe and let the owning thread call it.
  QMetaObject::invokeMethod(m_histogramGen, "deleteLater");
  // Wait for the background thread to clean up the object and quit
  while (m_worker->isRunning()) {
    QCoreApplication::processEvents();
  }
}

void CentralWidget::setActiveDataSource(DataSource* source)
{
  if (m_activeModule) {
    m_activeModule->disconnect(this);
    m_activeModule = nullptr;
  }
  setDataSource(source);
}

void CentralWidget::setActiveModule(Module* module)
{
  if (m_activeModule) {
    m_activeModule->disconnect(this);
  }
  m_activeModule = module;
  if (m_activeModule) {
    connect(m_activeModule, SIGNAL(colorMapChanged()),
            SLOT(onDataSourceChanged()));
    setDataSource(module->dataSource());
  } else {
    setDataSource(nullptr);
  }
}

void CentralWidget::setDataSource(DataSource* source)
{
  if (m_activeDataSource) {
    m_activeDataSource->disconnect(this);
    m_ui->histogramWidget->disconnect(m_activeDataSource);
  }
  m_activeDataSource = source;

  if (source) {
    m_ui->histogramWidget->setGradientOpacityChecked(
      source->isGradientOpacityVisible());

    connect(source, SIGNAL(dataChanged()), SLOT(onDataSourceChanged()));

    connect(m_ui->histogramWidget, SIGNAL(gradientVisibilityChanged(bool)),
            source, SLOT(setGradientOpacityVisibility(bool)));
  }

  if (!source) {
    m_ui->histogramWidget->setInputData(nullptr, "", "");
    m_ui->gradientOpacityWidget->setInputData(nullptr, "", "");
    return;
  }

  // Get the actual data source, build a histogram out of it.
  auto t =
    vtkTrivialProducer::SafeDownCast(source->producer()->GetClientSideObject());
  auto image = vtkImageData::SafeDownCast(t->GetOutputDataObject(0));

  if (image->GetPointData()->GetScalars() == nullptr) {
    return;
  }

  // Get the current color map
  if (m_activeModule) {
    m_ui->histogramWidget->setLUTProxy(m_activeModule->colorMap());
    if (m_activeModule->supportsGradientOpacity()) {
      m_ui->gradientOpacityWidget->setLUT(m_activeModule->gradientOpacityMap());
    }
  } else {
    m_ui->histogramWidget->setLUTProxy(source->colorMap());
    m_ui->gradientOpacityWidget->setLUT(source->gradientOpacityMap());
  }

  // Check our cache, and use that if appopriate (or update it).
  if (m_histogramCache.contains(image)) {
    auto cachedTable = m_histogramCache[image];
    if (cachedTable->GetMTime() > image->GetMTime()) {
      setHistogramTable(cachedTable);
      return;
    } else {
      // Need to recalculate, clear the plots, and remove the cached data.
      m_histogramCache.remove(image);
    }
  }

  // Calculate a histogram.
  auto table = vtkSmartPointer<vtkTable>::New();
  m_histogramCache[image] = table.Get();
  vtkSmartPointer<vtkImageData> const imageSP = image;

  // This fakes a Qt signal to the background thread (without exposing the
  // class internals as a signal).  The background thread will then call
  // makeHistogram on the HistogramMaker object with the parameters we
  // gave here.
  QMetaObject::invokeMethod(m_histogramGen, "makeHistogram",
                            Q_ARG(vtkSmartPointer<vtkImageData>, imageSP),
                            Q_ARG(vtkSmartPointer<vtkTable>, table));
}

void CentralWidget::onColorMapUpdated()
{
  this->onDataSourceChanged();
}

void CentralWidget::onDataSourceChanged()
{
  // This starts/restarts the internal timer so that several events occurring
  // within a few milliseconds of each other only result in one call to
  // refreshHistogram()
  m_timer->start();
}

void CentralWidget::refreshHistogram()
{
  setDataSource(m_activeDataSource);
}

void CentralWidget::histogramReady(vtkSmartPointer<vtkImageData> input,
                                   vtkSmartPointer<vtkTable> output)
{
  if (!input || !output) {
    return;
  }

  // If we no longer have an active datasource, ignore showing the histogram
  // since the data has been deleted
  if (!m_activeDataSource) {
    return;
  }

  auto t = vtkTrivialProducer::SafeDownCast(
    m_activeDataSource->producer()->GetClientSideObject());
  auto image = vtkImageData::SafeDownCast(t->GetOutputDataObject(0));

  // The current dataset has changed since the histogram was requested,
  // ignore this histogram and wait for the next one queued...
  if (image != input.Get()) {
    return;
  }

  setHistogramTable(output.Get());
}

void CentralWidget::setHistogramTable(vtkTable* table)
{
  auto arr = vtkDataArray::SafeDownCast(table->GetColumnByName("image_pops"));
  if (!arr) {
    return;
  }

  m_ui->histogramWidget->setInputData(table, "image_extents", "image_pops");
  m_ui->gradientOpacityWidget->setInputData(table, "image_extents",
                                            "image_pops");
}
} // end of namespace tomviz

#include "CentralWidget.moc"
<|endoftext|>


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

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "ModuleContour.h"

#include "DataSource.h"
#include "DoubleSliderWidget.h"
#include "Utilities.h"

#include "pqColorChooserButton.h"
#include "pqPropertyLinks.h"
#include "pqSignalAdaptors.h"
#include "pqWidgetRangeDomain.h"

#include "vtkDataObject.h"
#include "vtkNew.h"
#include "vtkSMParaViewPipelineControllerWithRendering.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMViewProxy.h"
#include "vtkSmartPointer.h"

#include <algorithm>
#include <string>
#include <vector>

#include <QCheckBox>
#include <QComboBox>
#include <QFormLayout>
#include <QLabel>

namespace tomviz {

class ModuleContour::Private
{
public:
  std::string NonLabelMapArrayName;
  bool UseSolidColor;
  pqPropertyLinks Links;
};

ModuleContour::ModuleContour(QObject* parentObject) : Superclass(parentObject)
{
  this->Internals = new Private;
  this->Internals->Links.setAutoUpdateVTKObjects(true);
  this->Internals->UseSolidColor = false;
}

ModuleContour::~ModuleContour()
{
  this->finalize();

  delete this->Internals;
  this->Internals = nullptr;
}

QIcon ModuleContour::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqIsosurface24.png");
}

bool ModuleContour::initialize(DataSource* data, vtkSMViewProxy* vtkView)
{
  if (!this->Superclass::initialize(data, vtkView)) {
    return false;
  }

  vtkSMSourceProxy* producer = data->producer();

  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  vtkSMSessionProxyManager* pxm = producer->GetSessionProxyManager();

  vtkSmartPointer<vtkSMProxy> contourProxy;
  contourProxy.TakeReference(pxm->NewProxy("filters", "FlyingEdges"));

  this->ContourFilter = vtkSMSourceProxy::SafeDownCast(contourProxy);
  Q_ASSERT(this->ContourFilter);
  controller->PreInitializeProxy(this->ContourFilter);
  vtkSMPropertyHelper(this->ContourFilter, "Input").Set(producer);
  vtkSMPropertyHelper(this->ContourFilter, "ComputeScalars", /*quiet*/ true)
    .Set(1);

  controller->PostInitializeProxy(this->ContourFilter);
  controller->RegisterPipelineProxy(this->ContourFilter);

  // Set up a data resampler to add LabelMap values on the contour
  vtkSmartPointer<vtkSMProxy> probeProxy;
  probeProxy.TakeReference(pxm->NewProxy("filters", "ResampleWithDataset"));

  this->ResampleFilter = vtkSMSourceProxy::SafeDownCast(probeProxy);
  Q_ASSERT(this->ResampleFilter);
  controller->PreInitializeProxy(this->ResampleFilter);
  vtkSMPropertyHelper(this->ResampleFilter, "Input").Set(data->producer());
  vtkSMPropertyHelper(this->ResampleFilter, "Source").Set(this->ContourFilter);
  controller->PostInitializeProxy(this->ResampleFilter);
  controller->RegisterPipelineProxy(this->ResampleFilter);

  // Create the representation for it. Show the unresampled contour filter to
  // start.
  this->ContourRepresentation =
    controller->Show(this->ContourFilter, 0, vtkView);
  Q_ASSERT(this->ContourRepresentation);
  vtkSMPropertyHelper(this->ContourRepresentation, "Representation")
    .Set("Surface");
  vtkSMPropertyHelper(this->ContourRepresentation, "Position")
    .Set(data->displayPosition(), 3);

  vtkSMPropertyHelper colorArrayHelper(this->ContourRepresentation,
                                       "ColorArrayName");
  this->Internals->NonLabelMapArrayName =
    std::string(colorArrayHelper.GetInputArrayNameToProcess());

  vtkSMPropertyHelper colorHelper(this->ContourRepresentation, "DiffuseColor");
  double white[3] = { 1.0, 1.0, 1.0 };
  colorHelper.Set(white, 3);
  // use proper color map.
  this->updateColorMap();

  this->ContourRepresentation->UpdateVTKObjects();

  return true;
}

void ModuleContour::updateColorMap()
{
  Q_ASSERT(this->ContourRepresentation);
  vtkSMPropertyHelper(this->ContourRepresentation, "LookupTable")
    .Set(this->colorMap());
  vtkSMPropertyHelper colorArrayHelper(this->ContourRepresentation,
                                       "ColorArrayName");

  if (this->colorByLabelMap()) {
    this->Internals->NonLabelMapArrayName =
      std::string(colorArrayHelper.GetInputArrayNameToProcess());
    colorArrayHelper.SetInputArrayToProcess(
      vtkDataObject::FIELD_ASSOCIATION_POINTS, "LabelMap");

    vtkSMPropertyHelper(this->ContourRepresentation, "Input")
      .Set(this->ResampleFilter);
  } else {
    if (this->Internals->UseSolidColor) {
      colorArrayHelper.SetInputArrayToProcess(
        vtkDataObject::FIELD_ASSOCIATION_POINTS, "");
    } else {
      colorArrayHelper.SetInputArrayToProcess(
        vtkDataObject::FIELD_ASSOCIATION_POINTS,
        this->Internals->NonLabelMapArrayName.c_str());
    }
    vtkSMPropertyHelper(this->ContourRepresentation, "Input")
      .Set(this->ContourFilter);
  }

  vtkSMPropertyHelper(this->ContourRepresentation, "Visibility")
    .Set(this->visibility() ? 1 : 0);
  this->ContourRepresentation->UpdateVTKObjects();
}

bool ModuleContour::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(this->ResampleFilter);
  controller->UnRegisterProxy(this->ContourRepresentation);
  controller->UnRegisterProxy(this->ContourFilter);
  this->ResampleFilter = nullptr;
  this->ContourFilter = nullptr;
  this->ContourRepresentation = nullptr;
  return true;
}

bool ModuleContour::setVisibility(bool val)
{
  Q_ASSERT(this->ContourRepresentation);
  vtkSMPropertyHelper(this->ContourRepresentation, "Visibility")
    .Set(val ? 1 : 0);
  this->ContourRepresentation->UpdateVTKObjects();

  return true;
}

bool ModuleContour::visibility() const
{
  Q_ASSERT(this->ContourRepresentation);
  return vtkSMPropertyHelper(this->ContourRepresentation, "Visibility")
           .GetAsInt() != 0;
}

void ModuleContour::setIsoValues(const QList<double>& values)
{
  std::vector<double> vectorValues(values.size());
  std::copy(values.begin(), values.end(), vectorValues.begin());
  vectorValues.push_back(0); // to avoid having to check for 0 size on Windows.

  vtkSMPropertyHelper(this->ContourFilter, "ContourValues")
    .Set(&vectorValues[0], values.size());
  this->ContourFilter->UpdateVTKObjects();
}

void ModuleContour::addToPanel(QWidget* panel)
{
  Q_ASSERT(this->ContourFilter);
  Q_ASSERT(this->ContourRepresentation);

  if (panel->layout()) {
    delete panel->layout();
  }

  QFormLayout* layout = new QFormLayout;

  //Solid color
  QHBoxLayout* colorLayout = new QHBoxLayout;
  colorLayout->addStretch();

  QCheckBox* useSolidColor = new QCheckBox;
  useSolidColor->setChecked(this->Internals->UseSolidColor);
  QObject::connect(useSolidColor, &QCheckBox::stateChanged, this,
                   &ModuleContour::setUseSolidColor);
  colorLayout->addWidget(useSolidColor);

  QLabel* colorLabel = new QLabel("Select Color");
  colorLayout->addWidget(colorLabel);

  pqColorChooserButton* colorSelector = new pqColorChooserButton(panel);
  colorLayout->addWidget(colorSelector);
  layout->addRow("", colorLayout);

  colorSelector->setShowAlphaChannel(false);
  DoubleSliderWidget* valueSlider = new DoubleSliderWidget(true);
  valueSlider->setLineEditWidth(50);
  layout->addRow("Value", valueSlider);

  QComboBox* representations = new QComboBox;
  representations->addItem("Surface");
  representations->addItem("Wireframe");
  representations->addItem("Points");
  layout->addRow("", representations);
  // TODO connect to update function

  DoubleSliderWidget* opacitySlider = new DoubleSliderWidget(true);
  opacitySlider->setLineEditWidth(50);
  layout->addRow("Opacity", opacitySlider);

  DoubleSliderWidget* specularSlider = new DoubleSliderWidget(true);
  specularSlider->setLineEditWidth(50);
  layout->addRow("Specular", specularSlider);

  pqSignalAdaptorComboBox* adaptor =
    new pqSignalAdaptorComboBox(representations);
  // layout->addStretch();

  panel->setLayout(layout);

  this->Internals->Links.addPropertyLink(
    valueSlider, "value", SIGNAL(valueEdited(double)), this->ContourFilter,
    this->ContourFilter->GetProperty("ContourValues"), 0);
  new pqWidgetRangeDomain(valueSlider, "minimum", "maximum",
                          this->ContourFilter->GetProperty("ContourValues"), 0);

  this->Internals->Links.addPropertyLink(
    adaptor, "currentText", SIGNAL(currentTextChanged(QString)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("Representation"));

  this->Internals->Links.addPropertyLink(
    opacitySlider, "value", SIGNAL(valueEdited(double)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("Opacity"), 0);
  this->Internals->Links.addPropertyLink(
    specularSlider, "value", SIGNAL(valueEdited(double)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("Specular"), 0);

  // Surface uses DiffuseColor and Wireframe uses AmbientColor so we have to set
  // both
  this->Internals->Links.addPropertyLink(
    colorSelector, "chosenColorRgbF", SIGNAL(chosenColorChanged(const QColor&)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("DiffuseColor"));
  this->Internals->Links.addPropertyLink(
    colorSelector, "chosenColorRgbF", SIGNAL(chosenColorChanged(const QColor&)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("AmbientColor"));

  this->connect(valueSlider, &DoubleSliderWidget::valueEdited, this,
                &ModuleContour::dataUpdated);
  this->connect(representations, &QComboBox::currentTextChanged, this,
                &ModuleContour::dataUpdated);
  this->connect(opacitySlider, &DoubleSliderWidget::valueEdited, this,
                &ModuleContour::dataUpdated);
  this->connect(specularSlider, &DoubleSliderWidget::valueEdited, this,
                &ModuleContour::dataUpdated);
  this->connect(colorSelector, &pqColorChooserButton::chosenColorChanged, this,
                &ModuleContour::dataUpdated);
}

void ModuleContour::dataUpdated()
{
  this->Internals->Links.accept();
  emit this->renderNeeded();
}

bool ModuleContour::serialize(pugi::xml_node& ns) const
{
  ns.append_attribute("solid_color").set_value(this->Internals->UseSolidColor);
  // save stuff that the user can change.
  pugi::xml_node node = ns.append_child("ContourFilter");
  QStringList contourProperties;
  contourProperties << "ContourValues";
  if (tomviz::serialize(this->ContourFilter, node, contourProperties) ==
      false) {
    qWarning("Failed to serialize ContourFilter.");
    ns.remove_child(node);
    return false;
  }

  QStringList contourRepresentationProperties;
  contourRepresentationProperties << "Representation"
                                  << "Opacity"
                                  << "Specular"
                                  << "Visibility"
                                  << "DiffuseColor";

  node = ns.append_child("ContourRepresentation");
  if (tomviz::serialize(this->ContourRepresentation, node,
                        contourRepresentationProperties) == false) {
    qWarning("Failed to serialize ContourRepresentation.");
    ns.remove_child(node);
    return false;
  }

  return this->Superclass::serialize(ns);
}

bool ModuleContour::deserialize(const pugi::xml_node& ns)
{
  if (ns.attribute("solid_color")) {
    this->Internals->UseSolidColor = ns.attribute("solid_color").as_bool();
  }
  return tomviz::deserialize(this->ContourFilter, ns.child("ContourFilter")) &&
         tomviz::deserialize(this->ContourRepresentation,
                             ns.child("ContourRepresentation")) &&
         this->Superclass::deserialize(ns);
}

void ModuleContour::dataSourceMoved(double newX, double newY, double newZ)
{
  double pos[3] = { newX, newY, newZ };
  vtkSMPropertyHelper(this->ContourRepresentation, "Position").Set(pos, 3);
  this->ContourRepresentation->MarkDirty(this->ContourRepresentation);
  this->ContourRepresentation->UpdateVTKObjects();
}

bool ModuleContour::isProxyPartOfModule(vtkSMProxy* proxy)
{
  return (proxy == this->ContourFilter.Get()) ||
         (proxy == this->ContourRepresentation.Get()) ||
         (proxy == this->ResampleFilter.Get());
}

std::string ModuleContour::getStringForProxy(vtkSMProxy* proxy)
{
  if (proxy == this->ContourFilter.Get()) {
    return "Contour";
  } else if (proxy == this->ContourRepresentation.Get()) {
    return "Representation";
  } else if (proxy == this->ResampleFilter.Get()) {
    return "Resample";
  } else {
    qWarning("Gave bad proxy to module in save animation state");
    return "";
  }
}

vtkSMProxy* ModuleContour::getProxyForString(const std::string& str)
{
  if (str == "Resample") {
    return this->ResampleFilter.Get();
  } else if (str == "Representation") {
    return this->ContourRepresentation.Get();
  } else if (str == "Contour") {
    return this->ContourFilter.Get();
  } else {
    return nullptr;
  }
}

void ModuleContour::setUseSolidColor(int useSolidColor)
{
  this->Internals->UseSolidColor = (useSolidColor != 0);
  this->updateColorMap();
  emit this->renderNeeded();
}

} // end of namespace tomviz
<commit_msg>fix formatting<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "ModuleContour.h"

#include "DataSource.h"
#include "DoubleSliderWidget.h"
#include "Utilities.h"

#include "pqColorChooserButton.h"
#include "pqPropertyLinks.h"
#include "pqSignalAdaptors.h"
#include "pqWidgetRangeDomain.h"

#include "vtkDataObject.h"
#include "vtkNew.h"
#include "vtkSMParaViewPipelineControllerWithRendering.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMViewProxy.h"
#include "vtkSmartPointer.h"

#include <algorithm>
#include <string>
#include <vector>

#include <QCheckBox>
#include <QComboBox>
#include <QFormLayout>
#include <QLabel>

namespace tomviz {

class ModuleContour::Private
{
public:
  std::string NonLabelMapArrayName;
  bool UseSolidColor;
  pqPropertyLinks Links;
};

ModuleContour::ModuleContour(QObject* parentObject) : Superclass(parentObject)
{
  this->Internals = new Private;
  this->Internals->Links.setAutoUpdateVTKObjects(true);
  this->Internals->UseSolidColor = false;
}

ModuleContour::~ModuleContour()
{
  this->finalize();

  delete this->Internals;
  this->Internals = nullptr;
}

QIcon ModuleContour::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqIsosurface24.png");
}

bool ModuleContour::initialize(DataSource* data, vtkSMViewProxy* vtkView)
{
  if (!this->Superclass::initialize(data, vtkView)) {
    return false;
  }

  vtkSMSourceProxy* producer = data->producer();

  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  vtkSMSessionProxyManager* pxm = producer->GetSessionProxyManager();

  vtkSmartPointer<vtkSMProxy> contourProxy;
  contourProxy.TakeReference(pxm->NewProxy("filters", "FlyingEdges"));

  this->ContourFilter = vtkSMSourceProxy::SafeDownCast(contourProxy);
  Q_ASSERT(this->ContourFilter);
  controller->PreInitializeProxy(this->ContourFilter);
  vtkSMPropertyHelper(this->ContourFilter, "Input").Set(producer);
  vtkSMPropertyHelper(this->ContourFilter, "ComputeScalars", /*quiet*/ true)
    .Set(1);

  controller->PostInitializeProxy(this->ContourFilter);
  controller->RegisterPipelineProxy(this->ContourFilter);

  // Set up a data resampler to add LabelMap values on the contour
  vtkSmartPointer<vtkSMProxy> probeProxy;
  probeProxy.TakeReference(pxm->NewProxy("filters", "ResampleWithDataset"));

  this->ResampleFilter = vtkSMSourceProxy::SafeDownCast(probeProxy);
  Q_ASSERT(this->ResampleFilter);
  controller->PreInitializeProxy(this->ResampleFilter);
  vtkSMPropertyHelper(this->ResampleFilter, "Input").Set(data->producer());
  vtkSMPropertyHelper(this->ResampleFilter, "Source").Set(this->ContourFilter);
  controller->PostInitializeProxy(this->ResampleFilter);
  controller->RegisterPipelineProxy(this->ResampleFilter);

  // Create the representation for it. Show the unresampled contour filter to
  // start.
  this->ContourRepresentation =
    controller->Show(this->ContourFilter, 0, vtkView);
  Q_ASSERT(this->ContourRepresentation);
  vtkSMPropertyHelper(this->ContourRepresentation, "Representation")
    .Set("Surface");
  vtkSMPropertyHelper(this->ContourRepresentation, "Position")
    .Set(data->displayPosition(), 3);

  vtkSMPropertyHelper colorArrayHelper(this->ContourRepresentation,
                                       "ColorArrayName");
  this->Internals->NonLabelMapArrayName =
    std::string(colorArrayHelper.GetInputArrayNameToProcess());

  vtkSMPropertyHelper colorHelper(this->ContourRepresentation, "DiffuseColor");
  double white[3] = { 1.0, 1.0, 1.0 };
  colorHelper.Set(white, 3);
  // use proper color map.
  this->updateColorMap();

  this->ContourRepresentation->UpdateVTKObjects();

  return true;
}

void ModuleContour::updateColorMap()
{
  Q_ASSERT(this->ContourRepresentation);
  vtkSMPropertyHelper(this->ContourRepresentation, "LookupTable")
    .Set(this->colorMap());
  vtkSMPropertyHelper colorArrayHelper(this->ContourRepresentation,
                                       "ColorArrayName");

  if (this->colorByLabelMap()) {
    this->Internals->NonLabelMapArrayName =
      std::string(colorArrayHelper.GetInputArrayNameToProcess());
    colorArrayHelper.SetInputArrayToProcess(
      vtkDataObject::FIELD_ASSOCIATION_POINTS, "LabelMap");

    vtkSMPropertyHelper(this->ContourRepresentation, "Input")
      .Set(this->ResampleFilter);
  } else {
    if (this->Internals->UseSolidColor) {
      colorArrayHelper.SetInputArrayToProcess(
        vtkDataObject::FIELD_ASSOCIATION_POINTS, "");
    } else {
      colorArrayHelper.SetInputArrayToProcess(
        vtkDataObject::FIELD_ASSOCIATION_POINTS,
        this->Internals->NonLabelMapArrayName.c_str());
    }
    vtkSMPropertyHelper(this->ContourRepresentation, "Input")
      .Set(this->ContourFilter);
  }

  vtkSMPropertyHelper(this->ContourRepresentation, "Visibility")
    .Set(this->visibility() ? 1 : 0);
  this->ContourRepresentation->UpdateVTKObjects();
}

bool ModuleContour::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(this->ResampleFilter);
  controller->UnRegisterProxy(this->ContourRepresentation);
  controller->UnRegisterProxy(this->ContourFilter);
  this->ResampleFilter = nullptr;
  this->ContourFilter = nullptr;
  this->ContourRepresentation = nullptr;
  return true;
}

bool ModuleContour::setVisibility(bool val)
{
  Q_ASSERT(this->ContourRepresentation);
  vtkSMPropertyHelper(this->ContourRepresentation, "Visibility")
    .Set(val ? 1 : 0);
  this->ContourRepresentation->UpdateVTKObjects();

  return true;
}

bool ModuleContour::visibility() const
{
  Q_ASSERT(this->ContourRepresentation);
  return vtkSMPropertyHelper(this->ContourRepresentation, "Visibility")
           .GetAsInt() != 0;
}

void ModuleContour::setIsoValues(const QList<double>& values)
{
  std::vector<double> vectorValues(values.size());
  std::copy(values.begin(), values.end(), vectorValues.begin());
  vectorValues.push_back(0); // to avoid having to check for 0 size on Windows.

  vtkSMPropertyHelper(this->ContourFilter, "ContourValues")
    .Set(&vectorValues[0], values.size());
  this->ContourFilter->UpdateVTKObjects();
}

void ModuleContour::addToPanel(QWidget* panel)
{
  Q_ASSERT(this->ContourFilter);
  Q_ASSERT(this->ContourRepresentation);

  if (panel->layout()) {
    delete panel->layout();
  }

  QFormLayout* layout = new QFormLayout;

  // Solid color
  QHBoxLayout* colorLayout = new QHBoxLayout;
  colorLayout->addStretch();

  QCheckBox* useSolidColor = new QCheckBox;
  useSolidColor->setChecked(this->Internals->UseSolidColor);
  QObject::connect(useSolidColor, &QCheckBox::stateChanged, this,
                   &ModuleContour::setUseSolidColor);
  colorLayout->addWidget(useSolidColor);

  QLabel* colorLabel = new QLabel("Select Color");
  colorLayout->addWidget(colorLabel);

  pqColorChooserButton* colorSelector = new pqColorChooserButton(panel);
  colorLayout->addWidget(colorSelector);
  layout->addRow("", colorLayout);

  colorSelector->setShowAlphaChannel(false);
  DoubleSliderWidget* valueSlider = new DoubleSliderWidget(true);
  valueSlider->setLineEditWidth(50);
  layout->addRow("Value", valueSlider);

  QComboBox* representations = new QComboBox;
  representations->addItem("Surface");
  representations->addItem("Wireframe");
  representations->addItem("Points");
  layout->addRow("", representations);
  // TODO connect to update function

  DoubleSliderWidget* opacitySlider = new DoubleSliderWidget(true);
  opacitySlider->setLineEditWidth(50);
  layout->addRow("Opacity", opacitySlider);

  DoubleSliderWidget* specularSlider = new DoubleSliderWidget(true);
  specularSlider->setLineEditWidth(50);
  layout->addRow("Specular", specularSlider);

  pqSignalAdaptorComboBox* adaptor =
    new pqSignalAdaptorComboBox(representations);
  // layout->addStretch();

  panel->setLayout(layout);

  this->Internals->Links.addPropertyLink(
    valueSlider, "value", SIGNAL(valueEdited(double)), this->ContourFilter,
    this->ContourFilter->GetProperty("ContourValues"), 0);
  new pqWidgetRangeDomain(valueSlider, "minimum", "maximum",
                          this->ContourFilter->GetProperty("ContourValues"), 0);

  this->Internals->Links.addPropertyLink(
    adaptor, "currentText", SIGNAL(currentTextChanged(QString)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("Representation"));

  this->Internals->Links.addPropertyLink(
    opacitySlider, "value", SIGNAL(valueEdited(double)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("Opacity"), 0);
  this->Internals->Links.addPropertyLink(
    specularSlider, "value", SIGNAL(valueEdited(double)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("Specular"), 0);

  // Surface uses DiffuseColor and Wireframe uses AmbientColor so we have to set
  // both
  this->Internals->Links.addPropertyLink(
    colorSelector, "chosenColorRgbF", SIGNAL(chosenColorChanged(const QColor&)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("DiffuseColor"));
  this->Internals->Links.addPropertyLink(
    colorSelector, "chosenColorRgbF", SIGNAL(chosenColorChanged(const QColor&)),
    this->ContourRepresentation,
    this->ContourRepresentation->GetProperty("AmbientColor"));

  this->connect(valueSlider, &DoubleSliderWidget::valueEdited, this,
                &ModuleContour::dataUpdated);
  this->connect(representations, &QComboBox::currentTextChanged, this,
                &ModuleContour::dataUpdated);
  this->connect(opacitySlider, &DoubleSliderWidget::valueEdited, this,
                &ModuleContour::dataUpdated);
  this->connect(specularSlider, &DoubleSliderWidget::valueEdited, this,
                &ModuleContour::dataUpdated);
  this->connect(colorSelector, &pqColorChooserButton::chosenColorChanged, this,
                &ModuleContour::dataUpdated);
}

void ModuleContour::dataUpdated()
{
  this->Internals->Links.accept();
  emit this->renderNeeded();
}

bool ModuleContour::serialize(pugi::xml_node& ns) const
{
  ns.append_attribute("solid_color").set_value(this->Internals->UseSolidColor);
  // save stuff that the user can change.
  pugi::xml_node node = ns.append_child("ContourFilter");
  QStringList contourProperties;
  contourProperties << "ContourValues";
  if (tomviz::serialize(this->ContourFilter, node, contourProperties) ==
      false) {
    qWarning("Failed to serialize ContourFilter.");
    ns.remove_child(node);
    return false;
  }

  QStringList contourRepresentationProperties;
  contourRepresentationProperties << "Representation"
                                  << "Opacity"
                                  << "Specular"
                                  << "Visibility"
                                  << "DiffuseColor";

  node = ns.append_child("ContourRepresentation");
  if (tomviz::serialize(this->ContourRepresentation, node,
                        contourRepresentationProperties) == false) {
    qWarning("Failed to serialize ContourRepresentation.");
    ns.remove_child(node);
    return false;
  }

  return this->Superclass::serialize(ns);
}

bool ModuleContour::deserialize(const pugi::xml_node& ns)
{
  if (ns.attribute("solid_color")) {
    this->Internals->UseSolidColor = ns.attribute("solid_color").as_bool();
  }
  return tomviz::deserialize(this->ContourFilter, ns.child("ContourFilter")) &&
         tomviz::deserialize(this->ContourRepresentation,
                             ns.child("ContourRepresentation")) &&
         this->Superclass::deserialize(ns);
}

void ModuleContour::dataSourceMoved(double newX, double newY, double newZ)
{
  double pos[3] = { newX, newY, newZ };
  vtkSMPropertyHelper(this->ContourRepresentation, "Position").Set(pos, 3);
  this->ContourRepresentation->MarkDirty(this->ContourRepresentation);
  this->ContourRepresentation->UpdateVTKObjects();
}

bool ModuleContour::isProxyPartOfModule(vtkSMProxy* proxy)
{
  return (proxy == this->ContourFilter.Get()) ||
         (proxy == this->ContourRepresentation.Get()) ||
         (proxy == this->ResampleFilter.Get());
}

std::string ModuleContour::getStringForProxy(vtkSMProxy* proxy)
{
  if (proxy == this->ContourFilter.Get()) {
    return "Contour";
  } else if (proxy == this->ContourRepresentation.Get()) {
    return "Representation";
  } else if (proxy == this->ResampleFilter.Get()) {
    return "Resample";
  } else {
    qWarning("Gave bad proxy to module in save animation state");
    return "";
  }
}

vtkSMProxy* ModuleContour::getProxyForString(const std::string& str)
{
  if (str == "Resample") {
    return this->ResampleFilter.Get();
  } else if (str == "Representation") {
    return this->ContourRepresentation.Get();
  } else if (str == "Contour") {
    return this->ContourFilter.Get();
  } else {
    return nullptr;
  }
}

void ModuleContour::setUseSolidColor(int useSolidColor)
{
  this->Internals->UseSolidColor = (useSolidColor != 0);
  this->updateColorMap();
  emit this->renderNeeded();
}

} // end of namespace tomviz
<|endoftext|>


<commit_before>/*  Copyright (C) 2006 Imperial College London and others.

    Please see the AUTHORS file in the main source directory for a full list
    of copyright holders.

    Prof. C Pain
    Applied Modelling and Computation Group
    Department of Earth Science and Engineering
    Imperial College London

    amcgsoftware@imperial.ac.uk

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation,
    version 2.1 of the License.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
    USA
*/

#include <cstring>
#include <iostream>
#include <sstream>
#include <stdlib.h>

#include "confdefs.h"

#include "c++debug.h"

#ifdef HAVE_MPI
#include <mpi.h>
#endif

using namespace std;

extern "C"{
#define checkmesh F77_FUNC(checkmesh, CHECKMESH)
  void checkmesh(const char* basename, const int* basename_len);
}

void Usage(){
  cout << "Usage: checkmesh TRIANGLE_BASENAME\n"
       << "\n"
       << "Checks the validity of the supplied triangle mesh" << endl;
}

int main(int argc, char** argv){
#ifdef HAVE_MPI
  MPI::Init(argc, argv);
  // Undo some MPI init shenanigans
  chdir(getenv("PWD"));
#endif

  if(argc < 2){
    Usage();
    return -1;
  }

  // Logging
  int nprocs = 1;
#ifdef HAVE_MPI
  if(MPI::Is_initialized()){
    nprocs = MPI::COMM_WORLD.Get_size();
  }
#endif
if(nprocs > 1){
  int rank = 0;
#ifdef HAVE_MPI
  if(MPI::Is_initialized()){
    rank = MPI::COMM_WORLD.Get_rank();
  }
#endif
  ostringstream buffer;
  buffer << "checkmesh.log-" << rank;
  if(freopen(buffer.str().c_str(), "w", stdout) == NULL){
    cerr << "Failed to redirect stdout" << endl;
    exit(-1);
  }
  buffer.str("");
  buffer << "checkmesh.err-" << rank;
  if(freopen(buffer.str().c_str(), "w", stderr) == NULL){
    cerr << "Failed to redirect stderr" << endl;
    exit(-1);
  }
  buffer.str("");
  }

  // Verbosity
  int verbosity = 2;
  set_global_debug_level_fc(&verbosity);

  int basename_len = strlen(argv[1]);
  checkmesh(argv[1], &basename_len);

#ifdef HAVE_MPI
  MPI::Finalize();
#endif
  return 0;
}
<commit_msg>updating to trunk<commit_after>/*  Copyright (C) 2006 Imperial College London and others.

    Please see the AUTHORS file in the main source directory for a full list
    of copyright holders.

    Prof. C Pain
    Applied Modelling and Computation Group
    Department of Earth Science and Engineering
    Imperial College London

    amcgsoftware@imperial.ac.uk

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation,
    version 2.1 of the License.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
    USA
*/

#include <cstring>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <stdio.h>

#include "confdefs.h"

#include "c++debug.h"

#ifdef HAVE_MPI
#include <mpi.h>
#endif

using namespace std;

extern "C"{
#define checkmesh F77_FUNC(checkmesh, CHECKMESH)
  void checkmesh(const char* basename, const int* basename_len);
}

void Usage(){
  cout << "Usage: checkmesh TRIANGLE_BASENAME\n"
       << "\n"
       << "Checks the validity of the supplied triangle mesh" << endl;
}

int main(int argc, char** argv){
#ifdef HAVE_MPI
  MPI::Init(argc, argv);
  // Undo some MPI init shenanigans
  chdir(getenv("PWD"));
#endif

  if(argc < 2){
    Usage();
    return -1;
  }

  // Logging
  int nprocs = 1;
#ifdef HAVE_MPI
  if(MPI::Is_initialized()){
    nprocs = MPI::COMM_WORLD.Get_size();
  }
#endif
if(nprocs > 1){
  int rank = 0;
#ifdef HAVE_MPI
  if(MPI::Is_initialized()){
    rank = MPI::COMM_WORLD.Get_rank();
  }
#endif
  ostringstream buffer;
  buffer << "checkmesh.log-" << rank;
  if(freopen(buffer.str().c_str(), "w", stdout) == NULL){
    cerr << "Failed to redirect stdout" << endl;
    exit(-1);
  }
  buffer.str("");
  buffer << "checkmesh.err-" << rank;
  if(freopen(buffer.str().c_str(), "w", stderr) == NULL){
    cerr << "Failed to redirect stderr" << endl;
    exit(-1);
  }
  buffer.str("");
  }

  // Verbosity
  int verbosity = 2;
  set_global_debug_level_fc(&verbosity);

  int basename_len = strlen(argv[1]);
  checkmesh(argv[1], &basename_len);

#ifdef HAVE_MPI
  MPI::Finalize();
#endif
  return 0;
}
<|endoftext|>