<commit_before>/*
    utilities.cpp

    KNode, the KDE newsreader
    Copyright (c) 1999-2001 the KNode authors.
    See file AUTHORS for details

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, US
*/

#include <qframe.h>
#include <qlayout.h>

#include <kconfig.h>
#include <klocale.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kdialogbase.h>
#include <kdebug.h>
#include <kio/netaccess.h>
#include <ktempfile.h>
#include <kfiledialog.h>

#include "knlistbox.h"
#include "knglobals.h"
#include "utilities.h"

//================================================================================

KNFile::KNFile(const QString& fname)
 : QFile(fname), filePos(0), readBytes(0)
{
  buffer.resize(512);
  dataPtr=buffer.data();
  dataPtr[0]='\0';
}

KNFile::~KNFile()
{
}

const QCString& KNFile::readLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
    while ((dataPtr[readBytes-1]!='\n')&&(static_cast<uint>(readBytes+2)==buffer.size())) {  // don't get tricked by files without newline
      at(filePos);
      if (!increaseBuffer() ||
         (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        readBytes=1;
        break;
      }
    }
  } else
    readBytes=1;

  dataPtr[readBytes-1] = '\0';
  return buffer;
}

const QCString& KNFile::readLineWnewLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
    while ((dataPtr[readBytes-1]!='\n')&&(static_cast<uint>(readBytes+2)==buffer.size())) {  // don't get tricked by files without newline
      at(filePos);
      if (!increaseBuffer() ||
         (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        dataPtr[0] = '\0';
        break;
      }
    }
  }
  else dataPtr[0] = '\0';

  return buffer;
}

int KNFile::findString(const char *s)
{
  QCString searchBuffer;
  searchBuffer.resize(2048);
  char *buffPtr = searchBuffer.data(), *pos;
  int readBytes, currentFilePos;

  while (!atEnd()) {
    currentFilePos = at();
    readBytes = readBlock(buffPtr, 2047);
    if (readBytes == -1)
      return -1;
    else
      buffPtr[readBytes] = 0;       // terminate string

    pos = strstr(buffPtr,s);
    if (pos == 0) {
      if (!atEnd())
        at(at()-strlen(s));
      else
        return -1;
    } else {
      return currentFilePos + (pos-buffPtr);
    }
  }

  return -1;
}

bool KNFile::increaseBuffer()
{
  if(buffer.resize(2*buffer.size())) {;
    dataPtr=buffer.data();
    dataPtr[0]='\0';
    kdDebug(5003) << "KNFile::increaseBuffer() : buffer doubled" << endl;
    return true;
  }
  else return false;
}

//===============================================================================

QString KNSaveHelper::lastPath;

KNSaveHelper::KNSaveHelper(QString saveName, QWidget *parent)
  : p_arent(parent), s_aveName(saveName), file(0), tmpFile(0)
{
}

KNSaveHelper::~KNSaveHelper()
{
  if (file) {       // local filesystem, just close the file
    delete file;
  } else
    if (tmpFile) {      // network location, initiate transaction
      tmpFile->close();
      if (KIO::NetAccess::upload(tmpFile->name(),url) == false)
        KNHelper::displayRemoteFileError();
      tmpFile->unlink();   // delete temp file
      delete tmpFile;
    }
}

QFile* KNSaveHelper::getFile(QString dialogTitle)
{
  if (lastPath.isEmpty())
    lastPath = "file:/";

  url = KFileDialog::getSaveURL(lastPath+s_aveName,QString::null,p_arent,dialogTitle);

  if (url.isEmpty())
    return 0;

  lastPath = url.url(-1);
  lastPath.truncate(lastPath.length()-url.fileName().length());

  if (url.isLocalFile()) {
    if (QFileInfo(url.path()).exists() &&
        (KMessageBox::warningContinueCancel(knGlobals.topWidget,
                                            i18n("A file named %1 already exists.\nDo you want to replace it?").arg(url.path()),
                                            dialogTitle, i18n("&Replace")) != KMessageBox::Continue)) {
      return 0;
    }

    file = new QFile(url.path());
    if(!file->open(IO_WriteOnly)) {
      KNHelper::displayExternalFileError();
      delete file;
      file = 0;
    }
    return file;
  } else {
    tmpFile = new KTempFile();
    if (tmpFile->status()!=0) {
      KNHelper::displayTempFileError();
      delete tmpFile;
      tmpFile = 0;
      return 0;
    }
    return tmpFile->file();
  }
}

//===============================================================================

QString KNLoadHelper::l_astPath;

KNLoadHelper::KNLoadHelper(QWidget *parent)
  : p_arent(parent), f_ile(0)
{
}

KNLoadHelper::~KNLoadHelper()
{
  delete f_ile;
  if (!t_empName.isEmpty())
    KIO::NetAccess::removeTempFile(t_empName);
}

KNFile* KNLoadHelper::getFile(QString dialogTitle)
{
  if (f_ile)
    return f_ile;

  KURL url = KFileDialog::getOpenURL(l_astPath,QString::null,p_arent,dialogTitle);

  if (url.isEmpty())
    return 0;

  l_astPath = url.url(-1);
  l_astPath.truncate(l_astPath.length()-url.fileName().length());

  return setURL(url);
}

KNFile* KNLoadHelper::setURL(KURL url)
{
  if (f_ile)
    return f_ile;

  u_rl = url;

  if (u_rl.isEmpty())
    return 0;

  QString fileName;
  if (!u_rl.isLocalFile()) {
    if (KIO::NetAccess::download(u_rl, t_empName))
      fileName = t_empName;
  } else
    fileName = u_rl.path();

  if (fileName.isEmpty())
    return 0;

  f_ile = new KNFile(fileName);
  if(!f_ile->open(IO_ReadOnly)) {
    KNHelper::displayExternalFileError();
    delete f_ile;
    f_ile = 0;
  }
  return f_ile;
}

//===============================================================================

// **** keyboard selection dialog *********************************************
int KNHelper::selectDialog(QWidget *parent, const QString &caption, const QStringList &options, int initialValue)
{
  KDialogBase *dlg=new KDialogBase(KDialogBase::Plain, caption, KDialogBase::Ok|KDialogBase::Cancel,
                                   KDialogBase::Ok, parent);
  QFrame *page = dlg->plainPage();
  QHBoxLayout *pageL = new QHBoxLayout(page,8,5);

  KNDialogListBox *list = new KNDialogListBox(true, page);
  pageL->addWidget(list);

  QString s;
  for ( QStringList::ConstIterator it = options.begin(); it != options.end(); ++it ) {
    s = (*it);
    s.replace(QRegExp("&"),"");   // remove accelerators
    list->insertItem(s);
  }

  list->setCurrentItem(initialValue);
  list->setFocus();
  restoreWindowSize("selectBox", dlg, QSize(247,174));

  int ret;
  if (dlg->exec())
    ret = list->currentItem();
  else
    ret = -1;

  saveWindowSize("selectBox", dlg->size());
  delete dlg;
  return ret;
}

// **** window geometry managing *********************************************

void KNHelper::saveWindowSize(const QString &name, const QSize &s)
{
  KConfig *c=KGlobal::config();
  c->setGroup("WINDOW_SIZES");
  c->writeEntry(name, s);
}

void KNHelper::restoreWindowSize(const QString &name, QWidget *d, const QSize &defaultSize)
{
  KConfig *c=KGlobal::config();
  c->setGroup("WINDOW_SIZES");

  QSize s=c->readSizeEntry(name,&defaultSize);

  if(s.isValid()) d->resize(s);
}

// **** scramble password strings **********************************************

const QString KNHelper::encryptStr(const QString& aStr)
{
  uint i,val,len = aStr.length();
  QCString result;

  for (i=0; i<len; i++)
  {
    val = aStr[i] - ' ';
    val = (255-' ') - val;
    result += (char)(val + ' ');
  }

  return result;
}

const QString KNHelper::decryptStr(const QString& aStr)
{
  return encryptStr(aStr);
}

// **** rot13 *******************************************************************

QString KNHelper::rot13(const QString &s)
{
  QString r(s);

  for (int i=0; (uint)i<r.length(); i++) {
    if ( r[i] >= QChar('A') && r[i] <= QChar('M') ||
         r[i] >= QChar('a') && r[i] <= QChar('m') )
         r[i] = (char)((int)QChar(r[i]) + 13);
    else
      if  ( r[i] >= QChar('N') && r[i] <= QChar('Z') ||
            r[i] >= QChar('n') && r[i] <= QChar('z') )
        r[i] = (char)((int)QChar(r[i]) - 13);
  }

  return r;
}

// **** us-ascii check **********************************************************

bool KNHelper::isUsAscii(const QString &s)
{
  for (uint i=0; i<s.length(); i++)
    if (s.at(i).latin1()<=0)    // c==0: non-latin1, c<0: non-us-ascii
      return false;

  return true;
}

// **** text rewraping *********************************************************

int findBreakPos(const QString &text, int start)
{
  int i;
  for(i=start;i>=0;i--)
    if(text[i].isSpace())
      break;
  if(i>0)
    return i;
  for(i=start;i<(int)text.length();i++)   // ok, the line is to long
    if(text[i].isSpace())
      break;
  return i;
}

void appendTextWPrefix(QString &result, const QString &text, int wrapAt, const QString &prefix)
{
  QString txt=text;
  int breakPos;

  while(!txt.isEmpty()) {

    if((int)(prefix.length()+txt.length()) > wrapAt) {
      breakPos=findBreakPos(txt,wrapAt-prefix.length());
      result+=(prefix+txt.left(breakPos)+"\n");
      txt.remove(0,breakPos+1);
    } else {
      result+=(prefix+txt+"\n");
      txt=QString::null;
    }
  }
}

QString KNHelper::rewrapStringList(QStringList text, int wrapAt, QChar quoteChar, bool stopAtSig, bool alwaysSpace)
{
  QString quoted, lastPrefix, thisPrefix, leftover, thisLine;
  int breakPos;

  for(QStringList::Iterator line=text.begin(); line!=text.end(); ++line) {

    if(stopAtSig && (*line)=="-- ")
      break;

    thisLine=(*line);
    if (!alwaysSpace && (thisLine[0]==quoteChar))
      thisLine.prepend(quoteChar);  // second quote level without space
    else
      thisLine.prepend(quoteChar+' ');

    thisPrefix=QString::null;
    QChar c;
    for(int idx=0; idx<(int)(thisLine.length()); idx++) {
      c=thisLine.at(idx);
      if( (c==' ') ||
          (c==quoteChar) || (c=='>') ||(c=='|') || (c==':') || (c=='#') || (c=='[') || (c=='{'))
        thisPrefix.append(c);
      else
        break;
    }

    thisLine.remove(0,thisPrefix.length());
    thisLine = thisLine.stripWhiteSpace();

    if(!leftover.isEmpty()) {   // don't break paragraphs, tables and quote levels
      if(thisLine.isEmpty() || (thisPrefix!=lastPrefix) || thisLine.contains("  ") || thisLine.contains('\t'))
        appendTextWPrefix(quoted, leftover, wrapAt, lastPrefix);
      else
        thisLine.prepend(leftover+" ");
      leftover=QString::null;
    }

    if((int)(thisPrefix.length()+thisLine.length()) > wrapAt) {
      breakPos=findBreakPos(thisLine,wrapAt-thisPrefix.length());
      if(breakPos < (int)(thisLine.length())) {
        leftover=thisLine.right(thisLine.length()-breakPos-1);
        thisLine.truncate(breakPos);
      }
    }

    quoted+=thisPrefix+thisLine+"\n";
    lastPrefix=thisPrefix;
  }

  if (!leftover.isEmpty())
    appendTextWPrefix(quoted, leftover, wrapAt, lastPrefix);

  return quoted;
}

// **** misc. message-boxes **********************************************************

void KNHelper::displayInternalFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to load/save configuration!\nWrong permissions on home directory?\nYou should close KNode now to avoid data loss!"));
}

void KNHelper::displayExternalFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to load/save file!"));
}

void KNHelper::displayRemoteFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to save remote file!"));
}

void KNHelper::displayTempFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to create temporary file!"));
}
<commit_msg>fixed a broken hack in KNSaveHelper<commit_after>/*
    utilities.cpp

    KNode, the KDE newsreader
    Copyright (c) 1999-2001 the KNode authors.
    See file AUTHORS for details

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, US
*/

#include <qframe.h>
#include <qlayout.h>

#include <kconfig.h>
#include <klocale.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kdialogbase.h>
#include <kdebug.h>
#include <kio/netaccess.h>
#include <ktempfile.h>
#include <kfiledialog.h>

#include "knlistbox.h"
#include "knglobals.h"
#include "utilities.h"

//================================================================================

KNFile::KNFile(const QString& fname)
 : QFile(fname), filePos(0), readBytes(0)
{
  buffer.resize(512);
  dataPtr=buffer.data();
  dataPtr[0]='\0';
}

KNFile::~KNFile()
{
}

const QCString& KNFile::readLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
    while ((dataPtr[readBytes-1]!='\n')&&(static_cast<uint>(readBytes+2)==buffer.size())) {  // don't get tricked by files without newline
      at(filePos);
      if (!increaseBuffer() ||
         (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        readBytes=1;
        break;
      }
    }
  } else
    readBytes=1;

  dataPtr[readBytes-1] = '\0';
  return buffer;
}

const QCString& KNFile::readLineWnewLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
    while ((dataPtr[readBytes-1]!='\n')&&(static_cast<uint>(readBytes+2)==buffer.size())) {  // don't get tricked by files without newline
      at(filePos);
      if (!increaseBuffer() ||
         (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        dataPtr[0] = '\0';
        break;
      }
    }
  }
  else dataPtr[0] = '\0';

  return buffer;
}

int KNFile::findString(const char *s)
{
  QCString searchBuffer;
  searchBuffer.resize(2048);
  char *buffPtr = searchBuffer.data(), *pos;
  int readBytes, currentFilePos;

  while (!atEnd()) {
    currentFilePos = at();
    readBytes = readBlock(buffPtr, 2047);
    if (readBytes == -1)
      return -1;
    else
      buffPtr[readBytes] = 0;       // terminate string

    pos = strstr(buffPtr,s);
    if (pos == 0) {
      if (!atEnd())
        at(at()-strlen(s));
      else
        return -1;
    } else {
      return currentFilePos + (pos-buffPtr);
    }
  }

  return -1;
}

bool KNFile::increaseBuffer()
{
  if(buffer.resize(2*buffer.size())) {;
    dataPtr=buffer.data();
    dataPtr[0]='\0';
    kdDebug(5003) << "KNFile::increaseBuffer() : buffer doubled" << endl;
    return true;
  }
  else return false;
}

//===============================================================================

QString KNSaveHelper::lastPath;

KNSaveHelper::KNSaveHelper(QString saveName, QWidget *parent)
  : p_arent(parent), s_aveName(saveName), file(0), tmpFile(0)
{
}

KNSaveHelper::~KNSaveHelper()
{
  if (file) {       // local filesystem, just close the file
    delete file;
  } else
    if (tmpFile) {      // network location, initiate transaction
      tmpFile->close();
      if (KIO::NetAccess::upload(tmpFile->name(),url) == false)
        KNHelper::displayRemoteFileError();
      tmpFile->unlink();   // delete temp file
      delete tmpFile;
    }
}

QFile* KNSaveHelper::getFile(QString dialogTitle)
{
  if (lastPath.isEmpty())
    lastPath = "file:/";

  url = KFileDialog::getSaveURL(lastPath+s_aveName,QString::null,p_arent,dialogTitle);

  if (url.isEmpty())
    return 0;

  lastPath = url.upURL().url();

  if (url.isLocalFile()) {
    if (QFileInfo(url.path()).exists() &&
        (KMessageBox::warningContinueCancel(knGlobals.topWidget,
                                            i18n("A file named %1 already exists.\nDo you want to replace it?").arg(url.path()),
                                            dialogTitle, i18n("&Replace")) != KMessageBox::Continue)) {
      return 0;
    }

    file = new QFile(url.path());
    if(!file->open(IO_WriteOnly)) {
      KNHelper::displayExternalFileError();
      delete file;
      file = 0;
    }
    return file;
  } else {
    tmpFile = new KTempFile();
    if (tmpFile->status()!=0) {
      KNHelper::displayTempFileError();
      delete tmpFile;
      tmpFile = 0;
      return 0;
    }
    return tmpFile->file();
  }
}

//===============================================================================

QString KNLoadHelper::l_astPath;

KNLoadHelper::KNLoadHelper(QWidget *parent)
  : p_arent(parent), f_ile(0)
{
}

KNLoadHelper::~KNLoadHelper()
{
  delete f_ile;
  if (!t_empName.isEmpty())
    KIO::NetAccess::removeTempFile(t_empName);
}

KNFile* KNLoadHelper::getFile(QString dialogTitle)
{
  if (f_ile)
    return f_ile;

  KURL url = KFileDialog::getOpenURL(l_astPath,QString::null,p_arent,dialogTitle);

  if (url.isEmpty())
    return 0;

  l_astPath = url.url(-1);
  l_astPath.truncate(l_astPath.length()-url.fileName().length());

  return setURL(url);
}

KNFile* KNLoadHelper::setURL(KURL url)
{
  if (f_ile)
    return f_ile;

  u_rl = url;

  if (u_rl.isEmpty())
    return 0;

  QString fileName;
  if (!u_rl.isLocalFile()) {
    if (KIO::NetAccess::download(u_rl, t_empName))
      fileName = t_empName;
  } else
    fileName = u_rl.path();

  if (fileName.isEmpty())
    return 0;

  f_ile = new KNFile(fileName);
  if(!f_ile->open(IO_ReadOnly)) {
    KNHelper::displayExternalFileError();
    delete f_ile;
    f_ile = 0;
  }
  return f_ile;
}

//===============================================================================

// **** keyboard selection dialog *********************************************
int KNHelper::selectDialog(QWidget *parent, const QString &caption, const QStringList &options, int initialValue)
{
  KDialogBase *dlg=new KDialogBase(KDialogBase::Plain, caption, KDialogBase::Ok|KDialogBase::Cancel,
                                   KDialogBase::Ok, parent);
  QFrame *page = dlg->plainPage();
  QHBoxLayout *pageL = new QHBoxLayout(page,8,5);

  KNDialogListBox *list = new KNDialogListBox(true, page);
  pageL->addWidget(list);

  QString s;
  for ( QStringList::ConstIterator it = options.begin(); it != options.end(); ++it ) {
    s = (*it);
    s.replace(QRegExp("&"),"");   // remove accelerators
    list->insertItem(s);
  }

  list->setCurrentItem(initialValue);
  list->setFocus();
  restoreWindowSize("selectBox", dlg, QSize(247,174));

  int ret;
  if (dlg->exec())
    ret = list->currentItem();
  else
    ret = -1;

  saveWindowSize("selectBox", dlg->size());
  delete dlg;
  return ret;
}

// **** window geometry managing *********************************************

void KNHelper::saveWindowSize(const QString &name, const QSize &s)
{
  KConfig *c=KGlobal::config();
  c->setGroup("WINDOW_SIZES");
  c->writeEntry(name, s);
}

void KNHelper::restoreWindowSize(const QString &name, QWidget *d, const QSize &defaultSize)
{
  KConfig *c=KGlobal::config();
  c->setGroup("WINDOW_SIZES");

  QSize s=c->readSizeEntry(name,&defaultSize);

  if(s.isValid()) d->resize(s);
}

// **** scramble password strings **********************************************

const QString KNHelper::encryptStr(const QString& aStr)
{
  uint i,val,len = aStr.length();
  QCString result;

  for (i=0; i<len; i++)
  {
    val = aStr[i] - ' ';
    val = (255-' ') - val;
    result += (char)(val + ' ');
  }

  return result;
}

const QString KNHelper::decryptStr(const QString& aStr)
{
  return encryptStr(aStr);
}

// **** rot13 *******************************************************************

QString KNHelper::rot13(const QString &s)
{
  QString r(s);

  for (int i=0; (uint)i<r.length(); i++) {
    if ( r[i] >= QChar('A') && r[i] <= QChar('M') ||
         r[i] >= QChar('a') && r[i] <= QChar('m') )
         r[i] = (char)((int)QChar(r[i]) + 13);
    else
      if  ( r[i] >= QChar('N') && r[i] <= QChar('Z') ||
            r[i] >= QChar('n') && r[i] <= QChar('z') )
        r[i] = (char)((int)QChar(r[i]) - 13);
  }

  return r;
}

// **** us-ascii check **********************************************************

bool KNHelper::isUsAscii(const QString &s)
{
  for (uint i=0; i<s.length(); i++)
    if (s.at(i).latin1()<=0)    // c==0: non-latin1, c<0: non-us-ascii
      return false;

  return true;
}

// **** text rewraping *********************************************************

int findBreakPos(const QString &text, int start)
{
  int i;
  for(i=start;i>=0;i--)
    if(text[i].isSpace())
      break;
  if(i>0)
    return i;
  for(i=start;i<(int)text.length();i++)   // ok, the line is to long
    if(text[i].isSpace())
      break;
  return i;
}

void appendTextWPrefix(QString &result, const QString &text, int wrapAt, const QString &prefix)
{
  QString txt=text;
  int breakPos;

  while(!txt.isEmpty()) {

    if((int)(prefix.length()+txt.length()) > wrapAt) {
      breakPos=findBreakPos(txt,wrapAt-prefix.length());
      result+=(prefix+txt.left(breakPos)+"\n");
      txt.remove(0,breakPos+1);
    } else {
      result+=(prefix+txt+"\n");
      txt=QString::null;
    }
  }
}

QString KNHelper::rewrapStringList(QStringList text, int wrapAt, QChar quoteChar, bool stopAtSig, bool alwaysSpace)
{
  QString quoted, lastPrefix, thisPrefix, leftover, thisLine;
  int breakPos;

  for(QStringList::Iterator line=text.begin(); line!=text.end(); ++line) {

    if(stopAtSig && (*line)=="-- ")
      break;

    thisLine=(*line);
    if (!alwaysSpace && (thisLine[0]==quoteChar))
      thisLine.prepend(quoteChar);  // second quote level without space
    else
      thisLine.prepend(quoteChar+' ');

    thisPrefix=QString::null;
    QChar c;
    for(int idx=0; idx<(int)(thisLine.length()); idx++) {
      c=thisLine.at(idx);
      if( (c==' ') ||
          (c==quoteChar) || (c=='>') ||(c=='|') || (c==':') || (c=='#') || (c=='[') || (c=='{'))
        thisPrefix.append(c);
      else
        break;
    }

    thisLine.remove(0,thisPrefix.length());
    thisLine = thisLine.stripWhiteSpace();

    if(!leftover.isEmpty()) {   // don't break paragraphs, tables and quote levels
      if(thisLine.isEmpty() || (thisPrefix!=lastPrefix) || thisLine.contains("  ") || thisLine.contains('\t'))
        appendTextWPrefix(quoted, leftover, wrapAt, lastPrefix);
      else
        thisLine.prepend(leftover+" ");
      leftover=QString::null;
    }

    if((int)(thisPrefix.length()+thisLine.length()) > wrapAt) {
      breakPos=findBreakPos(thisLine,wrapAt-thisPrefix.length());
      if(breakPos < (int)(thisLine.length())) {
        leftover=thisLine.right(thisLine.length()-breakPos-1);
        thisLine.truncate(breakPos);
      }
    }

    quoted+=thisPrefix+thisLine+"\n";
    lastPrefix=thisPrefix;
  }

  if (!leftover.isEmpty())
    appendTextWPrefix(quoted, leftover, wrapAt, lastPrefix);

  return quoted;
}

// **** misc. message-boxes **********************************************************

void KNHelper::displayInternalFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to load/save configuration!\nWrong permissions on home directory?\nYou should close KNode now to avoid data loss!"));
}

void KNHelper::displayExternalFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to load/save file!"));
}

void KNHelper::displayRemoteFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to save remote file!"));
}

void KNHelper::displayTempFileError(QWidget *w)
{
  KMessageBox::error((w!=0)? w : knGlobals.topWidget, i18n("Unable to create temporary file!"));
}
<|endoftext|>


<commit_before>#include <bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define SZ(x) ((int)((x).size()))
#define PB(x) push_back(x);
#define INF (0x3f3f3f3f)
#define MEMSET(x,v) memset(x,v,sizeof(x));

typedef long long LL;
typedef pair<int, int> PII; typedef pair<PII, int> PII2;
typedef vector<int> VI; typedef vector<VI> VVI;

int main() {

    return 0;
}
<commit_msg>Fixed DefaultCode.cpp<commit_after>#include <bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define SZ(x) ((int)((x).size()))
#define PB(x) push_back(x)
#define INF (0x3f3f3f3f)
#define MEMSET(x,v) memset(x,v,sizeof(x))

typedef long long LL;
typedef pair<int, int> PII; typedef pair<PII, int> PII2;

int main() {

    return 0;
}
<|endoftext|>


<commit_before>#include "tileManager.h"
#include "scene/scene.h"
#include "tile/mapTile.h"
#include "view/view.h"

#include <chrono>
#include <algorithm>

TileManager::TileManager() {
    // Instantiate workers
    for (size_t i = 0; i < MAX_WORKERS; i++) {
        m_workers.push_back(std::unique_ptr<TileWorker>(new TileWorker()));
    }
}

TileManager::TileManager(TileManager&& _other) :
    m_view(std::move(_other.m_view)),
    m_tileSet(std::move(_other.m_tileSet)),
    m_dataSources(std::move(_other.m_dataSources)),
    m_workers(std::move(_other.m_workers)),
    m_queuedTiles(std::move(_other.m_queuedTiles)) {
}

TileManager::~TileManager() {
    for (auto& worker : m_workers) {
        if (!worker->isFree()) {
            worker->abort();
            worker->getTileResult();
        }
        // We stop all workers before we destroy the resources they use.
        // TODO: This will wait for any pending network requests to finish,
        // which could delay closing of the application.
    }
    m_dataSources.clear();
    m_tileSet.clear();
}

void TileManager::addToWorkerQueue(std::vector<char>&& _rawData, const TileID& _tileId, DataSource* _source) {

    std::lock_guard<std::mutex> lock(m_queueTileMutex);
    m_queuedTiles.emplace_back(std::unique_ptr<TileTask>(new TileTask(std::move(_rawData), _tileId, _source)));

}

void TileManager::addToWorkerQueue(std::shared_ptr<TileData>& _parsedData, const TileID& _tileID, DataSource* _source) {

    std::lock_guard<std::mutex> lock(m_queueTileMutex);
    m_queuedTiles.emplace_back(std::unique_ptr<TileTask>(new TileTask(_parsedData, _tileID, _source)));

}

void TileManager::updateTileSet() {

    m_tileSetChanged = false;

    // Check if any native worker needs to be dispatched i.e. queuedTiles is not empty
    {
        auto workersIter = m_workers.begin();
        auto queuedTilesIter = m_queuedTiles.begin();

        while (workersIter != m_workers.end() && queuedTilesIter != m_queuedTiles.end()) {

            auto& worker = *workersIter;

            if (worker->isFree()) {
                worker->processTileData(std::move(*queuedTilesIter), m_scene->getStyles(), *m_view);
                queuedTilesIter = m_queuedTiles.erase(queuedTilesIter);
            }

            ++workersIter;
        }
    }

    // Check if any incoming tiles are finished
    for (auto& worker : m_workers) {

        if (!worker->isFree() && worker->isFinished()) {

            // Get result from worker and move it into tile set
            auto tile = worker->getTileResult();
            const TileID& id = tile->getID();
            logMsg("Tile [%d, %d, %d] finished loading\n", id.z, id.x, id.y);
            std::swap(m_tileSet[id], tile);
            cleanProxyTiles(id);
            m_tileSetChanged = true;

        }

    }

    if (! (m_view->changedOnLastUpdate() || m_tileSetChanged) ) {
        // No new tiles have come into view and no tiles have finished loading,
        // so the tileset is unchanged
        return;
    }

    const std::set<TileID>& visibleTiles = m_view->getVisibleTiles();

    // Loop over visibleTiles and add any needed tiles to tileSet
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (visTilesIter != visibleTiles.end()) {

            if (setTilesIter == m_tileSet.end() || *visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles
                addTile(*visTilesIter);
                m_tileSetChanged = true;
                ++visTilesIter;
            } else if (setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet (handled below)
                ++setTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }

    // Loop over tileSet and remove any tiles that are neither visible nor proxies
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (setTilesIter != m_tileSet.end()) {

            if (visTilesIter == visibleTiles.end() || setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet
                if (setTilesIter->second->getProxyCounter() <= 0) {
                    removeTile(setTilesIter);
                    m_tileSetChanged = true;
                } else {
                    ++setTilesIter;
                }
            } else if (*visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles (shouldn't occur)
                ++visTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }
}

void TileManager::addTile(const TileID& _tileID) {

    std::shared_ptr<MapTile> tile(new MapTile(_tileID, m_view->getMapProjection()));
    m_tileSet[_tileID] = std::move(tile);

    for (auto& source : m_dataSources) {

        if (!source->loadTileData(_tileID, *this)) {

            logMsg("ERROR: Loading failed for tile [%d, %d, %d]\n", _tileID.z, _tileID.x, _tileID.y);

        }
    }

    //Add Proxy if corresponding proxy MapTile ready
    updateProxyTiles(_tileID, m_view->isZoomIn());
}

void TileManager::removeTile(std::map< TileID, std::shared_ptr<MapTile> >::iterator& _tileIter) {

    const TileID& id = _tileIter->first;

    // Make sure to cancel the network request associated with this tile, then if already fetched remove it from the proocessing queue and the worker managing this tile, if applicable
    for(auto& dataSource : m_dataSources) {
        dataSource->cancelLoadingTile(id);
        cleanProxyTiles(id);
    }

    // Remove tile from queue, if present
    const auto& found = std::find_if(m_queuedTiles.begin(), m_queuedTiles.end(),
                                        [&](std::unique_ptr<TileTask>& p) {
                                            return (p->tileID == id);
                                        });

    if (found != m_queuedTiles.end()) {
        logMsg("Erasing tile: [%d,%d,%d]\n", id.x, id.y, id.z);
        m_queuedTiles.erase(found);
        cleanProxyTiles(id);
    }

    // If a worker is processing this tile, abort it
    for (const auto& worker : m_workers) {
        if (!worker->isFree() && worker->getTileID() == id) {
            worker->abort();
            // Proxy tiles will be cleaned in update loop
        }
    }

    // Remove tile from set
    _tileIter = m_tileSet.erase(_tileIter);

}

void TileManager::updateProxyTiles(const TileID& _tileID, bool _zoomingIn) {
    if (_zoomingIn) {
        // zoom in - add parent
        const auto& parentID = _tileID.getParent();
        const auto& parentTileIter = m_tileSet.find(parentID);
        if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
            parentTileIter->second->incProxyCounter();
        }
    } else {
        for(int i = 0; i < 4; i++) {
            const auto& childID = _tileID.getChild(i);
            const auto& childTileIter = m_tileSet.find(childID);
            if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
                childTileIter->second->incProxyCounter();
            }
        }
    }
}

void TileManager::cleanProxyTiles(const TileID& _tileID) {
    // check if parent proxy is present
    const auto& parentID = _tileID.getParent();
    const auto& parentTileIter = m_tileSet.find(parentID);
    if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
        parentTileIter->second->decProxyCounter();
    }

    // check if child proxies are present
    for(int i = 0; i < 4; i++) {
        const auto& childID = _tileID.getChild(i);
        const auto& childTileIter = m_tileSet.find(childID);
        if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
            childTileIter->second->decProxyCounter();
        }
    }
}

<commit_msg>one less log message.. HURRAY!!<commit_after>#include "tileManager.h"
#include "scene/scene.h"
#include "tile/mapTile.h"
#include "view/view.h"

#include <chrono>
#include <algorithm>

TileManager::TileManager() {
    // Instantiate workers
    for (size_t i = 0; i < MAX_WORKERS; i++) {
        m_workers.push_back(std::unique_ptr<TileWorker>(new TileWorker()));
    }
}

TileManager::TileManager(TileManager&& _other) :
    m_view(std::move(_other.m_view)),
    m_tileSet(std::move(_other.m_tileSet)),
    m_dataSources(std::move(_other.m_dataSources)),
    m_workers(std::move(_other.m_workers)),
    m_queuedTiles(std::move(_other.m_queuedTiles)) {
}

TileManager::~TileManager() {
    for (auto& worker : m_workers) {
        if (!worker->isFree()) {
            worker->abort();
            worker->getTileResult();
        }
        // We stop all workers before we destroy the resources they use.
        // TODO: This will wait for any pending network requests to finish,
        // which could delay closing of the application.
    }
    m_dataSources.clear();
    m_tileSet.clear();
}

void TileManager::addToWorkerQueue(std::vector<char>&& _rawData, const TileID& _tileId, DataSource* _source) {

    std::lock_guard<std::mutex> lock(m_queueTileMutex);
    m_queuedTiles.emplace_back(std::unique_ptr<TileTask>(new TileTask(std::move(_rawData), _tileId, _source)));

}

void TileManager::addToWorkerQueue(std::shared_ptr<TileData>& _parsedData, const TileID& _tileID, DataSource* _source) {

    std::lock_guard<std::mutex> lock(m_queueTileMutex);
    m_queuedTiles.emplace_back(std::unique_ptr<TileTask>(new TileTask(_parsedData, _tileID, _source)));

}

void TileManager::updateTileSet() {

    m_tileSetChanged = false;

    // Check if any native worker needs to be dispatched i.e. queuedTiles is not empty
    {
        auto workersIter = m_workers.begin();
        auto queuedTilesIter = m_queuedTiles.begin();

        while (workersIter != m_workers.end() && queuedTilesIter != m_queuedTiles.end()) {

            auto& worker = *workersIter;

            if (worker->isFree()) {
                worker->processTileData(std::move(*queuedTilesIter), m_scene->getStyles(), *m_view);
                queuedTilesIter = m_queuedTiles.erase(queuedTilesIter);
            }

            ++workersIter;
        }
    }

    // Check if any incoming tiles are finished
    for (auto& worker : m_workers) {

        if (!worker->isFree() && worker->isFinished()) {

            // Get result from worker and move it into tile set
            auto tile = worker->getTileResult();
            const TileID& id = tile->getID();
            logMsg("Tile [%d, %d, %d] finished loading\n", id.z, id.x, id.y);
            std::swap(m_tileSet[id], tile);
            cleanProxyTiles(id);
            m_tileSetChanged = true;

        }

    }

    if (! (m_view->changedOnLastUpdate() || m_tileSetChanged) ) {
        // No new tiles have come into view and no tiles have finished loading,
        // so the tileset is unchanged
        return;
    }

    const std::set<TileID>& visibleTiles = m_view->getVisibleTiles();

    // Loop over visibleTiles and add any needed tiles to tileSet
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (visTilesIter != visibleTiles.end()) {

            if (setTilesIter == m_tileSet.end() || *visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles
                addTile(*visTilesIter);
                m_tileSetChanged = true;
                ++visTilesIter;
            } else if (setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet (handled below)
                ++setTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }

    // Loop over tileSet and remove any tiles that are neither visible nor proxies
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (setTilesIter != m_tileSet.end()) {

            if (visTilesIter == visibleTiles.end() || setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet
                if (setTilesIter->second->getProxyCounter() <= 0) {
                    removeTile(setTilesIter);
                    m_tileSetChanged = true;
                } else {
                    ++setTilesIter;
                }
            } else if (*visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles (shouldn't occur)
                ++visTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }
}

void TileManager::addTile(const TileID& _tileID) {

    std::shared_ptr<MapTile> tile(new MapTile(_tileID, m_view->getMapProjection()));
    m_tileSet[_tileID] = std::move(tile);

    for (auto& source : m_dataSources) {

        if (!source->loadTileData(_tileID, *this)) {

            logMsg("ERROR: Loading failed for tile [%d, %d, %d]\n", _tileID.z, _tileID.x, _tileID.y);

        }
    }

    //Add Proxy if corresponding proxy MapTile ready
    updateProxyTiles(_tileID, m_view->isZoomIn());
}

void TileManager::removeTile(std::map< TileID, std::shared_ptr<MapTile> >::iterator& _tileIter) {

    const TileID& id = _tileIter->first;

    // Make sure to cancel the network request associated with this tile, then if already fetched remove it from the proocessing queue and the worker managing this tile, if applicable
    for(auto& dataSource : m_dataSources) {
        dataSource->cancelLoadingTile(id);
        cleanProxyTiles(id);
    }

    // Remove tile from queue, if present
    const auto& found = std::find_if(m_queuedTiles.begin(), m_queuedTiles.end(),
                                        [&](std::unique_ptr<TileTask>& p) {
                                            return (p->tileID == id);
                                        });

    if (found != m_queuedTiles.end()) {
        m_queuedTiles.erase(found);
        cleanProxyTiles(id);
    }

    // If a worker is processing this tile, abort it
    for (const auto& worker : m_workers) {
        if (!worker->isFree() && worker->getTileID() == id) {
            worker->abort();
            // Proxy tiles will be cleaned in update loop
        }
    }

    // Remove tile from set
    _tileIter = m_tileSet.erase(_tileIter);

}

void TileManager::updateProxyTiles(const TileID& _tileID, bool _zoomingIn) {
    if (_zoomingIn) {
        // zoom in - add parent
        const auto& parentID = _tileID.getParent();
        const auto& parentTileIter = m_tileSet.find(parentID);
        if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
            parentTileIter->second->incProxyCounter();
        }
    } else {
        for(int i = 0; i < 4; i++) {
            const auto& childID = _tileID.getChild(i);
            const auto& childTileIter = m_tileSet.find(childID);
            if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
                childTileIter->second->incProxyCounter();
            }
        }
    }
}

void TileManager::cleanProxyTiles(const TileID& _tileID) {
    // check if parent proxy is present
    const auto& parentID = _tileID.getParent();
    const auto& parentTileIter = m_tileSet.find(parentID);
    if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
        parentTileIter->second->decProxyCounter();
    }

    // check if child proxies are present
    for(int i = 0; i < 4; i++) {
        const auto& childID = _tileID.getChild(i);
        const auto& childTileIter = m_tileSet.find(childID);
        if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
            childTileIter->second->decProxyCounter();
        }
    }
}

<|endoftext|>


<commit_before>/*
 * ContextToGL.cpp
 *
 * Copyright (C) 2021 by VISUS (Universitaet Stuttgart).
 * Alle Rechte vorbehalten.
 */

#include "mmcore/view/ContextToGL.h"
#include "mmcore/utility/log/Log.h"

namespace megamol::core::view {

using utility::log::Log;

ContextToGL::ContextToGL(void)
    : Renderer3DModuleGL()
    , _getContextSlot("getContext", "Slot for non-GL context")
{

    this->_getContextSlot.SetCompatibleCall<core::view::CallRender3DDescription>();
    this->MakeSlotAvailable(&this->_getContextSlot);

}

ContextToGL::~ContextToGL(void) {
    this->Release();
}

bool ContextToGL::create(void) {
    if (!_utils.isInitialized()) {
        if (!_utils.InitPrimitiveRendering(this->GetCoreInstance()->ShaderSourceFactory())) {
            Log::DefaultLog.WriteError("[ContextToGL] Unable to initialize RenderUtility.");
        }
    }

    return true;
}

void ContextToGL::release(void) {
}

bool ContextToGL::GetExtents(CallRender3DGL& call) {

    auto cr = _getContextSlot.CallAs<CallRender3D>();
    if (cr == nullptr) return false;
    // no copy constructor available
    auto cast_in = dynamic_cast<AbstractCallRender*>(&call);
    auto cast_out = dynamic_cast<AbstractCallRender*>(cr);
    *cast_out = *cast_in;

    if (!_framebuffer) {
        _framebuffer = std::make_shared<CPUFramebuffer>();
    }
    cr->SetFramebuffer(_framebuffer);

    (*cr)(view::CallRender3D::FnGetExtents);

    call.AccessBoundingBoxes() = cr->AccessBoundingBoxes();
    call.SetTimeFramesCount(cr->TimeFramesCount());

    return true;
}

bool ContextToGL::Render(CallRender3DGL& call) {

    auto cr = _getContextSlot.CallAs<CallRender3D>();
    if (cr == nullptr) return false;
    // no copy constructor available
    auto cast_in = dynamic_cast<AbstractCallRender*>(&call);
    auto cast_out = dynamic_cast<AbstractCallRender*>(cr);
    *cast_out = *cast_in;

    if (!_framebuffer) {
        _framebuffer = std::make_shared<CPUFramebuffer>();
    }
    cr->SetFramebuffer(_framebuffer);

    (*cr)(view::CallRender3D::FnRender);

    Camera_2 cam;
    call.GetCamera(cam);
    cam_type::snapshot_type snapshot;
    cam_type::matrix_type viewTemp, projTemp;

    // Generate complete snapshot and calculate matrices
    cam.calc_matrices(snapshot, viewTemp, projTemp, core::thecam::snapshot_content::all);

    auto width = cam.resolution_gate().width();
    auto height = cam.resolution_gate().height();

    auto lhs_fbo = call.GetFramebufferObject();
    if (lhs_fbo != NULL) {

        // module own fbo
        auto new_fbo = vislib::graphics::gl::FramebufferObject();
        new_fbo.Create(width, height, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE,
            vislib::graphics::gl::FramebufferObject::ATTACHMENT_TEXTURE, GL_DEPTH_COMPONENT);
        new_fbo.Enable();

        new_fbo.BindColourTexture();
        glClear(GL_COLOR_BUFFER_BIT);
        glTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, _framebuffer->colorBuffer.data());
        glBindTexture(GL_TEXTURE_2D, 0);

        if (_framebuffer->depthBufferActive) {
            new_fbo.BindDepthTexture();
            glClear(GL_DEPTH_BUFFER_BIT);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
                _framebuffer->depthBuffer.data());
            glBindTexture(GL_TEXTURE_2D, 0);
        }
        float right = (width + static_cast<float>(width)) / 2.0f;
        float left = (width - static_cast<float>(width)) / 2.0f;
        float bottom = (height + static_cast<float>(height)) / 2.0f;
        float up = (height - static_cast<float>(height)) / 2.0f;
        glm::vec3 pos_bottom_left = {left, bottom, 0.0f};
        glm::vec3 pos_upper_left = {left, up, 0.0f};
        glm::vec3 pos_upper_right = {right, up, 0.0f};
        glm::vec3 pos_bottom_right = {right, bottom, 0.0f};
        _utils.Push2DColorTexture(
            new_fbo.GetColourTextureID(), pos_bottom_left, pos_upper_left, pos_upper_right, pos_bottom_right,true);
        if (_framebuffer->depthBufferActive) {
            _utils.Push2DDepthTexture(
                new_fbo.GetDepthTextureID(), pos_bottom_left, pos_upper_left, pos_upper_right, pos_bottom_right, true);
        }

        new_fbo.Disable();

        // draw into lhs fbo
        if ((lhs_fbo->GetWidth() != width) || (lhs_fbo->GetHeight() != height)) {
            lhs_fbo->Release();
            lhs_fbo->Create(width, height, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE,
                vislib::graphics::gl::FramebufferObject::ATTACHMENT_TEXTURE, GL_DEPTH_COMPONENT);
        }
        if (lhs_fbo->IsValid() && !lhs_fbo->IsEnabled()) {
            lhs_fbo->Enable();
        }

        glm::mat4 ortho = glm::ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height), -1.0f, 1.0f);

        _utils.DrawTextures(ortho, glm::vec2(width, height));

        if (lhs_fbo->IsValid()) {
            lhs_fbo->Disable();
        }
    } else {
        return false;
    }
    return true;
}

} // namespace megamol::core::view
<commit_msg>forward input events<commit_after>/*
 * ContextToGL.cpp
 *
 * Copyright (C) 2021 by VISUS (Universitaet Stuttgart).
 * Alle Rechte vorbehalten.
 */

#include "mmcore/view/ContextToGL.h"
#include "mmcore/utility/log/Log.h"

namespace megamol::core::view {

using utility::log::Log;

ContextToGL::ContextToGL(void)
    : Renderer3DModuleGL()
    , _getContextSlot("getContext", "Slot for non-GL context")
{

    this->_getContextSlot.SetCompatibleCall<core::view::CallRender3DDescription>();
    this->MakeSlotAvailable(&this->_getContextSlot);

}

ContextToGL::~ContextToGL(void) {
    this->Release();
}

bool ContextToGL::create(void) {
    if (!_utils.isInitialized()) {
        if (!_utils.InitPrimitiveRendering(this->GetCoreInstance()->ShaderSourceFactory())) {
            Log::DefaultLog.WriteError("[ContextToGL] Unable to initialize RenderUtility.");
        }
    }

    return true;
}

void ContextToGL::release(void) {
}

bool ContextToGL::GetExtents(CallRender3DGL& call) {

    auto cr = _getContextSlot.CallAs<CallRender3D>();
    if (cr == nullptr) return false;
    // no copy constructor available
    auto cast_in = dynamic_cast<AbstractCallRender*>(&call);
    auto cast_out = dynamic_cast<AbstractCallRender*>(cr);
    *cast_out = *cast_in;

    if (!_framebuffer) {
        _framebuffer = std::make_shared<CPUFramebuffer>();
    }
    cr->SetFramebuffer(_framebuffer);

    (*cr)(view::CallRender3D::FnGetExtents);

    call.AccessBoundingBoxes() = cr->AccessBoundingBoxes();
    call.SetTimeFramesCount(cr->TimeFramesCount());

    return true;
}

bool ContextToGL::Render(CallRender3DGL& call) {

    auto cr = _getContextSlot.CallAs<CallRender3D>();
    if (cr == nullptr) return false;
    // no copy constructor available
    auto cast_in = dynamic_cast<AbstractCallRender*>(&call);
    auto cast_out = dynamic_cast<AbstractCallRender*>(cr);
    *cast_out = *cast_in;

    if (!_framebuffer) {
        _framebuffer = std::make_shared<CPUFramebuffer>();
    }
    cr->SetFramebuffer(_framebuffer);
    cr->SetInputEvent(call.GetInputEvent());

    auto const& ie = cr->GetInputEvent();
    switch (ie.tag) {
    case InputEvent::Tag::Char: {
        (*cr)(view::CallRender3D::FnOnChar);
    } break;
    case InputEvent::Tag::Key: {
        (*cr)(view::CallRender3D::FnOnKey);
    } break;
    case InputEvent::Tag::MouseButton: {
        (*cr)(view::CallRender3D::FnOnMouseButton);
    } break;
    case InputEvent::Tag::MouseMove: {
        (*cr)(view::CallRender3D::FnOnMouseMove);
    } break;
    case InputEvent::Tag::MouseScroll: {
        (*cr)(view::CallRender3D::FnOnMouseScroll);
    } break;
    }

    (*cr)(view::CallRender3D::FnRender);

    Camera_2 cam;
    call.GetCamera(cam);
    cam_type::snapshot_type snapshot;
    cam_type::matrix_type viewTemp, projTemp;

    // Generate complete snapshot and calculate matrices
    cam.calc_matrices(snapshot, viewTemp, projTemp, core::thecam::snapshot_content::all);

    auto width = cam.resolution_gate().width();
    auto height = cam.resolution_gate().height();

    auto lhs_fbo = call.GetFramebufferObject();
    if (lhs_fbo != NULL) {

        // module own fbo
        auto new_fbo = vislib::graphics::gl::FramebufferObject();
        new_fbo.Create(width, height, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE,
            vislib::graphics::gl::FramebufferObject::ATTACHMENT_TEXTURE, GL_DEPTH_COMPONENT);
        new_fbo.Enable();

        new_fbo.BindColourTexture();
        glClear(GL_COLOR_BUFFER_BIT);
        glTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, _framebuffer->colorBuffer.data());
        glBindTexture(GL_TEXTURE_2D, 0);

        if (_framebuffer->depthBufferActive) {
            new_fbo.BindDepthTexture();
            glClear(GL_DEPTH_BUFFER_BIT);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
                _framebuffer->depthBuffer.data());
            glBindTexture(GL_TEXTURE_2D, 0);
        }
        float right = (width + static_cast<float>(width)) / 2.0f;
        float left = (width - static_cast<float>(width)) / 2.0f;
        float bottom = (height + static_cast<float>(height)) / 2.0f;
        float up = (height - static_cast<float>(height)) / 2.0f;
        glm::vec3 pos_bottom_left = {left, bottom, 0.0f};
        glm::vec3 pos_upper_left = {left, up, 0.0f};
        glm::vec3 pos_upper_right = {right, up, 0.0f};
        glm::vec3 pos_bottom_right = {right, bottom, 0.0f};
        _utils.Push2DColorTexture(
            new_fbo.GetColourTextureID(), pos_bottom_left, pos_upper_left, pos_upper_right, pos_bottom_right,true);
        if (_framebuffer->depthBufferActive) {
            _utils.Push2DDepthTexture(
                new_fbo.GetDepthTextureID(), pos_bottom_left, pos_upper_left, pos_upper_right, pos_bottom_right, true);
        }

        new_fbo.Disable();

        // draw into lhs fbo
        if ((lhs_fbo->GetWidth() != width) || (lhs_fbo->GetHeight() != height)) {
            lhs_fbo->Release();
            lhs_fbo->Create(width, height, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE,
                vislib::graphics::gl::FramebufferObject::ATTACHMENT_TEXTURE, GL_DEPTH_COMPONENT);
        }
        if (lhs_fbo->IsValid() && !lhs_fbo->IsEnabled()) {
            lhs_fbo->Enable();
        }

        glm::mat4 ortho = glm::ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height), -1.0f, 1.0f);

        _utils.DrawTextures(ortho, glm::vec2(width, height));

        if (lhs_fbo->IsValid()) {
            lhs_fbo->Disable();
        }
    } else {
        return false;
    }
    return true;
}
} // namespace megamol::core::view
<|endoftext|>


<commit_before>//
// C++ Interface: BuiltinFuncs
//
// Description:
//
//
// Author: Carmelo Piccione <carmelo.piccione@gmail.com>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//

#ifndef _BUILTIN_FUNCS_HPP
#define _BUILTIN_FUNCS_HPP

#include "Common.hpp"
#include "Func.hpp"
#include <cmath>
#include <cstdlib>
#include <cassert>

#include "RandomNumberGenerators.hpp"

/* Wrappers for all the builtin functions
   The arg_list pointer is a list of floats. Its
   size is equal to the number of arguments the parameter
   takes */
class FuncWrappers {

/* Values to optimize the sigmoid function */
static const int R =  32767;
static const int RR = 65534;

public:

static inline float int_wrapper(float * arg_list) {

return floor(arg_list[0]);

}

static inline float sqr_wrapper(float * arg_list) {
	return pow(arg_list[0], 2);
}

static inline float sigmoid_wrapper(float * arg_list)
{
	const double t = (1+exp(-arg_list[0]*arg_list[1]));
	return (fabs(t) > 0.00001) ? 1.0/t : 0;
}

static inline float sign_wrapper(float * arg_list) {

return -arg_list[0];
}

static inline float min_wrapper(float * arg_list) {

if (arg_list[0] > arg_list[1])
return arg_list[1];

return arg_list[0];
}

static inline float max_wrapper(float * arg_list) {

if (arg_list[0] > arg_list[1])
return arg_list[0];

return arg_list[1];
}

static inline float bor_wrapper(float * arg_list) {

return (float)((int)arg_list[0] || (int)arg_list[1]);
}

static inline float band_wrapper(float * arg_list) {
return (float)((int)arg_list[0] && (int)arg_list[1]);
}

static inline float bnot_wrapper(float * arg_list) {
return (float)(!(int)arg_list[0]);
}

static inline float if_wrapper(float * arg_list) {

	if ((int)arg_list[0] == 0)
		return arg_list[2];
	//std::cout <<"NOT ZERO: " << arg_list[0] << std::endl;
	return arg_list[1];
}

static inline float rand_wrapper(float * arg_list) {
float l=1;

//  printf("RAND ARG:(%d)\n", (int)arg_list[0]);
if ((int)arg_list[0] > 0)
	l  = (float) RandomNumberGenerators::uniformInteger((int)arg_list[0]);

return l;
}

static inline float equal_wrapper(float * arg_list) {
	return (arg_list[0] == arg_list[1]);
}

static inline float above_wrapper(float * arg_list) {

return (arg_list[0] > arg_list[1]);
}

static inline float below_wrapper(float * arg_list) {

return (arg_list[0] < arg_list[1]);
}

static float sin_wrapper(float * arg_list) {
	const float d = sinf(*arg_list);
	return d;
}

static inline float cos_wrapper(float * arg_list) {
return (cos (arg_list[0]));
}

static inline float tan_wrapper(float * arg_list) {
return (tan(arg_list[0]));
}

static inline float asin_wrapper(float * arg_list) {
return (asin (arg_list[0]));
}

static inline float acos_wrapper(float * arg_list) {
return (acos (arg_list[0]));
}

static inline float atan_wrapper(float * arg_list) {
return (atan (arg_list[0]));
}

static inline float atan2_wrapper(float * arg_list) {
return (atan2 (arg_list[0], arg_list[1]));
}

static inline float pow_wrapper(float * arg_list) {
return (pow (arg_list[0], arg_list[1]));
}

static inline float exp_wrapper(float * arg_list) {
return (exp(arg_list[0]));
}

static inline float abs_wrapper(float * arg_list) {
return (fabs(arg_list[0]));
}

static inline float log_wrapper(float* arg_list) {
return (log (arg_list[0]));
}

static inline float log10_wrapper(float * arg_list) {
return (log10 (arg_list[0]));
}

static inline float sqrt_wrapper(float * arg_list) {
return (sqrt (arg_list[0]));
}

static inline float print_wrapper(float * arg_list) {

	int len = sizeof(arg_list)/sizeof(float);

	for (int i = 0; i < len; i++)
	{
		std::cout << arg_list[0];
		if (i != (len-1))
			std::cout << " ";
	}

	if (len > 0)
		std::cout << std::endl;

	if (len > 0)
		return arg_list[0];
	else
		return 0;
}

static inline float nchoosek_wrapper(float * arg_list) {
unsigned long cnm = 1UL;
int i, f;
int n, m;

n = (int)arg_list[0];
m = (int)arg_list[1];

if (m*2 >n) m = n-m;
for (i=1 ; i <= m; n--, i++)
{
if ((f=n) % i == 0)
f   /= i;
else  cnm /= i;
cnm *= f;
}
return (float)cnm;
}

static inline float fact_wrapper(float * arg_list) {

int result = 1;

int n = (int)arg_list[0];

while (n > 1) {
result = result * n;
n--;
}
return (float)result;
}
};

#include <map>
class BuiltinFuncs {

public:

    static int init_builtin_func_db();
    static int destroy_builtin_func_db();
    static int load_all_builtin_func();
    static int load_builtin_func( const std::string & name, float (*func_ptr)(float*), int num_args );

    static int insert_func( Func *func );
    static int remove_func( Func *func );
    static Func *find_func( const std::string & name );
private:
     static std::map<std::string, Func*> builtin_func_tree;
     static volatile bool initialized;
};

#endif
<commit_msg>typo<commit_after>//
// C++ Interface: BuiltinFuncs
//
// Description:
//
//
// Author: Carmelo Piccione <carmelo.piccione@gmail.com>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//

#ifndef _BUILTIN_FUNCS_HPP
#define _BUILTIN_FUNCS_HPP

#include "Common.hpp"
#include "Func.hpp"
#include <cmath>
#include <cstdlib>
#include <cassert>

#include "RandomNumberGenerators.hpp"

/* Wrappers for all the builtin functions
   The arg_list pointer is a list of floats. Its
   size is equal to the number of arguments the parameter
   takes */
class FuncWrappers {

/* Values to optimize the sigmoid function */
static const int R =  32767;
static const int RR = 65534;

public:

static inline float int_wrapper(float * arg_list) {

return floor(arg_list[0]);

}

static inline float sqr_wrapper(float * arg_list) {
	return pow(arg_list[0], 2);
}

static inline float sigmoid_wrapper(float * arg_list)
{
	const double t = (1+exp(-arg_list[0]*arg_list[1]));
	return (fabs(t) > 0.00001) ? 1.0/t : 0;
}

static inline float sign_wrapper(float * arg_list) {

return -arg_list[0];
}

static inline float min_wrapper(float * arg_list) {

if (arg_list[0] > arg_list[1])
return arg_list[1];

return arg_list[0];
}

static inline float max_wrapper(float * arg_list) {

if (arg_list[0] > arg_list[1])
return arg_list[0];

return arg_list[1];
}

static inline float bor_wrapper(float * arg_list) {

return (float)((int)arg_list[0] || (int)arg_list[1]);
}

static inline float band_wrapper(float * arg_list) {
return (float)((int)arg_list[0] && (int)arg_list[1]);
}

static inline float bnot_wrapper(float * arg_list) {
return (float)(!(int)arg_list[0]);
}

static inline float if_wrapper(float * arg_list) {

	if ((int)arg_list[0] == 0)
		return arg_list[2];
	//std::cout <<"NOT ZERO: " << arg_list[0] << std::endl;
	return arg_list[1];
}

static inline float rand_wrapper(float * arg_list) {
float l=1;

//  printf("RAND ARG:(%d)\n", (int)arg_list[0]);
if ((int)arg_list[0] > 0)
	l  = (float) RandomNumberGenerators::uniformInteger((int)arg_list[0]);

return l;
}

static inline float equal_wrapper(float * arg_list) {
	return (arg_list[0] == arg_list[1]);
}

static inline float above_wrapper(float * arg_list) {

return (arg_list[0] > arg_list[1]);
}

static inline float below_wrapper(float * arg_list) {

return (arg_list[0] < arg_list[1]);
}

static float sin_wrapper(float * arg_list) {
	const float d = sinf(*arg_list);
	return d;
}

static inline float cos_wrapper(float * arg_list) {
return (cos (arg_list[0]));
}

static inline float tan_wrapper(float * arg_list) {
return (tan(arg_list[0]));
}

static inline float asin_wrapper(float * arg_list) {
return (asin (arg_list[0]));
}

static inline float acos_wrapper(float * arg_list) {
return (acos (arg_list[0]));
}

static inline float atan_wrapper(float * arg_list) {
return (atan (arg_list[0]));
}

static inline float atan2_wrapper(float * arg_list) {
return (atan2 (arg_list[0], arg_list[1]));
}

static inline float pow_wrapper(float * arg_list) {
return (pow (arg_list[0], arg_list[1]));
}

static inline float exp_wrapper(float * arg_list) {
return (exp(arg_list[0]));
}

static inline float abs_wrapper(float * arg_list) {
return (fabs(arg_list[0]));
}

static inline float log_wrapper(float* arg_list) {
return (log (arg_list[0]));
}

static inline float log10_wrapper(float * arg_list) {
return (log10 (arg_list[0]));
}

static inline float sqrt_wrapper(float * arg_list) {
return (sqrt (arg_list[0]));
}

static inline float print_wrapper(float * arg_list) {

	int len = sizeof(arg_list)/sizeof(float);

	for (int i = 0; i < len; i++)
	{
		std::cout << arg_list[i];
		if (i != (len-1))
			std::cout << " ";
	}

	if (len > 0)
		std::cout << std::endl;

	if (len > 0)
		return arg_list[0];
	else
		return 0;
}

static inline float nchoosek_wrapper(float * arg_list) {
unsigned long cnm = 1UL;
int i, f;
int n, m;

n = (int)arg_list[0];
m = (int)arg_list[1];

if (m*2 >n) m = n-m;
for (i=1 ; i <= m; n--, i++)
{
if ((f=n) % i == 0)
f   /= i;
else  cnm /= i;
cnm *= f;
}
return (float)cnm;
}

static inline float fact_wrapper(float * arg_list) {

int result = 1;

int n = (int)arg_list[0];

while (n > 1) {
result = result * n;
n--;
}
return (float)result;
}
};

#include <map>
class BuiltinFuncs {

public:

    static int init_builtin_func_db();
    static int destroy_builtin_func_db();
    static int load_all_builtin_func();
    static int load_builtin_func( const std::string & name, float (*func_ptr)(float*), int num_args );

    static int insert_func( Func *func );
    static int remove_func( Func *func );
    static Func *find_func( const std::string & name );
private:
     static std::map<std::string, Func*> builtin_func_tree;
     static volatile bool initialized;
};

#endif
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "spriterenderercomponent.h"

#include <texture.h>
#include <game.h>

#include "graphics/item.h"
#include "graphics/engine.h"
#include "graphics/material.h"
#include "graphics/mesh.h"
#include "graphics/materialinstance.h"
#include "engine/gameobject.h"
#include "engine/asset.h"

#include <QtGui/QMatrix4x4>
#include <QtGui/QColor>
#include <QtCore/QMimeData>
#include <QtCore/QVariant>

REGISTER_OBJECTTYPE( GluonEngine, SpriteRendererComponent )

using namespace GluonEngine;

class SpriteRendererComponent::SpriteRendererComponentPrivate
{
    public:
        SpriteRendererComponentPrivate()
        {
            item = 0;
            texture = 0;
            material = 0;
            size = QSizeF( 1.0f, 1.0f );
            color.setRgb( 255, 255, 255 );
        }

        GluonGraphics::Item* item;
        GluonEngine::Asset* texture;
        GluonGraphics::MaterialInstance* material;

        QColor color;
        QSizeF size;
};

SpriteRendererComponent::SpriteRendererComponent( QObject* parent )
    : Component( parent )
    , d( new SpriteRendererComponentPrivate )
{

}

SpriteRendererComponent::SpriteRendererComponent( const SpriteRendererComponent& other )
    : Component( other )
    , d( other.d )
{
}

SpriteRendererComponent::~SpriteRendererComponent()
{
    delete d;
}

QString SpriteRendererComponent::category() const
{
    return QString( "Graphics Rendering" );
}

void SpriteRendererComponent::initialize()
{
    if( !d->item )
    {
        d->item = GluonGraphics::Engine::instance()->createItem( "default" );
    }

    if( d->material )
    {
        Asset* materialAsset = qobject_cast<Asset*>( d->material->parent() );
        if( materialAsset )
            materialAsset->load();

        Asset* texture = 0;
        if( d->material->property( "texture0" ).type() == QVariant::String )
            texture = gameProject()->findChild<Asset*>( d->material->property( "texture0" ).toString() );
        else
            texture = qobject_cast<Asset*>( GluonCore::GluonObjectFactory::instance()->wrappedObject( d->material->property( "texture0" ) ) );

        if( texture )
            texture->load();
        d->item->setMaterialInstance( d->material );
    }
}

void SpriteRendererComponent::start()
{
}

void SpriteRendererComponent::draw( int timeLapse )
{
    Q_UNUSED( timeLapse )

    if( d->item )
    {
        QMatrix4x4 transform = gameObject()->transform();
        transform.scale( d->size.width() / 2, d->size.height() / 2 );
        d->item->setTransform( transform );
    }
}

void SpriteRendererComponent::cleanup()
{
    if( d->item )
    {
        GluonGraphics::Engine::instance()->destroyItem( d->item );
        d->item = 0;
    }
}

void SpriteRendererComponent::setSize( const QSizeF& size )
{
    d->size = size;
}

QSizeF SpriteRendererComponent::size()
{
    return d->size;
}

GluonGraphics::MaterialInstance*
SpriteRendererComponent::material()
{
    return d->material;
}

void SpriteRendererComponent::setMaterial( GluonGraphics::MaterialInstance* material )
{
    d->material = material;

    if( d->item )
    {
        if(material)
        {
            d->item->setMaterialInstance( material );
        }
        else
        {
            d->item->setMaterialInstance(GluonGraphics::Engine::instance()->material("default")->instance("default"));
        }
    }
}

void SpriteRendererComponent::setMaterial( const QString& path )
{
    setMaterial( qobject_cast<GluonGraphics::MaterialInstance*>( Game::instance()->gameProject()->findItemByName( path ) ) );
}

Q_EXPORT_PLUGIN2( gluon_component_spriterenderer, GluonEngine::SpriteRendererComponent );

#include "spriterenderercomponent.moc"
<commit_msg>Add name sanitizing to the string based texture asset locator<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "spriterenderercomponent.h"

#include <texture.h>
#include <game.h>

#include "graphics/item.h"
#include "graphics/engine.h"
#include "graphics/material.h"
#include "graphics/mesh.h"
#include "graphics/materialinstance.h"
#include "engine/gameobject.h"
#include "engine/asset.h"

#include <QtGui/QMatrix4x4>
#include <QtGui/QColor>
#include <QtCore/QMimeData>
#include <QtCore/QVariant>

REGISTER_OBJECTTYPE( GluonEngine, SpriteRendererComponent )

using namespace GluonEngine;

class SpriteRendererComponent::SpriteRendererComponentPrivate
{
    public:
        SpriteRendererComponentPrivate()
        {
            item = 0;
            texture = 0;
            material = 0;
            size = QSizeF( 1.0f, 1.0f );
            color.setRgb( 255, 255, 255 );
        }

        GluonGraphics::Item* item;
        GluonEngine::Asset* texture;
        GluonGraphics::MaterialInstance* material;

        QColor color;
        QSizeF size;
};

SpriteRendererComponent::SpriteRendererComponent( QObject* parent )
    : Component( parent )
    , d( new SpriteRendererComponentPrivate )
{

}

SpriteRendererComponent::SpriteRendererComponent( const SpriteRendererComponent& other )
    : Component( other )
    , d( other.d )
{
}

SpriteRendererComponent::~SpriteRendererComponent()
{
    delete d;
}

QString SpriteRendererComponent::category() const
{
    return QString( "Graphics Rendering" );
}

void SpriteRendererComponent::initialize()
{
    if( !d->item )
    {
        d->item = GluonGraphics::Engine::instance()->createItem( "default" );
    }

    if( d->material )
    {
        Asset* materialAsset = qobject_cast<Asset*>( d->material->parent() );
        if( materialAsset )
            materialAsset->load();

        Asset* texture = 0;
        if( d->material->property( "texture0" ).type() == QVariant::String )
        {
            QString theName( d->material->property( "texture0" ).toString() );
            QString theObjectName = GluonObject::nameToObjectName( theName );
            texture = gameProject()->findChild<Asset*>( theObjectName );
            if(!texture)
                debug( QString( "Texture failed to load - attempted to load texture named %1" ).arg( theName ) );
        }
        else
            texture = qobject_cast<Asset*>( GluonCore::GluonObjectFactory::instance()->wrappedObject( d->material->property( "texture0" ) ) );

        if( texture )
            texture->load();
        d->item->setMaterialInstance( d->material );
    }
}

void SpriteRendererComponent::start()
{
}

void SpriteRendererComponent::draw( int timeLapse )
{
    Q_UNUSED( timeLapse )

    if( d->item )
    {
        QMatrix4x4 transform = gameObject()->transform();
        transform.scale( d->size.width() / 2, d->size.height() / 2 );
        d->item->setTransform( transform );
    }
}

void SpriteRendererComponent::cleanup()
{
    if( d->item )
    {
        GluonGraphics::Engine::instance()->destroyItem( d->item );
        d->item = 0;
    }
}

void SpriteRendererComponent::setSize( const QSizeF& size )
{
    d->size = size;
}

QSizeF SpriteRendererComponent::size()
{
    return d->size;
}

GluonGraphics::MaterialInstance*
SpriteRendererComponent::material()
{
    return d->material;
}

void SpriteRendererComponent::setMaterial( GluonGraphics::MaterialInstance* material )
{
    d->material = material;

    if( d->item )
    {
        if(material)
        {
            d->item->setMaterialInstance( material );
        }
        else
        {
            d->item->setMaterialInstance(GluonGraphics::Engine::instance()->material("default")->instance("default"));
        }
    }
}

void SpriteRendererComponent::setMaterial( const QString& path )
{
    setMaterial( qobject_cast<GluonGraphics::MaterialInstance*>( Game::instance()->gameProject()->findItemByName( path ) ) );
}

Q_EXPORT_PLUGIN2( gluon_component_spriterenderer, GluonEngine::SpriteRendererComponent );

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


<commit_before>/*
  broadcaststatus.cpp

  This file is part of KDEPIM.

  Author: Don Sanders <sanders@kde.org>

  Copyright (C) 2000 Don Sanders <sanders@kde.org>

  License GPL
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <qdatetime.h>

#include <klocale.h>
#include <kglobal.h>

#include "broadcaststatus.h"
#include "progressmanager.h"

KPIM::BroadcastStatus* KPIM::BroadcastStatus::instance_ = 0;

namespace KPIM {

BroadcastStatus* BroadcastStatus::instance()
{
  if (!instance_)
    instance_ = new BroadcastStatus();
  return instance_;
}

BroadcastStatus::BroadcastStatus()
{
}

void BroadcastStatus::setStatusMsg( const QString& message )
{
  mStatusMsg = message;
  if( !mTransientActive )
    emit statusMsg( message );
}

void BroadcastStatus::setStatusMsgWithTimestamp( const QString& message )
{
  KLocale* locale = KGlobal::locale();
  setStatusMsg( i18n( "%1 is a time, %2 is a status message", "[%1] %2" )
                .arg( locale->formatTime( QTime::currentTime(),
                                          true /* with seconds */ ) )
                .arg( message ) );
}

void BroadcastStatus::setStatusMsgTransmissionCompleted( int numMessages,
                                                           int numBytes,
                                                           int numBytesRead,
                                                           int numBytesToRead,
                                                           bool mLeaveOnServer,
                                                           KPIM::ProgressItem* item )
{
  QString statusMsg;
  if( numMessages > 0 ) {
    if( numBytes != -1 ) {
      if( ( numBytesToRead != numBytes ) && mLeaveOnServer )
        statusMsg = i18n( "Transmission complete. %n new message in %1 KB "
                          "(%2 KB remaining on the server).",
                          "Transmission complete. %n new messages in %1 KB "
                          "(%2 KB remaining on the server).",
                          numMessages )
                    .arg( numBytesRead / 1024 )
                    .arg( numBytes / 1024 );
      else
        statusMsg = i18n( "Transmission complete. %n message in %1 KB.",
                         "Transmission complete. %n messages in %1 KB.",
                          numMessages )
                    .arg( numBytesRead / 1024 );
    }
    else
      statusMsg = i18n( "Transmission complete. %n new message.",
                        "Transmission complete. %n new messages.",
                        numMessages );
  }
  else
    statusMsg = i18n( "Transmission complete. No new messages." );

  setStatusMsgWithTimestamp( statusMsg );
  if ( item )
    item->setStatus( statusMsg );
}

void BroadcastStatus::setStatusMsgTransmissionCompleted( const QString& account,
                                                           int numMessages,
                                                           int numBytes,
                                                           int numBytesRead,
                                                           int numBytesToRead,
                                                           bool mLeaveOnServer,
                                                           KPIM::ProgressItem* item )
{
  QString statusMsg;
  if( numMessages > 0 ) {
    if( numBytes != -1 ) {
      if( ( numBytesToRead != numBytes ) && mLeaveOnServer )
        statusMsg = i18n( "Transmission for account %3 complete. "
                          "%n new message in %1 KB "
                          "(%2 KB remaining on the server).",
                          "Transmission for account %3 complete. "
                          "%n new messages in %1 KB "
                          "(%2 KB remaining on the server).",
                          numMessages )
                    .arg( numBytesRead / 1024 )
                    .arg( numBytes / 1024 )
                    .arg( account );
      else
        statusMsg = i18n( "Transmission for account %2 complete. "
                          "%n message in %1 KB.",
                          "Transmission for account %2 complete. "
                          "%n messages in %1 KB.",
                          numMessages )
                    .arg( numBytesRead / 1024 )
                    .arg( account );
    }
    else
      statusMsg = i18n( "Transmission for account %1 complete. "
                        "%n new message.",
                        "Transmission for account %1 complete. "
                        "%n new messages.",
                        numMessages )
                  .arg( account );
  }
  else
    statusMsg = i18n( "Transmission for account %1 complete. No new messages.")
                .arg( account );

  setStatusMsgWithTimestamp( statusMsg );
  if ( item )
    item->setStatus( statusMsg );
}

void BroadcastStatus::setTransientStatusMsg( const QString& msg )
{
  mTransientActive = true;
  emit statusMsg( msg );
}

void BroadcastStatus::reset()
{
  mTransientActive = false;
  // restore
  emit statusMsg( mStatusMsg );
}

}

#include "broadcaststatus.moc"
<commit_msg>Introduced a new bool member and didn't initialize it. Bad Till. No cookie for me tonight.<commit_after>/*
  broadcaststatus.cpp

  This file is part of KDEPIM.

  Author: Don Sanders <sanders@kde.org>

  Copyright (C) 2000 Don Sanders <sanders@kde.org>

  License GPL
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <qdatetime.h>

#include <klocale.h>
#include <kglobal.h>

#include "broadcaststatus.h"
#include "progressmanager.h"

KPIM::BroadcastStatus* KPIM::BroadcastStatus::instance_ = 0;

namespace KPIM {

BroadcastStatus* BroadcastStatus::instance()
{
  if (!instance_)
    instance_ = new BroadcastStatus();
  return instance_;
}

BroadcastStatus::BroadcastStatus()
  :mTransientActive( false )
{
}

void BroadcastStatus::setStatusMsg( const QString& message )
{
  mStatusMsg = message;
  if( !mTransientActive )
    emit statusMsg( message );
}

void BroadcastStatus::setStatusMsgWithTimestamp( const QString& message )
{
  KLocale* locale = KGlobal::locale();
  setStatusMsg( i18n( "%1 is a time, %2 is a status message", "[%1] %2" )
                .arg( locale->formatTime( QTime::currentTime(),
                                          true /* with seconds */ ) )
                .arg( message ) );
}

void BroadcastStatus::setStatusMsgTransmissionCompleted( int numMessages,
                                                           int numBytes,
                                                           int numBytesRead,
                                                           int numBytesToRead,
                                                           bool mLeaveOnServer,
                                                           KPIM::ProgressItem* item )
{
  QString statusMsg;
  if( numMessages > 0 ) {
    if( numBytes != -1 ) {
      if( ( numBytesToRead != numBytes ) && mLeaveOnServer )
        statusMsg = i18n( "Transmission complete. %n new message in %1 KB "
                          "(%2 KB remaining on the server).",
                          "Transmission complete. %n new messages in %1 KB "
                          "(%2 KB remaining on the server).",
                          numMessages )
                    .arg( numBytesRead / 1024 )
                    .arg( numBytes / 1024 );
      else
        statusMsg = i18n( "Transmission complete. %n message in %1 KB.",
                         "Transmission complete. %n messages in %1 KB.",
                          numMessages )
                    .arg( numBytesRead / 1024 );
    }
    else
      statusMsg = i18n( "Transmission complete. %n new message.",
                        "Transmission complete. %n new messages.",
                        numMessages );
  }
  else
    statusMsg = i18n( "Transmission complete. No new messages." );

  setStatusMsgWithTimestamp( statusMsg );
  if ( item )
    item->setStatus( statusMsg );
}

void BroadcastStatus::setStatusMsgTransmissionCompleted( const QString& account,
                                                           int numMessages,
                                                           int numBytes,
                                                           int numBytesRead,
                                                           int numBytesToRead,
                                                           bool mLeaveOnServer,
                                                           KPIM::ProgressItem* item )
{
  QString statusMsg;
  if( numMessages > 0 ) {
    if( numBytes != -1 ) {
      if( ( numBytesToRead != numBytes ) && mLeaveOnServer )
        statusMsg = i18n( "Transmission for account %3 complete. "
                          "%n new message in %1 KB "
                          "(%2 KB remaining on the server).",
                          "Transmission for account %3 complete. "
                          "%n new messages in %1 KB "
                          "(%2 KB remaining on the server).",
                          numMessages )
                    .arg( numBytesRead / 1024 )
                    .arg( numBytes / 1024 )
                    .arg( account );
      else
        statusMsg = i18n( "Transmission for account %2 complete. "
                          "%n message in %1 KB.",
                          "Transmission for account %2 complete. "
                          "%n messages in %1 KB.",
                          numMessages )
                    .arg( numBytesRead / 1024 )
                    .arg( account );
    }
    else
      statusMsg = i18n( "Transmission for account %1 complete. "
                        "%n new message.",
                        "Transmission for account %1 complete. "
                        "%n new messages.",
                        numMessages )
                  .arg( account );
  }
  else
    statusMsg = i18n( "Transmission for account %1 complete. No new messages.")
                .arg( account );

  setStatusMsgWithTimestamp( statusMsg );
  if ( item )
    item->setStatus( statusMsg );
}

void BroadcastStatus::setTransientStatusMsg( const QString& msg )
{
  mTransientActive = true;
  emit statusMsg( msg );
}

void BroadcastStatus::reset()
{
  mTransientActive = false;
  // restore
  emit statusMsg( mStatusMsg );
}

}

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


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

#include "DataManager.h"

#include "OrbitBase/Logging.h"
#include "OrbitClientData/ModuleData.h"
#include "OrbitClientData/ProcessData.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"

using orbit_client_protos::FunctionInfo;
using orbit_grpc_protos::ModuleInfo;
using orbit_grpc_protos::ProcessInfo;
using orbit_grpc_protos::TracepointInfo;

void DataManager::UpdateProcessInfos(const std::vector<ProcessInfo>& process_infos) {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  // Note that at this point the data manager does not remove old processes.
  // To do it correctly we may need to implement some callback logic here
  // since the ProcessData can be in use by some views.
  for (const ProcessInfo& info : process_infos) {
    int32_t process_id = info.pid();
    auto it = process_map_.find(process_id);
    if (it != process_map_.end()) {
      it->second.SetProcessInfo(info);
    } else {
      auto [inserted_it, success] = process_map_.try_emplace(process_id, info);
      CHECK(success);
    }
  }
}

void DataManager::UpdateModuleInfos(int32_t process_id,
                                    const std::vector<ModuleInfo>& module_infos) {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  auto process_it = process_map_.find(process_id);
  CHECK(process_it != process_map_.end());
  ProcessData& process = process_it->second;

  for (const auto& module_info : module_infos) {
    auto module_it = module_map_.find(module_info.file_path());
    if (module_it == module_map_.end()) {
      const auto [inserted_it, success] = module_map_.try_emplace(
          module_info.file_path(), std::make_unique<ModuleData>(module_info));
      CHECK(success);
    } else {
      ModuleData* module = (*module_it).second.get();
      if (!module->is_loaded()) continue;
      // When a module is already loaded (has loaded symbols), it could be the case that the
      // modules base address changed. Since the module base address is *currently* saved in
      // FunctionInfo, these need to be updated.
      // TODO(169309553): As soon as module base address is not part of FunctionInfo anymore, remove
      // the following.
      if (module_info.address_start() != process.GetModuleBaseAddress(module->file_path())) {
        module->UpdateFunctionsModuleBaseAddress(module_info.address_start());
      }
    }
  }

  process.UpdateModuleInfos(module_infos);
}

void DataManager::SelectFunction(const FunctionInfo& function) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  if (!selected_functions_.contains(function)) {
    selected_functions_.insert(function);
  }
}

void DataManager::DeselectFunction(const FunctionInfo& function) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_functions_.erase(function);
}

void DataManager::set_visible_functions(absl::flat_hash_set<uint64_t> visible_functions) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  visible_functions_ = std::move(visible_functions);
}

void DataManager::set_selected_thread_id(int32_t thread_id) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_thread_id_ = thread_id;
}

bool DataManager::IsFunctionVisible(uint64_t function_address) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return visible_functions_.contains(function_address);
}

int32_t DataManager::selected_thread_id() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_thread_id_;
}

const TextBox* DataManager::selected_text_box() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_text_box_;
}

void DataManager::set_selected_text_box(const TextBox* text_box) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_text_box_ = text_box;
}

void DataManager::ClearSelectedFunctions() {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_functions_.clear();
}

const ProcessData* DataManager::GetProcessByPid(int32_t process_id) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  auto it = process_map_.find(process_id);
  if (it == process_map_.end()) {
    return nullptr;
  }

  return &it->second;
}

const ModuleData* DataManager::GetModuleByPath(const std::string& path) const {
  return GetMutableModuleByPath(path);
}

ModuleData* DataManager::GetMutableModuleByPath(const std::string& path) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  auto it = module_map_.find(path);
  if (it == module_map_.end()) {
    return nullptr;
  }

  return it->second.get();
}

bool DataManager::IsFunctionSelected(const FunctionInfo& function) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_functions_.contains(function);
}

std::vector<FunctionInfo> DataManager::GetSelectedFunctions() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return std::vector<FunctionInfo>(selected_functions_.begin(), selected_functions_.end());
}

std::vector<FunctionInfo> DataManager::GetSelectedAndOrbitFunctions() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  CHECK(selected_process_ != nullptr);

  std::vector<FunctionInfo> result = GetSelectedFunctions();

  // Collect OrbitFunctions
  for (const auto& [module_path, _] : selected_process_->GetMemoryMap()) {
    const ModuleData* module = module_map_.at(module_path).get();
    if (!module->is_loaded()) continue;

    const std::vector<FunctionInfo>& orbit_functions = module->GetOrbitFunctions();
    result.insert(result.end(), orbit_functions.begin(), orbit_functions.end());
  }

  return result;
}

void DataManager::set_selected_process(int32_t pid) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  const ProcessData* process = GetProcessByPid(pid);
  CHECK(process != nullptr);
  selected_process_ = process;
}

const ProcessData* DataManager::selected_process() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_process_;
}

void DataManager::SelectTracepoint(const TracepointInfo& info) {
  if (!IsTracepointSelected(info)) selected_tracepoints_.emplace(info);
}

void DataManager::DeselectTracepoint(const TracepointInfo& info) {
  CHECK(IsTracepointSelected(info));
  selected_tracepoints_.erase(info);
}

bool DataManager::IsTracepointSelected(const TracepointInfo& info) const {
  return selected_tracepoints_.contains(info);
}

const TracepointInfoSet& DataManager::selected_tracepoints() const { return selected_tracepoints_; }

const ModuleData* DataManager::FindModuleByAddress(int32_t process_id, uint64_t absolute_address) {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  const ProcessData* process = GetProcessByPid(process_id);
  if (process == nullptr) return nullptr;

  const auto& result = process->FindModuleByAddress(absolute_address);
  if (!result) return nullptr;

  const std::string& module_path = result.value().first;

  return module_map_.at(module_path).get();
}

const FunctionInfo* DataManager::FindFunctionByAddress(int32_t process_id,
                                                       uint64_t absolute_address,
                                                       bool is_exact) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  const ProcessData* process = GetProcessByPid(process_id);
  if (process == nullptr) return nullptr;

  const auto& result = process->FindModuleByAddress(absolute_address);
  if (!result) return nullptr;

  const std::string& module_path = result.value().first;
  const uint64_t module_base_address = result.value().second;

  const ModuleData* module = module_map_.at(module_path).get();

  const uint64_t relative_address = absolute_address - module_base_address;
  return module->FindFunctionByRelativeAddress(relative_address, is_exact);
}

[[nodiscard]] absl::flat_hash_map<std::string, ModuleData*> DataManager::GetModulesLoadedByProcess(
    const ProcessData* process) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  absl::flat_hash_map<std::string, ModuleData*> result;
  for (const auto& [module_path, _] : process->GetMemoryMap()) {
    result[module_path] = module_map_.at(module_path).get();
  }

  return result;
}<commit_msg>Fix crash because of wrong order in DataManager<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "DataManager.h"

#include "OrbitBase/Logging.h"
#include "OrbitClientData/ModuleData.h"
#include "OrbitClientData/ProcessData.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"

using orbit_client_protos::FunctionInfo;
using orbit_grpc_protos::ModuleInfo;
using orbit_grpc_protos::ProcessInfo;
using orbit_grpc_protos::TracepointInfo;

void DataManager::UpdateProcessInfos(const std::vector<ProcessInfo>& process_infos) {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  // Note that at this point the data manager does not remove old processes.
  // To do it correctly we may need to implement some callback logic here
  // since the ProcessData can be in use by some views.
  for (const ProcessInfo& info : process_infos) {
    int32_t process_id = info.pid();
    auto it = process_map_.find(process_id);
    if (it != process_map_.end()) {
      it->second.SetProcessInfo(info);
    } else {
      auto [inserted_it, success] = process_map_.try_emplace(process_id, info);
      CHECK(success);
    }
  }
}

void DataManager::UpdateModuleInfos(int32_t process_id,
                                    const std::vector<ModuleInfo>& module_infos) {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  auto process_it = process_map_.find(process_id);
  CHECK(process_it != process_map_.end());
  ProcessData& process = process_it->second;
  process.UpdateModuleInfos(module_infos);

  for (const auto& module_info : module_infos) {
    auto module_it = module_map_.find(module_info.file_path());
    if (module_it == module_map_.end()) {
      const auto [inserted_it, success] = module_map_.try_emplace(
          module_info.file_path(), std::make_unique<ModuleData>(module_info));
      CHECK(success);
    } else {
      ModuleData* module = (*module_it).second.get();
      if (!module->is_loaded()) continue;
      // When a module is already loaded (has loaded symbols), it could be the case that the
      // modules base address changed. Since the module base address is *currently* saved in
      // FunctionInfo, these need to be updated.
      // TODO(169309553): As soon as module base address is not part of FunctionInfo anymore, remove
      // the following.
      if (module_info.address_start() != process.GetModuleBaseAddress(module->file_path())) {
        module->UpdateFunctionsModuleBaseAddress(module_info.address_start());
      }
    }
  }
}

void DataManager::SelectFunction(const FunctionInfo& function) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  if (!selected_functions_.contains(function)) {
    selected_functions_.insert(function);
  }
}

void DataManager::DeselectFunction(const FunctionInfo& function) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_functions_.erase(function);
}

void DataManager::set_visible_functions(absl::flat_hash_set<uint64_t> visible_functions) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  visible_functions_ = std::move(visible_functions);
}

void DataManager::set_selected_thread_id(int32_t thread_id) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_thread_id_ = thread_id;
}

bool DataManager::IsFunctionVisible(uint64_t function_address) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return visible_functions_.contains(function_address);
}

int32_t DataManager::selected_thread_id() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_thread_id_;
}

const TextBox* DataManager::selected_text_box() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_text_box_;
}

void DataManager::set_selected_text_box(const TextBox* text_box) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_text_box_ = text_box;
}

void DataManager::ClearSelectedFunctions() {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  selected_functions_.clear();
}

const ProcessData* DataManager::GetProcessByPid(int32_t process_id) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  auto it = process_map_.find(process_id);
  if (it == process_map_.end()) {
    return nullptr;
  }

  return &it->second;
}

const ModuleData* DataManager::GetModuleByPath(const std::string& path) const {
  return GetMutableModuleByPath(path);
}

ModuleData* DataManager::GetMutableModuleByPath(const std::string& path) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  auto it = module_map_.find(path);
  if (it == module_map_.end()) {
    return nullptr;
  }

  return it->second.get();
}

bool DataManager::IsFunctionSelected(const FunctionInfo& function) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_functions_.contains(function);
}

std::vector<FunctionInfo> DataManager::GetSelectedFunctions() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return std::vector<FunctionInfo>(selected_functions_.begin(), selected_functions_.end());
}

std::vector<FunctionInfo> DataManager::GetSelectedAndOrbitFunctions() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  CHECK(selected_process_ != nullptr);

  std::vector<FunctionInfo> result = GetSelectedFunctions();

  // Collect OrbitFunctions
  for (const auto& [module_path, _] : selected_process_->GetMemoryMap()) {
    const ModuleData* module = module_map_.at(module_path).get();
    if (!module->is_loaded()) continue;

    const std::vector<FunctionInfo>& orbit_functions = module->GetOrbitFunctions();
    result.insert(result.end(), orbit_functions.begin(), orbit_functions.end());
  }

  return result;
}

void DataManager::set_selected_process(int32_t pid) {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  const ProcessData* process = GetProcessByPid(pid);
  CHECK(process != nullptr);
  selected_process_ = process;
}

const ProcessData* DataManager::selected_process() const {
  CHECK(std::this_thread::get_id() == main_thread_id_);
  return selected_process_;
}

void DataManager::SelectTracepoint(const TracepointInfo& info) {
  if (!IsTracepointSelected(info)) selected_tracepoints_.emplace(info);
}

void DataManager::DeselectTracepoint(const TracepointInfo& info) {
  CHECK(IsTracepointSelected(info));
  selected_tracepoints_.erase(info);
}

bool DataManager::IsTracepointSelected(const TracepointInfo& info) const {
  return selected_tracepoints_.contains(info);
}

const TracepointInfoSet& DataManager::selected_tracepoints() const { return selected_tracepoints_; }

const ModuleData* DataManager::FindModuleByAddress(int32_t process_id, uint64_t absolute_address) {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  const ProcessData* process = GetProcessByPid(process_id);
  if (process == nullptr) return nullptr;

  const auto& result = process->FindModuleByAddress(absolute_address);
  if (!result) return nullptr;

  const std::string& module_path = result.value().first;

  return module_map_.at(module_path).get();
}

const FunctionInfo* DataManager::FindFunctionByAddress(int32_t process_id,
                                                       uint64_t absolute_address,
                                                       bool is_exact) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  const ProcessData* process = GetProcessByPid(process_id);
  if (process == nullptr) return nullptr;

  const auto& result = process->FindModuleByAddress(absolute_address);
  if (!result) return nullptr;

  const std::string& module_path = result.value().first;
  const uint64_t module_base_address = result.value().second;

  const ModuleData* module = module_map_.at(module_path).get();

  const uint64_t relative_address = absolute_address - module_base_address;
  return module->FindFunctionByRelativeAddress(relative_address, is_exact);
}

[[nodiscard]] absl::flat_hash_map<std::string, ModuleData*> DataManager::GetModulesLoadedByProcess(
    const ProcessData* process) const {
  CHECK(std::this_thread::get_id() == main_thread_id_);

  absl::flat_hash_map<std::string, ModuleData*> result;
  for (const auto& [module_path, _] : process->GetMemoryMap()) {
    result[module_path] = module_map_.at(module_path).get();
  }

  return result;
}<|endoftext|>