<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2014, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#ifdef __linux__
#include <QDebug>
#include "LuminaOS.h"
#include <unistd.h>
#include <stdio.h> // Needed for BUFSIZ

//can't read xbrightness settings - assume invalid until set
static int screenbrightness = -1;

//OS-specific prefix(s)
QString LOS::AppPrefix(){ return "/usr/"; } //Prefix for applications
QString LOS::SysPrefix(){ return "/"; } //Prefix for system

//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return LOS::AppPrefix() + "/share/applications/synaptic.desktop"; } //graphical app/pkg manager
QString LOS::QtConfigShortcut(){ return LOS::AppPrefix() + "/bin/qtconfig"; } //qtconfig binary (NOT *.desktop file)

// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
  /* Returns: QStringList[<type>::::<filesystem>::::<path>]
     Note: <type> = [USB, HDRIVE, DVD, SDCARD, UNKNOWN]
     df is much better for this than mount, because it skips
     all non-physical devices (like bind-mounts from schroot)
     so they are not listed in lumina-fm */
  QStringList devs = LUtils::getCmdOutput("df --output=source,fstype,target");
  //Now check the output
  for(int i=0; i<devs.length(); i++){
    if(devs[i].startsWith("/dev/")){
      QString type = devs[i].section(" on ",0,0);
        type.remove("/dev/");
      //Determine the type of hardware device based on the dev node
      if(type.startsWith("sd")){ type = "HDRIVE"; }
      else if(type.startsWith("sr")){ type="DVD"; }
      else{ type = "UNKNOWN"; }
      //Now put the device in the proper output format
      devs[i] = type+"::::"+devs[i].section("(",1,1).section(",",0,0)+"::::"+devs[i].section(" on ",1,50).section("(",0,0).simplified();
    }else{
      //invalid device - remove it from the list
      devs.removeAt(i);
      i--;
    }
  }
  return devs;
}

//Read screen brightness information
int LOS::ScreenBrightness(){
   //Returns: Screen Brightness as a percentage (0-100, with -1 for errors)
  if(screenbrightness==-1){
    if(QFile::exists(QDir::homePath()+"/.lumina/.currentxbrightness")){
      int val = LUtils::readFile(QDir::homePath()+"/.lumina/.currentxbrightness").join("").simplified().toInt();
      screenbrightness = val;
    }
  }
  return screenbrightness;

}

//Set screen brightness
void LOS::setScreenBrightness(int percent){
  //ensure bounds
  if(percent<0){percent=0;}
  else if(percent>100){ percent=100; }
  // float pf = percent/100.0; //convert to a decimel
  //Run the command
  QString cmd = "xbacklight -set %1";
  // cmd = cmd.arg( QString::number( int(65535*pf) ) );
  cmd = cmd.arg( QString::number( percent ) );
  int ret = LUtils::runCmd(cmd);
  //Save the result for later
  if(ret!=0){ screenbrightness = -1; }
  else{ screenbrightness = percent; }
  LUtils::writeFile(QDir::homePath()+"/.lumina/.currentxbrightness", QStringList() << QString::number(screenbrightness), true);

}

//Read the current volume
int LOS::audioVolume(){ //Returns: audio volume as a percentage (0-100, with -1 for errors)
QString info = LUtils::getCmdOutput("amixer get Master").join("").simplified();;
  int out = -1;
  int start_position, end_position;
  QString current_volume;
  if(!info.isEmpty()){
     start_position = info.indexOf("[");
     start_position++;
     end_position = info.indexOf("%");
     current_volume = info.mid(start_position, end_position - start_position);
     out = current_volume.toInt();
  }
  return out;

}

//Set the current volume
void LOS::setAudioVolume(int percent){
  if(percent<0){percent=0;}
  else if(percent>100){percent=100;}
  QString info = "amixer -c 0 sset Master,0 " + QString::number(percent) + "%";
  if(!info.isEmpty()){
    //Run Command
    LUtils::runCmd(info);
  }

}

//Change the current volume a set amount (+ or -)
void LOS::changeAudioVolume(int percentdiff){
  int old_volume = audioVolume();
  int new_volume = old_volume + percentdiff;
  if (new_volume < 0)
      new_volume = 0;
  if (new_volume > 100)
      new_volume = 100;
  qDebug() << "Setting new volume to: " << new_volume;
  setAudioVolume(new_volume);
}

//Check if a graphical audio mixer is installed
bool LOS::hasMixerUtility(){
  return QFile::exists(LOS::AppPrefix() + "bin/pavucontrol");
}

//Launch the graphical audio mixer utility
void LOS::startMixerUtility(){
  QProcess::startDetached(LOS::AppPrefix() + "bin/pavucontrol");
}

//Check for user system permission (shutdown/restart)
bool LOS::userHasShutdownAccess(){
  return true; //not implemented yet
}

//System Shutdown
void LOS::systemShutdown(){ //start poweroff sequence
  QProcess::startDetached("shutdown -h now");
}

//System Restart
void LOS::systemRestart(){ //start reboot sequence
  QProcess::startDetached("shutdown -r now");
}

//Battery Availability
bool LOS::hasBattery(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool no_battery = my_status.contains("No support");
  if (no_battery) return false;
  return true;
}

//Battery Charge Level
int LOS::batteryCharge(){ //Returns: percent charge (0-100), anything outside that range is counted as an error
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  int my_start = my_status.indexOf("%");
  // get the number right before the % sign
  int my_end = my_start;
  my_start--;
  while ( (my_status[my_start] != ' ') && (my_start > 0) )
      my_start--;
  my_start++;
  int my_charge = my_status.mid(my_start, my_end - my_start).toInt();
  if ( (my_charge < 0) || (my_charge > 100) ) return -1;
  return my_charge;
}

//Battery Charging State
// Many possible values are returned if the laptop is plugged in
// these include "Unknown, Full and No support.
// However, it seems just one status is returned when running
// on battery and that is "Discharging". So if the value we get
// is NOT Discharging then we assume the battery is charging.
bool LOS::batteryIsCharging(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool discharging = my_status.contains("Discharging");
  if (discharging) return false;
  return true;
}

//Battery Time Remaining
int LOS::batterySecondsLeft(){ //Returns: estimated number of seconds remaining
  return 0; //not implemented yet for Linux
}

#endif
<commit_msg>fixup device detection in LuminaOS-Debian<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2014, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#ifdef __linux__
#include <QDebug>
#include "LuminaOS.h"
#include <unistd.h>
#include <stdio.h> // Needed for BUFSIZ

//can't read xbrightness settings - assume invalid until set
static int screenbrightness = -1;

//OS-specific prefix(s)
QString LOS::AppPrefix(){ return "/usr/"; } //Prefix for applications
QString LOS::SysPrefix(){ return "/"; } //Prefix for system

//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return LOS::AppPrefix() + "/share/applications/synaptic.desktop"; } //graphical app/pkg manager
QString LOS::QtConfigShortcut(){ return LOS::AppPrefix() + "/bin/qtconfig"; } //qtconfig binary (NOT *.desktop file)

// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
  /* Returns: QStringList[<type>::::<filesystem>::::<path>]
     Note: <type> = [USB, HDRIVE, DVD, SDCARD, UNKNOWN]
     df is much better for this than mount, because it skips
     all non-physical devices (like bind-mounts from schroot)
     so they are not listed in lumina-fm */
  QStringList devs = LUtils::getCmdOutput("df --output=source,fstype,target");
  //Now check the output
  for(int i=0; i<devs.length(); i++){
    if(devs[i].startsWith("/dev/")){
      devs[i] = devs[i].simplified();
      QString type = devs[i].section(" on ",0,0);
      type.remove("/dev/");
      //Determine the type of hardware device based on the dev node
      if(type.startsWith("sd")){ type = "HDRIVE"; }
      else if(type.startsWith("sr")){ type="DVD"; }
      else if(type.contains("mapper")){ type="LVM"; }
      else{ type = "UNKNOWN"; }
      //Now put the device in the proper output format
      devs[i] = type + "::::" + devs[i].section(" ",1,1) + "::::" + devs[i].section(" ",2,2);
    }else{
      //invalid device - remove it from the list
      devs.removeAt(i);
      i--;
    }
  }
  return devs;
}

//Read screen brightness information
int LOS::ScreenBrightness(){
   //Returns: Screen Brightness as a percentage (0-100, with -1 for errors)
  if(screenbrightness==-1){
    if(QFile::exists(QDir::homePath()+"/.lumina/.currentxbrightness")){
      int val = LUtils::readFile(QDir::homePath()+"/.lumina/.currentxbrightness").join("").simplified().toInt();
      screenbrightness = val;
    }
  }
  return screenbrightness;

}

//Set screen brightness
void LOS::setScreenBrightness(int percent){
  //ensure bounds
  if(percent<0){percent=0;}
  else if(percent>100){ percent=100; }
  // float pf = percent/100.0; //convert to a decimel
  //Run the command
  QString cmd = "xbacklight -set %1";
  // cmd = cmd.arg( QString::number( int(65535*pf) ) );
  cmd = cmd.arg( QString::number( percent ) );
  int ret = LUtils::runCmd(cmd);
  //Save the result for later
  if(ret!=0){ screenbrightness = -1; }
  else{ screenbrightness = percent; }
  LUtils::writeFile(QDir::homePath()+"/.lumina/.currentxbrightness", QStringList() << QString::number(screenbrightness), true);

}

//Read the current volume
int LOS::audioVolume(){ //Returns: audio volume as a percentage (0-100, with -1 for errors)
QString info = LUtils::getCmdOutput("amixer get Master").join("").simplified();;
  int out = -1;
  int start_position, end_position;
  QString current_volume;
  if(!info.isEmpty()){
     start_position = info.indexOf("[");
     start_position++;
     end_position = info.indexOf("%");
     current_volume = info.mid(start_position, end_position - start_position);
     out = current_volume.toInt();
  }
  return out;

}

//Set the current volume
void LOS::setAudioVolume(int percent){
  if(percent<0){percent=0;}
  else if(percent>100){percent=100;}
  QString info = "amixer -c 0 sset Master,0 " + QString::number(percent) + "%";
  if(!info.isEmpty()){
    //Run Command
    LUtils::runCmd(info);
  }

}

//Change the current volume a set amount (+ or -)
void LOS::changeAudioVolume(int percentdiff){
  int old_volume = audioVolume();
  int new_volume = old_volume + percentdiff;
  if (new_volume < 0)
      new_volume = 0;
  if (new_volume > 100)
      new_volume = 100;
  qDebug() << "Setting new volume to: " << new_volume;
  setAudioVolume(new_volume);
}

//Check if a graphical audio mixer is installed
bool LOS::hasMixerUtility(){
  return QFile::exists(LOS::AppPrefix() + "bin/pavucontrol");
}

//Launch the graphical audio mixer utility
void LOS::startMixerUtility(){
  QProcess::startDetached(LOS::AppPrefix() + "bin/pavucontrol");
}

//Check for user system permission (shutdown/restart)
bool LOS::userHasShutdownAccess(){
  return true; //not implemented yet
}

//System Shutdown
void LOS::systemShutdown(){ //start poweroff sequence
  QProcess::startDetached("shutdown -h now");
}

//System Restart
void LOS::systemRestart(){ //start reboot sequence
  QProcess::startDetached("shutdown -r now");
}

//Battery Availability
bool LOS::hasBattery(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool no_battery = my_status.contains("No support");
  if (no_battery) return false;
  return true;
}

//Battery Charge Level
int LOS::batteryCharge(){ //Returns: percent charge (0-100), anything outside that range is counted as an error
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  int my_start = my_status.indexOf("%");
  // get the number right before the % sign
  int my_end = my_start;
  my_start--;
  while ( (my_status[my_start] != ' ') && (my_start > 0) )
      my_start--;
  my_start++;
  int my_charge = my_status.mid(my_start, my_end - my_start).toInt();
  if ( (my_charge < 0) || (my_charge > 100) ) return -1;
  return my_charge;
}

//Battery Charging State
// Many possible values are returned if the laptop is plugged in
// these include "Unknown, Full and No support.
// However, it seems just one status is returned when running
// on battery and that is "Discharging". So if the value we get
// is NOT Discharging then we assume the battery is charging.
bool LOS::batteryIsCharging(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool discharging = my_status.contains("Discharging");
  if (discharging) return false;
  return true;
}

//Battery Time Remaining
int LOS::batterySecondsLeft(){ //Returns: estimated number of seconds remaining
  return 0; //not implemented yet for Linux
}

#endif
<|endoftext|>


<commit_before>// -*- c-basic-offset: 2 -*-

#include "kfoldertree.h"
#include <klocale.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <qpainter.h>
#include <qapplication.h>
#include <qheader.h>
#include <qstyle.h>

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTree *parent, const QString & label,
				  Protocol protocol, Type type )
  : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
    mUnread(-1), mTotal(0)
{
}

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTreeItem *parent,
				  const QString & label, Protocol protocol, Type type,
          int unread, int total )
    : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
      mUnread( unread ), mTotal( total )
{
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::protocolSortingKey() const
{
  // protocol dependant sorting order:
  // local < imap < news < search < other
  switch ( mProtocol ) {
  case Local:
    return 1;
  case CachedImap:
  case Imap:
    return 2;
  case News:
    return 3;
  case Search:
    return 4;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::typeSortingKey() const
{
  // type dependant sorting order:
  // inbox < outbox < sent-mail < trash < drafts
  // < calendar < contacts < notes < tasks
  // < normal folders
  switch ( mType ) {
  case Inbox:
    return 1;
  case Outbox:
    return 2;
  case SentMail:
    return 3;
  case Trash:
    return 4;
  case Drafts:
    return 5;
  case Calendar:
    return 6;
  case Contacts:
    return 7;
  case Notes:
    return 8;
  case Tasks:
    return 9;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::compare( QListViewItem * i, int col, bool ) const
{
  KFolderTreeItem* other = static_cast<KFolderTreeItem*>( i );

  if (col == 0)
  {
    // sort by folder

    // local root-folder
    if ( depth() == 0 && mProtocol == NONE )
      return -1;
    if ( other->depth() == 0 && other->protocol() == NONE )
      return 1;

    // first compare by protocol
    int thisKey = protocolSortingKey();
    int thatKey = other->protocolSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // then compare by type
    thisKey = typeSortingKey();
    thatKey = other->typeSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // and finally compare by name
    return text( 0 ).localeAwareCompare( other->text( 0 ) );
  }
  else
  {
    // sort by unread or total-column
    int a = 0, b = 0;
    if (col == static_cast<KFolderTree*>(listView())->unreadIndex())
    {
      a = mUnread;
      b = other->unreadCount();
    }
    else if (col == static_cast<KFolderTree*>(listView())->totalIndex())
    {
      a = mTotal;
      b = other->totalCount();
    }

    if ( a == b )
      return 0;
    else
      return (a < b ? -1 : 1);
  }
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setUnreadCount( int aUnread )
{
  if ( aUnread < 0 ) return;

  mUnread = aUnread;

  QString unread = QString::null;
  if (mUnread == 0)
    unread = "- ";
  else {
    unread.setNum(mUnread);
    unread += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->unreadIndex(),
      unread );
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setTotalCount( int aTotal )
{
  if ( aTotal < 0 ) return;

  mTotal = aTotal;

  QString total = QString::null;
  if (mTotal == 0)
    total = "- ";
  else {
    total.setNum(mTotal);
    total += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->totalIndex(),
      total );
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::countUnreadRecursive()
{
  int count = (mUnread > 0) ? mUnread : 0;

  for ( QListViewItem *item = firstChild() ;
      item ; item = item->nextSibling() )
  {
    count += static_cast<KFolderTreeItem*>(item)->countUnreadRecursive();
  }

  return count;
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::paintCell( QPainter * p, const QColorGroup & cg,
                                  int column, int width, int align )
{
  KFolderTree *ft = static_cast<KFolderTree*>(listView());

  const int unreadRecursiveCount = countUnreadRecursive();
  const int unreadCount = ( mUnread > 0 ) ? mUnread : 0;

  /* The below is exceedingly silly, but Ingo insists that the unread
   * count that is shown in parenthesis after the folder name must
   * be configurable in color. That means that paintCell needs to do
   * two painting passes which flickers. Since that flicker is not
   * needed when there is the unread column, special case that. */
  if ( ft->isUnreadActive() ) {
    if ( (column == 0 || column == ft->unreadIndex())
          && ( unreadCount > 0 || ( !isOpen() && unreadRecursiveCount > 0 ) ) )
    {
      QFont f = p->font();
      f.setWeight(QFont::Bold);
      p->setFont(f);
    }
    KListViewItem::paintCell( p, cg, column, width, align );
  } else {
    QListView *lv = listView();
    QString oldText = text(column);

    // set an empty text so that we can have our own implementation (see further down)
    // but still benefit from KListView::paintCell
    setText( column, "" );

    KListViewItem::paintCell( p, cg, column, width, align );

    int r = lv ? lv->itemMargin() : 1;
    const QPixmap *icon = pixmap( column );
    int marg = lv ? lv->itemMargin() : 1;

    QString t;
    QRect br;
    setText( column, oldText );
    if ( isSelected() )
      p->setPen( cg.highlightedText() );
    else
      p->setPen( ft->paintInfo().colFore );

    if ( icon ) {
      r += icon->width() + lv->itemMargin();
    }
    t = text( column );
    if ( !t.isEmpty() )
    {
      // use a bold-font for the folder- and the unread-columns
      if ( (column == 0 || column == ft->unreadIndex())
            && ( unreadCount > 0
                 || ( !isOpen() && unreadRecursiveCount > 0 ) ) )
      {
        QFont f = p->font();
        f.setWeight(QFont::Bold);
        p->setFont(f);
      }
      p->drawText( r, 0, width-marg-r, height(),
          align | AlignVCenter, t, -1, &br );
      if (!isSelected())
        p->setPen( ft->paintInfo().colUnread );
      if (column == 0) {
        // draw the unread-count if the unread-column is not active
        QString unread;

        if ( !ft->isUnreadActive()
             && ( unreadCount > 0
                  || ( !isOpen() && unreadRecursiveCount > 0 ) ) ) {
          if ( isOpen() )
            unread = " (" + QString::number( unreadCount ) + ")";
          else if ( unreadRecursiveCount == unreadCount || mType == Root )
            unread = " (" + QString::number( unreadRecursiveCount ) + ")";
          else
            unread = " (" + QString::number( unreadCount ) + " + " +
                     QString::number( unreadRecursiveCount-unreadCount ) + ")";

          p->drawText( br.right(), 0, width-marg-br.right(), height(),
                       align | AlignVCenter, unread );
        }
      }
    } // end !t.isEmpty()
  }
}

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

KFolderTree::KFolderTree( QWidget *parent, const char* name )
  : KListView( parent, name ), mUnreadIndex(-1), mTotalIndex(-1)
{
  // GUI-options
  setStyleDependantFrameWidth();
  setAcceptDrops(true);
  setDropVisualizer(false);
  setAllColumnsShowFocus(true);
  setShowSortIndicator(true);
  setUpdatesEnabled(true);
  setItemsRenameable(false);
  setRootIsDecorated(true);
  setSelectionModeExt(Extended);
  setAlternateBackground(QColor());
  setFullWidth(true);
  disableAutoSelection();
}

//-----------------------------------------------------------------------------
void KFolderTree::setStyleDependantFrameWidth()
{
  // set the width of the frame to a reasonable value for the current GUI style
  int frameWidth;
  if( style().isA("KeramikStyle") )
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
  else
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth );
  if ( frameWidth < 0 )
    frameWidth = 0;
  if ( frameWidth != lineWidth() )
    setLineWidth( frameWidth );
}

//-----------------------------------------------------------------------------
void KFolderTree::styleChange( QStyle& oldStyle )
{
  setStyleDependantFrameWidth();
  KListView::styleChange( oldStyle );
}

//-----------------------------------------------------------------------------
void KFolderTree::drawContentsOffset( QPainter * p, int ox, int oy,
                                       int cx, int cy, int cw, int ch )
{
  bool oldUpdatesEnabled = isUpdatesEnabled();
  setUpdatesEnabled(false);
  KListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
  setUpdatesEnabled(oldUpdatesEnabled);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMousePressEvent( QMouseEvent *e )
{
    setSelectionModeExt(Single);
    KListView::contentsMousePressEvent(e);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMouseReleaseEvent( QMouseEvent *e )
{
    KListView::contentsMouseReleaseEvent(e);
    setSelectionModeExt(Extended);
}

//-----------------------------------------------------------------------------
void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk )
{
  int oldSize = mAcceptableDropMimetypes.size();
  mAcceptableDropMimetypes.resize(oldSize+1);
  mAcceptOutside.resize(oldSize+1);

  mAcceptableDropMimetypes.at(oldSize) =  mimeType;
  mAcceptOutside.setBit(oldSize, outsideOk);
}

//-----------------------------------------------------------------------------
bool KFolderTree::acceptDrag( QDropEvent* event ) const
{
  QListViewItem* item = itemAt(contentsToViewport(event->pos()));

  for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++)
  {
    if (event->provides(mAcceptableDropMimetypes[i]))
    {
      if (item)
        return (static_cast<KFolderTreeItem*>(item))->acceptDrag(event);
      else
        return mAcceptOutside[i];
    }
  }
  return false;
}

//-----------------------------------------------------------------------------
void KFolderTree::addUnreadColumn( const QString & name, int width )
{
  mUnreadIndex = addColumn( name, width );
  setColumnAlignment( mUnreadIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
}

//-----------------------------------------------------------------------------
void KFolderTree::addTotalColumn( const QString & name, int width )
{
  mTotalIndex = addColumn( name, width );
  setColumnAlignment( mTotalIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
}

//-----------------------------------------------------------------------------
void KFolderTree::removeUnreadColumn()
{
  if ( !isUnreadActive() ) return;
  removeColumn( mUnreadIndex );
  if ( isTotalActive() && mTotalIndex > mUnreadIndex )
    mTotalIndex--;
  mUnreadIndex = -1;
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::removeTotalColumn()
{
  if ( !isTotalActive() ) return;
  removeColumn( mTotalIndex );
  if ( isUnreadActive() && mTotalIndex < mUnreadIndex )
    mUnreadIndex--;
  mTotalIndex = -1;
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::setFullWidth( bool fullWidth )
{
  if (fullWidth)
    header()->setStretchEnabled( true, 0 );
}

#include "kfoldertree.moc"
<commit_msg>Resize the headers when adding the total or unread column.<commit_after>// -*- c-basic-offset: 2 -*-

#include "kfoldertree.h"
#include <klocale.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <qpainter.h>
#include <qapplication.h>
#include <qheader.h>
#include <qstyle.h>

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTree *parent, const QString & label,
				  Protocol protocol, Type type )
  : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
    mUnread(-1), mTotal(0)
{
}

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTreeItem *parent,
				  const QString & label, Protocol protocol, Type type,
          int unread, int total )
    : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
      mUnread( unread ), mTotal( total )
{
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::protocolSortingKey() const
{
  // protocol dependant sorting order:
  // local < imap < news < search < other
  switch ( mProtocol ) {
  case Local:
    return 1;
  case CachedImap:
  case Imap:
    return 2;
  case News:
    return 3;
  case Search:
    return 4;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::typeSortingKey() const
{
  // type dependant sorting order:
  // inbox < outbox < sent-mail < trash < drafts
  // < calendar < contacts < notes < tasks
  // < normal folders
  switch ( mType ) {
  case Inbox:
    return 1;
  case Outbox:
    return 2;
  case SentMail:
    return 3;
  case Trash:
    return 4;
  case Drafts:
    return 5;
  case Calendar:
    return 6;
  case Contacts:
    return 7;
  case Notes:
    return 8;
  case Tasks:
    return 9;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::compare( QListViewItem * i, int col, bool ) const
{
  KFolderTreeItem* other = static_cast<KFolderTreeItem*>( i );

  if (col == 0)
  {
    // sort by folder

    // local root-folder
    if ( depth() == 0 && mProtocol == NONE )
      return -1;
    if ( other->depth() == 0 && other->protocol() == NONE )
      return 1;

    // first compare by protocol
    int thisKey = protocolSortingKey();
    int thatKey = other->protocolSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // then compare by type
    thisKey = typeSortingKey();
    thatKey = other->typeSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // and finally compare by name
    return text( 0 ).localeAwareCompare( other->text( 0 ) );
  }
  else
  {
    // sort by unread or total-column
    int a = 0, b = 0;
    if (col == static_cast<KFolderTree*>(listView())->unreadIndex())
    {
      a = mUnread;
      b = other->unreadCount();
    }
    else if (col == static_cast<KFolderTree*>(listView())->totalIndex())
    {
      a = mTotal;
      b = other->totalCount();
    }

    if ( a == b )
      return 0;
    else
      return (a < b ? -1 : 1);
  }
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setUnreadCount( int aUnread )
{
  if ( aUnread < 0 ) return;

  mUnread = aUnread;

  QString unread = QString::null;
  if (mUnread == 0)
    unread = "- ";
  else {
    unread.setNum(mUnread);
    unread += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->unreadIndex(),
      unread );
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setTotalCount( int aTotal )
{
  if ( aTotal < 0 ) return;

  mTotal = aTotal;

  QString total = QString::null;
  if (mTotal == 0)
    total = "- ";
  else {
    total.setNum(mTotal);
    total += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->totalIndex(),
      total );
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::countUnreadRecursive()
{
  int count = (mUnread > 0) ? mUnread : 0;

  for ( QListViewItem *item = firstChild() ;
      item ; item = item->nextSibling() )
  {
    count += static_cast<KFolderTreeItem*>(item)->countUnreadRecursive();
  }

  return count;
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::paintCell( QPainter * p, const QColorGroup & cg,
                                  int column, int width, int align )
{
  KFolderTree *ft = static_cast<KFolderTree*>(listView());

  const int unreadRecursiveCount = countUnreadRecursive();
  const int unreadCount = ( mUnread > 0 ) ? mUnread : 0;

  /* The below is exceedingly silly, but Ingo insists that the unread
   * count that is shown in parenthesis after the folder name must
   * be configurable in color. That means that paintCell needs to do
   * two painting passes which flickers. Since that flicker is not
   * needed when there is the unread column, special case that. */
  if ( ft->isUnreadActive() ) {
    if ( (column == 0 || column == ft->unreadIndex())
          && ( unreadCount > 0 || ( !isOpen() && unreadRecursiveCount > 0 ) ) )
    {
      QFont f = p->font();
      f.setWeight(QFont::Bold);
      p->setFont(f);
    }
    KListViewItem::paintCell( p, cg, column, width, align );
  } else {
    QListView *lv = listView();
    QString oldText = text(column);

    // set an empty text so that we can have our own implementation (see further down)
    // but still benefit from KListView::paintCell
    setText( column, "" );

    KListViewItem::paintCell( p, cg, column, width, align );

    int r = lv ? lv->itemMargin() : 1;
    const QPixmap *icon = pixmap( column );
    int marg = lv ? lv->itemMargin() : 1;

    QString t;
    QRect br;
    setText( column, oldText );
    if ( isSelected() )
      p->setPen( cg.highlightedText() );
    else
      p->setPen( ft->paintInfo().colFore );

    if ( icon ) {
      r += icon->width() + lv->itemMargin();
    }
    t = text( column );
    if ( !t.isEmpty() )
    {
      // use a bold-font for the folder- and the unread-columns
      if ( (column == 0 || column == ft->unreadIndex())
            && ( unreadCount > 0
                 || ( !isOpen() && unreadRecursiveCount > 0 ) ) )
      {
        QFont f = p->font();
        f.setWeight(QFont::Bold);
        p->setFont(f);
      }
      p->drawText( r, 0, width-marg-r, height(),
          align | AlignVCenter, t, -1, &br );
      if (!isSelected())
        p->setPen( ft->paintInfo().colUnread );
      if (column == 0) {
        // draw the unread-count if the unread-column is not active
        QString unread;

        if ( !ft->isUnreadActive()
             && ( unreadCount > 0
                  || ( !isOpen() && unreadRecursiveCount > 0 ) ) ) {
          if ( isOpen() )
            unread = " (" + QString::number( unreadCount ) + ")";
          else if ( unreadRecursiveCount == unreadCount || mType == Root )
            unread = " (" + QString::number( unreadRecursiveCount ) + ")";
          else
            unread = " (" + QString::number( unreadCount ) + " + " +
                     QString::number( unreadRecursiveCount-unreadCount ) + ")";

          p->drawText( br.right(), 0, width-marg-br.right(), height(),
                       align | AlignVCenter, unread );
        }
      }
    } // end !t.isEmpty()
  }
}

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

KFolderTree::KFolderTree( QWidget *parent, const char* name )
  : KListView( parent, name ), mUnreadIndex(-1), mTotalIndex(-1)
{
  // GUI-options
  setStyleDependantFrameWidth();
  setAcceptDrops(true);
  setDropVisualizer(false);
  setAllColumnsShowFocus(true);
  setShowSortIndicator(true);
  setUpdatesEnabled(true);
  setItemsRenameable(false);
  setRootIsDecorated(true);
  setSelectionModeExt(Extended);
  setAlternateBackground(QColor());
  setFullWidth(true);
  disableAutoSelection();
}

//-----------------------------------------------------------------------------
void KFolderTree::setStyleDependantFrameWidth()
{
  // set the width of the frame to a reasonable value for the current GUI style
  int frameWidth;
  if( style().isA("KeramikStyle") )
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
  else
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth );
  if ( frameWidth < 0 )
    frameWidth = 0;
  if ( frameWidth != lineWidth() )
    setLineWidth( frameWidth );
}

//-----------------------------------------------------------------------------
void KFolderTree::styleChange( QStyle& oldStyle )
{
  setStyleDependantFrameWidth();
  KListView::styleChange( oldStyle );
}

//-----------------------------------------------------------------------------
void KFolderTree::drawContentsOffset( QPainter * p, int ox, int oy,
                                       int cx, int cy, int cw, int ch )
{
  bool oldUpdatesEnabled = isUpdatesEnabled();
  setUpdatesEnabled(false);
  KListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
  setUpdatesEnabled(oldUpdatesEnabled);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMousePressEvent( QMouseEvent *e )
{
    setSelectionModeExt(Single);
    KListView::contentsMousePressEvent(e);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMouseReleaseEvent( QMouseEvent *e )
{
    KListView::contentsMouseReleaseEvent(e);
    setSelectionModeExt(Extended);
}

//-----------------------------------------------------------------------------
void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk )
{
  int oldSize = mAcceptableDropMimetypes.size();
  mAcceptableDropMimetypes.resize(oldSize+1);
  mAcceptOutside.resize(oldSize+1);

  mAcceptableDropMimetypes.at(oldSize) =  mimeType;
  mAcceptOutside.setBit(oldSize, outsideOk);
}

//-----------------------------------------------------------------------------
bool KFolderTree::acceptDrag( QDropEvent* event ) const
{
  QListViewItem* item = itemAt(contentsToViewport(event->pos()));

  for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++)
  {
    if (event->provides(mAcceptableDropMimetypes[i]))
    {
      if (item)
        return (static_cast<KFolderTreeItem*>(item))->acceptDrag(event);
      else
        return mAcceptOutside[i];
    }
  }
  return false;
}

//-----------------------------------------------------------------------------
void KFolderTree::addUnreadColumn( const QString & name, int width )
{
  mUnreadIndex = addColumn( name, width );
  setColumnAlignment( mUnreadIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::addTotalColumn( const QString & name, int width )
{
  mTotalIndex = addColumn( name, width );
  setColumnAlignment( mTotalIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::removeUnreadColumn()
{
  if ( !isUnreadActive() ) return;
  removeColumn( mUnreadIndex );
  if ( isTotalActive() && mTotalIndex > mUnreadIndex )
    mTotalIndex--;
  mUnreadIndex = -1;
}

//-----------------------------------------------------------------------------
void KFolderTree::removeTotalColumn()
{
  if ( !isTotalActive() ) return;
  removeColumn( mTotalIndex );
  if ( isUnreadActive() && mTotalIndex < mUnreadIndex )
    mUnreadIndex--;
  mTotalIndex = -1;
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::setFullWidth( bool fullWidth )
{
  if (fullWidth)
    header()->setStretchEnabled( true, 0 );
}

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


<commit_before>#include "GLBlaat/GL.h"

#include "NQVTKWidget.h"
#include "NQVTKWidget.moc"

#include "NQVTK/Math/Vector3.h"

#include "NQVTK/Rendering/Camera.h"
#include "NQVTK/Rendering/Renderer.h"
#include "NQVTK/Rendering/NestedRenderer.h"
#include "NQVTK/Rendering/Camera.h"
#include "NQVTK/Interactors/Interactor.h"

#include <QMouseEvent>
#include <QGLFormat>

#include <algorithm>
#include <cassert>

// ----------------------------------------------------------------------------
NQVTKWidget *NQVTKWidget::shareWidget = 0;

// ----------------------------------------------------------------------------
NQVTKWidget::NQVTKWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::AlphaChannel), parent, NQVTKWidget::shareWidget),
renderer(0), interactor(0)
{
	setMouseTracking(true);
	crosshairOn = false;

	// Set the singleton if this is the first NQVTKWidget
	if (!NQVTKWidget::shareWidget)
	{
		NQVTKWidget::shareWidget = this;
	}
}

// ----------------------------------------------------------------------------
NQVTKWidget::~NQVTKWidget()
{
	delete interactor;
	if (renderer)
	{
		makeCurrent();
		delete renderer;
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::SetRenderer(NQVTK::Renderer *renderer)
{
	assert(!this->renderer);
	this->renderer = renderer;
}

// ----------------------------------------------------------------------------
NQVTK::Renderer *NQVTKWidget::GetRenderer(bool getInner)
{
	NQVTK::Renderer *ren = renderer;
	if (getInner)
	{
		// Loop to remove all layers
		NQVTK::NestedRenderer *nren;
		do
		{
			nren = dynamic_cast<NQVTK::NestedRenderer*>(ren);
			if (nren) ren = nren->GetBaseRenderer();
		}
		while (nren);
	}

	return ren;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::SetInteractor(NQVTK::Interactor *interactor)
{
	assert(!this->interactor);
	this->interactor = interactor;
	interactor->ResizeEvent(this->width(), this->height());
}

// ----------------------------------------------------------------------------
void NQVTKWidget::StartContinuousUpdate()
{
	// Render-on-idle timer
	startTimer(0);
	// FPS display timer
	fpsTimerId = startTimer(1000);
	frames = 0;
}

// ----------------------------------------------------------------------------
bool NQVTKWidget::Initialize()
{
	glInit();
	return isValid();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::ResetShareWidget(NQVTKWidget *shareWidget)
{
	NQVTKWidget::shareWidget = shareWidget;
}

// ----------------------------------------------------------------------------
QImage NQVTKWidget::GrabHighRes(int magnification)
{
	QImage result(magnification * width(), magnification * height(),
		QImage::Format_ARGB32);
	unsigned char *resData = result.bits();
	for (int j = 0; j < magnification; ++j)
	{
		double jitterY = static_cast<double>(j) /
			static_cast<double>(magnification);
		for (int i = 0; i < magnification; ++i)
		{
			double jitterX = -static_cast<double>(i) /
				static_cast<double>(magnification);
			renderer->SetCameraJitter(jitterX, jitterY);
			// Force an update
			makeCurrent();
			paintGL();
			swapBuffers();
			// Grab the result and copy to the large image
			QImage img = grabFrameBuffer(true);
			for (int y = 0; y < img.height(); ++y)
			{
				unsigned char *data = img.scanLine(y);
				int outY = magnification * y + j;
				for (int x = 0; x < img.width(); ++x)
				{
					int outX = magnification * x + i;
					int outPixel = outX + outY * magnification * width();
					for (int comp = 0; comp < 4; ++comp)
					{
						resData[4 * outPixel + comp] = data[4 * x + comp];
					}
				}
			}
		}
	}
	// Set jitter back to normal
	renderer->SetCameraJitter(0.0, 0.0);
	updateGL();

	return result;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::toggleCrosshair(bool on)
{
	crosshairOn = on;
	updateGL();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::setCrosshairPos(double x, double y)
{
	crosshairX = x; crosshairY = y;
	updateGL();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::syncCamera(NQVTK::Camera *cam)
{
	if (!renderer) return;
	renderer->GetCamera()->position = cam->position;
	renderer->GetCamera()->focus = cam->focus;
	renderer->GetCamera()->up = cam->up;
	updateGL();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::initializeGL()
{
	// TODO: add support for multiple contexts
	// GLBlaat should support this (on the GLEW side), as well as NQVTK. This
	// involves splitting all GL-side resources and managing them separately,
	// with multiple instances (one per context) per renderable, volume, ...
	if (glewInit() != GLEW_OK)
	{
		qDebug("Failed to initialize GLEW!");
		return;
	}

	qDebug("Initializing renderer...");
	if (renderer)
	{
		renderer->TryInitialize();
		if (!renderer->IsInitialized())
		{
			qDebug("Failed to initialize renderer...");
		}
	}
	else
	{
		qDebug("Renderer not set!");
	}
	qDebug("Init done!");
}

// ----------------------------------------------------------------------------
void NQVTKWidget::resizeGL(int w, int h)
{
	if (!renderer) return;
	renderer->Resize(w, h);
	if (interactor) interactor->ResizeEvent(w, h);
	if (renderer->IsInitialized())
	{
		emit cameraUpdated(GetRenderer()->GetCamera());
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::paintGL()
{
	// Draw if we can and are visible, otherwise just clear the screen
	// NOTE: Call both Initialize and Resize before calling Draw on a Renderer
	// The second of these is only called when the widget is shown
	if (renderer != 0 && renderer->IsInitialized() && isVisible())
	{
		renderer->Draw();

		NQVTK::Camera *camera = renderer->GetCamera();

		// Draw crosshairs
		if (crosshairOn)
		{
			double x = (crosshairX / renderer->GetCamera()->aspect) +
				2.0 * camera->jitterX;
			double y = -crosshairY + 2.0 * camera->jitterY;

			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();

			glPushAttrib(GL_ALL_ATTRIB_BITS);

			glDisable(GL_DEPTH_TEST);
			glDisable(GL_LIGHTING);

			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
			glEnable(GL_BLEND);

			glBegin(GL_LINES);
			glColor4d(1.0, 0.0, 0.0, 0.7);
			glVertex2d(x, -1.0);
			glVertex2d(x, 1.0);
			glVertex2d(-1.0, y);
			glVertex2d(1.0, y);
			glEnd();

			glPopAttrib();
		}
	}
	else
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		// Dark red shows something went wrong
		glClearColor(0.5, 0.0, 0.0, 0.0);
		glClear(GL_COLOR_BUFFER_BIT);
		glPopAttrib();
	}

	// Increase fps count
	++frames;
}

// ----------------------------------------------------------------------------
NQVTK::MouseEvent NQVTKWidget::translateMouseEvent(QMouseEvent *event)
{
	NQVTK::MouseEvent ev;
	// Translate button
	int button = 0;
	switch (event->button())
	{
	case Qt::LeftButton:
		button = NQVTK::MouseEvent::LeftButton;
		break;
	case Qt::RightButton:
		button = NQVTK::MouseEvent::RightButton;
		break;
	case Qt::MidButton:
		button = NQVTK::MouseEvent::MiddleButton;
		break;
	}
	// Translate buttons state
	int buttons = 0;
	if (event->buttons() & Qt::LeftButton)
		buttons |= NQVTK::MouseEvent::LeftButton;
	if (event->buttons() & Qt::RightButton)
		buttons |= NQVTK::MouseEvent::RightButton;
	if (event->buttons() & Qt::MidButton)
		buttons |= NQVTK::MouseEvent::MiddleButton;
	// Build event
	ev.button = button;
	ev.buttons = buttons;
	ev.x = event->x();
	ev.y = event->y();
	ev.control = event->modifiers() & Qt::ControlModifier;
	ev.shift = event->modifiers() & Qt::ShiftModifier;
	ev.alt = event->modifiers() & Qt::AltModifier;
	return ev;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::timerEvent(QTimerEvent *event)
{
	if (event->timerId() == fpsTimerId)
	{
		// Update FPS display
		emit fpsChanged(frames);
		frames = 0;
	}
	else
	{
		// Update on idle
		updateGL();
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mouseMoveEvent(QMouseEvent *event)
{
	// Ignore events if initialization failed
	if (renderer == 0 || !renderer->IsInitialized())
	{
		event->ignore();
		return;
	}

	// Pass the event to the interactor
	if (interactor)
	{
		if (interactor->MouseMoveEvent(translateMouseEvent(event)))
		{
			// TODO: this should probably not be emitted for each mouse event
			emit cameraUpdated(GetRenderer()->GetCamera());
			event->accept();
			updateGL();
		}
		else
		{
			event->ignore();
		}
	}

	// Compute projection-neutral coordinates
	double x = (2.0 * static_cast<double>(event->x()) / this->width() - 1.0) *
		GetRenderer()->GetCamera()->aspect;
	double y = 2.0 * static_cast<double>(event->y()) / this->height() - 1.0;
	emit cursorPosChanged(x, y);
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mousePressEvent(QMouseEvent *event)
{
	// Ignore events if initialization failed
	if (renderer == 0 || !renderer->IsInitialized())
	{
		event->ignore();
		return;
	}

	// Pass the event to the interactor
	if (interactor)
	{
		if (interactor->MousePressEvent(translateMouseEvent(event)))
		{
			event->accept();
			updateGL();
		}
		else
		{
			event->ignore();
		}
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mouseReleaseEvent(QMouseEvent *event)
{
	// Ignore events if initialization failed
	if (renderer == 0 || !renderer->IsInitialized())
	{
		event->ignore();
		return;
	}

	// Pass the event to the interactor
	if (interactor)
	{
		if (interactor->MouseReleaseEvent(translateMouseEvent(event)))
		{
			event->accept();
			updateGL();
		}
		else
		{
			event->ignore();
		}
	}
}
<commit_msg>Fixed crosshair jittering.<commit_after>#include "GLBlaat/GL.h"

#include "NQVTKWidget.h"
#include "NQVTKWidget.moc"

#include "NQVTK/Math/Vector3.h"

#include "NQVTK/Rendering/Camera.h"
#include "NQVTK/Rendering/Renderer.h"
#include "NQVTK/Rendering/NestedRenderer.h"
#include "NQVTK/Rendering/Camera.h"
#include "NQVTK/Interactors/Interactor.h"

#include <QMouseEvent>
#include <QGLFormat>

#include <algorithm>
#include <cassert>

// ----------------------------------------------------------------------------
NQVTKWidget *NQVTKWidget::shareWidget = 0;

// ----------------------------------------------------------------------------
NQVTKWidget::NQVTKWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::AlphaChannel), parent, NQVTKWidget::shareWidget),
renderer(0), interactor(0)
{
	setMouseTracking(true);
	crosshairOn = false;

	// Set the singleton if this is the first NQVTKWidget
	if (!NQVTKWidget::shareWidget)
	{
		NQVTKWidget::shareWidget = this;
	}
}

// ----------------------------------------------------------------------------
NQVTKWidget::~NQVTKWidget()
{
	delete interactor;
	if (renderer)
	{
		makeCurrent();
		delete renderer;
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::SetRenderer(NQVTK::Renderer *renderer)
{
	assert(!this->renderer);
	this->renderer = renderer;
}

// ----------------------------------------------------------------------------
NQVTK::Renderer *NQVTKWidget::GetRenderer(bool getInner)
{
	NQVTK::Renderer *ren = renderer;
	if (getInner)
	{
		// Loop to remove all layers
		NQVTK::NestedRenderer *nren;
		do
		{
			nren = dynamic_cast<NQVTK::NestedRenderer*>(ren);
			if (nren) ren = nren->GetBaseRenderer();
		}
		while (nren);
	}

	return ren;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::SetInteractor(NQVTK::Interactor *interactor)
{
	assert(!this->interactor);
	this->interactor = interactor;
	interactor->ResizeEvent(this->width(), this->height());
}

// ----------------------------------------------------------------------------
void NQVTKWidget::StartContinuousUpdate()
{
	// Render-on-idle timer
	startTimer(0);
	// FPS display timer
	fpsTimerId = startTimer(1000);
	frames = 0;
}

// ----------------------------------------------------------------------------
bool NQVTKWidget::Initialize()
{
	glInit();
	return isValid();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::ResetShareWidget(NQVTKWidget *shareWidget)
{
	NQVTKWidget::shareWidget = shareWidget;
}

// ----------------------------------------------------------------------------
QImage NQVTKWidget::GrabHighRes(int magnification)
{
	QImage result(magnification * width(), magnification * height(),
		QImage::Format_ARGB32);
	unsigned char *resData = result.bits();
	for (int j = 0; j < magnification; ++j)
	{
		double jitterY = static_cast<double>(j) /
			static_cast<double>(magnification);
		for (int i = 0; i < magnification; ++i)
		{
			double jitterX = -static_cast<double>(i) /
				static_cast<double>(magnification);
			renderer->SetCameraJitter(jitterX, jitterY);
			// Force an update
			makeCurrent();
			paintGL();
			swapBuffers();
			// Grab the result and copy to the large image
			QImage img = grabFrameBuffer(true);
			for (int y = 0; y < img.height(); ++y)
			{
				unsigned char *data = img.scanLine(y);
				int outY = magnification * y + j;
				for (int x = 0; x < img.width(); ++x)
				{
					int outX = magnification * x + i;
					int outPixel = outX + outY * magnification * width();
					for (int comp = 0; comp < 4; ++comp)
					{
						resData[4 * outPixel + comp] = data[4 * x + comp];
					}
				}
			}
		}
	}
	// Set jitter back to normal
	renderer->SetCameraJitter(0.0, 0.0);
	updateGL();

	return result;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::toggleCrosshair(bool on)
{
	crosshairOn = on;
	updateGL();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::setCrosshairPos(double x, double y)
{
	crosshairX = x; crosshairY = y;
	updateGL();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::syncCamera(NQVTK::Camera *cam)
{
	if (!renderer) return;
	renderer->GetCamera()->position = cam->position;
	renderer->GetCamera()->focus = cam->focus;
	renderer->GetCamera()->up = cam->up;
	updateGL();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::initializeGL()
{
	// TODO: add support for multiple contexts
	// GLBlaat should support this (on the GLEW side), as well as NQVTK. This
	// involves splitting all GL-side resources and managing them separately,
	// with multiple instances (one per context) per renderable, volume, ...
	if (glewInit() != GLEW_OK)
	{
		qDebug("Failed to initialize GLEW!");
		return;
	}

	qDebug("Initializing renderer...");
	if (renderer)
	{
		renderer->TryInitialize();
		if (!renderer->IsInitialized())
		{
			qDebug("Failed to initialize renderer...");
		}
	}
	else
	{
		qDebug("Renderer not set!");
	}
	qDebug("Init done!");
}

// ----------------------------------------------------------------------------
void NQVTKWidget::resizeGL(int w, int h)
{
	if (!renderer) return;
	renderer->Resize(w, h);
	if (interactor) interactor->ResizeEvent(w, h);
	if (renderer->IsInitialized())
	{
		emit cameraUpdated(GetRenderer()->GetCamera());
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::paintGL()
{
	// Draw if we can and are visible, otherwise just clear the screen
	// NOTE: Call both Initialize and Resize before calling Draw on a Renderer
	// The second of these is only called when the widget is shown
	if (renderer != 0 && renderer->IsInitialized() && isVisible())
	{
		renderer->Draw();

		NQVTK::Camera *camera = renderer->GetCamera();

		// Draw crosshairs
		if (crosshairOn)
		{
			double x = (crosshairX / renderer->GetCamera()->aspect) +
				camera->jitterX;
			double y = -crosshairY + camera->jitterY;

			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();

			glPushAttrib(GL_ALL_ATTRIB_BITS);

			glDisable(GL_DEPTH_TEST);
			glDisable(GL_LIGHTING);
			glLineWidth(1.0f);

			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
			glEnable(GL_BLEND);

			glBegin(GL_LINES);
			glColor4d(1.0, 0.0, 0.0, 0.7);
			glVertex2d(x, -1.0);
			glVertex2d(x, 1.0);
			glVertex2d(-1.0, y);
			glVertex2d(1.0, y);
			glEnd();

			glPopAttrib();
		}
	}
	else
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		// Dark red shows something went wrong
		glClearColor(0.5, 0.0, 0.0, 0.0);
		glClear(GL_COLOR_BUFFER_BIT);
		glPopAttrib();
	}

	// Increase fps count
	++frames;
}

// ----------------------------------------------------------------------------
NQVTK::MouseEvent NQVTKWidget::translateMouseEvent(QMouseEvent *event)
{
	NQVTK::MouseEvent ev;
	// Translate button
	int button = 0;
	switch (event->button())
	{
	case Qt::LeftButton:
		button = NQVTK::MouseEvent::LeftButton;
		break;
	case Qt::RightButton:
		button = NQVTK::MouseEvent::RightButton;
		break;
	case Qt::MidButton:
		button = NQVTK::MouseEvent::MiddleButton;
		break;
	}
	// Translate buttons state
	int buttons = 0;
	if (event->buttons() & Qt::LeftButton)
		buttons |= NQVTK::MouseEvent::LeftButton;
	if (event->buttons() & Qt::RightButton)
		buttons |= NQVTK::MouseEvent::RightButton;
	if (event->buttons() & Qt::MidButton)
		buttons |= NQVTK::MouseEvent::MiddleButton;
	// Build event
	ev.button = button;
	ev.buttons = buttons;
	ev.x = event->x();
	ev.y = event->y();
	ev.control = event->modifiers() & Qt::ControlModifier;
	ev.shift = event->modifiers() & Qt::ShiftModifier;
	ev.alt = event->modifiers() & Qt::AltModifier;
	return ev;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::timerEvent(QTimerEvent *event)
{
	if (event->timerId() == fpsTimerId)
	{
		// Update FPS display
		emit fpsChanged(frames);
		frames = 0;
	}
	else
	{
		// Update on idle
		updateGL();
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mouseMoveEvent(QMouseEvent *event)
{
	// Ignore events if initialization failed
	if (renderer == 0 || !renderer->IsInitialized())
	{
		event->ignore();
		return;
	}

	// Pass the event to the interactor
	if (interactor)
	{
		if (interactor->MouseMoveEvent(translateMouseEvent(event)))
		{
			// TODO: this should probably not be emitted for each mouse event
			emit cameraUpdated(GetRenderer()->GetCamera());
			event->accept();
			updateGL();
		}
		else
		{
			event->ignore();
		}
	}

	// Compute projection-neutral coordinates
	double x = (2.0 * static_cast<double>(event->x()) / this->width() - 1.0) *
		GetRenderer()->GetCamera()->aspect;
	double y = 2.0 * static_cast<double>(event->y()) / this->height() - 1.0;
	emit cursorPosChanged(x, y);
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mousePressEvent(QMouseEvent *event)
{
	// Ignore events if initialization failed
	if (renderer == 0 || !renderer->IsInitialized())
	{
		event->ignore();
		return;
	}

	// Pass the event to the interactor
	if (interactor)
	{
		if (interactor->MousePressEvent(translateMouseEvent(event)))
		{
			event->accept();
			updateGL();
		}
		else
		{
			event->ignore();
		}
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mouseReleaseEvent(QMouseEvent *event)
{
	// Ignore events if initialization failed
	if (renderer == 0 || !renderer->IsInitialized())
	{
		event->ignore();
		return;
	}

	// Pass the event to the interactor
	if (interactor)
	{
		if (interactor->MouseReleaseEvent(translateMouseEvent(event)))
		{
			event->accept();
			updateGL();
		}
		else
		{
			event->ignore();
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Revert "Fix relative rotation in ChLinkMarkers so that it always uses a quaternion with positive e0"<commit_after><|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "Class.h"

#include "../types/SymbolProviderType.h"
#include "../types/ClassType.h"
#include "Project.h"

#include "ModelBase/src/nodes/TypedListDefinition.h"
DEFINE_TYPED_LIST(OOModel::Class)

namespace OOModel {

COMPOSITENODE_DEFINE_EMPTY_CONSTRUCTORS(Class)
COMPOSITENODE_DEFINE_TYPE_REGISTRATION_METHODS(Class)

REGISTER_ATTRIBUTE(Class, baseClasses, TypedListOfExpression, false, false, true)
REGISTER_ATTRIBUTE(Class, friends, TypedListOfExpression, false, false, true)
REGISTER_ATTRIBUTE(Class, typeArguments, TypedListOfFormalTypeArgument, false, false, true)
REGISTER_ATTRIBUTE(Class, classes, TypedListOfClass, false, false, true)
REGISTER_ATTRIBUTE(Class, methods, TypedListOfMethod, false, false, true)
REGISTER_ATTRIBUTE(Class, fields, TypedListOfField, false, false, true)
REGISTER_ATTRIBUTE(Class, enumerators, TypedListOfEnumerator, false, false, true)
REGISTER_ATTRIBUTE(Class, cKind, Integer, false, false, true)

Class::Class(const QString& name)
: Super(nullptr, Class::getMetaData())
{
	setName(name);
	setConstructKind(ConstructKind::Class);
}

Class::Class(const QString& name, ConstructKind kind)
: Super(nullptr, Class::getMetaData())
{
	setName(name);
	setConstructKind(kind);
}

Class::Class(const QString& name, Modifier::Modifiers mod, ConstructKind kind)
: Super(nullptr, Class::getMetaData())
{
	setName(name);
	modifiers()->set(mod);
	setConstructKind(kind);
}

Class::SymbolTypes Class::symbolType() const
{
	return CONTAINER;
}

bool Class::isGeneric()
{
	return typeArguments()->size() > 0;
}

inline bool Class::findInTarget(Expression* target, QSet<Node*>& result, const Model::SymbolMatcher& matcher,
		SymbolTypes symbolTypes, bool exhaustAllScopes) const
{
	bool found = false;
	auto t = target->type();
	if (auto sp = dynamic_cast<SymbolProviderType*>(t))
	{

		if (sp->symbolProvider() && sp->symbolProvider() != this)
			found = sp->symbolProvider()->findSymbols(result, matcher, sp->symbolProvider(), SEARCH_DOWN,
				symbolTypes, exhaustAllScopes);
	}
	SAFE_DELETE(t);
	return found;
}

bool Class::findSymbols(QSet<Node*>& result, const Model::SymbolMatcher& matcher, const Node* source,
				FindSymbolDirection direction, SymbolTypes symbolTypes, bool exhaustAllScopes) const
{
	bool found{};

	if (direction == SEARCH_HERE)
	{
		if (symbolMatches(matcher, symbolTypes))
		{
			found = true;
			result.insert(const_cast<Class*>(this));
		}
	}
	else if (direction == SEARCH_DOWN)
	{
		for (auto c : childrenInScope())
		{
			if (c != typeArguments() && c != friends())
				found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;
		}

		// Look in base classes
		if (exhaustAllScopes || !found)
		{
			if (baseClasses()->size() == 0)
			{
				if (auto implicit = defaultImplicitBaseFromProject())
					found = findInTarget(implicit, result, matcher, symbolTypes, exhaustAllScopes) || found;
			}
			else
				for (auto bc : *baseClasses())
					found = findInTarget(bc, result, matcher, symbolTypes, exhaustAllScopes) || found;
		}
	}
	else if (direction == SEARCH_UP)
	{
		auto ignore = childToSubnode(source);
		for (auto c : childrenInScope())
			if (c != ignore) // Optimize the search by skipping this scope, since we've already searched there
				found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;

		// Look in base classes, but only if we are not trying to resolve a base class name
		ignore = baseClasses()->childToSubnode(source);
		if (!ignore && (exhaustAllScopes || !found))
		{
			if (baseClasses()->size() == 0)
			{
				if (auto implicit = defaultImplicitBaseFromProject())
					found = findInTarget(implicit, result, matcher, symbolTypes, exhaustAllScopes) || found;
			}
			else
				for (auto bc : *baseClasses())
					found = findInTarget(bc, result, matcher, symbolTypes, exhaustAllScopes) || found;
		}

		if ((exhaustAllScopes || !found) && symbolMatches(matcher, symbolTypes))
		{
			found = true;
			result.insert(const_cast<Class*>(this));
		}

		if ((exhaustAllScopes || !found) && parent())
			found = parent()->findSymbols(result, matcher, source, SEARCH_UP, symbolTypes, exhaustAllScopes) || found;
	}

	return found;
}

Expression* Class::defaultImplicitBaseFromProject() const
{
	auto p = parent();
	while (p)
	{
		if (auto proj = DCast<Project>(p))
		{
			if (constructKind() != ConstructKind::Enum && proj->implicitBaseType()) return proj->implicitBaseType();
			if (constructKind() == ConstructKind::Enum && proj->implicitEnumType()) return proj->implicitEnumType();
		}
		p = p->parent();
	}
	return nullptr;
}

QSet<Class*> Class::allBaseClasses()
{
	QSet<Class*> bases;

	for (auto base : *baseClasses())
	{
		auto type = base->type();
		auto ct = dynamic_cast<ClassType*>(type);
		if (ct)
		{
			bases.insert(ct->classDefinition());
			bases.unite(ct->classDefinition()->allBaseClasses());
		}

		SAFE_DELETE(type);
	}

	if (baseClasses()->isEmpty())
	{
		if (auto classDef = implicitBaseFromProject())
		{
				bases.insert(classDef);
				bases.unite(classDef->allBaseClasses());
		}
	}

	return bases;
}

QSet<Class*> Class::directBaseClasses()
{
	QSet<Class*> result;
	for (auto baseClass : *baseClasses())
		if (auto asClass = expressionToClass(baseClass))
			result << asClass;
	if (implicitBaseFromProject())
		result << implicitBaseFromProject();
	return result;
}

Class* Class::implicitBaseFromProject() const
{
	if (auto classDef = expressionToClass(defaultImplicitBaseFromProject()))
	{
		if (this != classDef) return classDef;
	}

	return nullptr;
}

Class* Class::expressionToClass(Expression* expr)
{
	if (expr)
	{
		auto type = std::unique_ptr<Type>(expr->type());
		if (auto ct = dynamic_cast<ClassType*>(type.get()))
			return ct->classDefinition();
	}
	return nullptr;
}

QSet<Class*> Class::directSubClasses()
{
	auto top = root();
	//Find all the classes where this method is subclasses
	QSet<Class*> result;
	QList<Model::Node*> toCheck;
	toCheck.append(top);
	while (!toCheck.isEmpty())
	{
		auto check = toCheck.takeLast();
		if (auto clazz = DCast<Class>(check))
			if (clazz->directBaseClasses().contains(this))
				result << clazz;
		toCheck.append(check->children());
	}
	return result;
}

}
<commit_msg>Changes to class<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "Class.h"

#include "../types/SymbolProviderType.h"
#include "../types/ClassType.h"
#include "Project.h"

#include "ModelBase/src/nodes/TypedListDefinition.h"
DEFINE_TYPED_LIST(OOModel::Class)

namespace OOModel {

COMPOSITENODE_DEFINE_EMPTY_CONSTRUCTORS(Class)
COMPOSITENODE_DEFINE_TYPE_REGISTRATION_METHODS(Class)

REGISTER_ATTRIBUTE(Class, baseClasses, TypedListOfExpression, false, false, true)
REGISTER_ATTRIBUTE(Class, friends, TypedListOfExpression, false, false, true)
REGISTER_ATTRIBUTE(Class, typeArguments, TypedListOfFormalTypeArgument, false, false, true)
REGISTER_ATTRIBUTE(Class, classes, TypedListOfClass, false, false, true)
REGISTER_ATTRIBUTE(Class, methods, TypedListOfMethod, false, false, true)
REGISTER_ATTRIBUTE(Class, fields, TypedListOfField, false, false, true)
REGISTER_ATTRIBUTE(Class, enumerators, TypedListOfEnumerator, false, false, true)
REGISTER_ATTRIBUTE(Class, cKind, Integer, false, false, true)

Class::Class(const QString& name)
: Super(nullptr, Class::getMetaData())
{
	setName(name);
	setConstructKind(ConstructKind::Class);
}

Class::Class(const QString& name, ConstructKind kind)
: Super(nullptr, Class::getMetaData())
{
	setName(name);
	setConstructKind(kind);
}

Class::Class(const QString& name, Modifier::Modifiers mod, ConstructKind kind)
: Super(nullptr, Class::getMetaData())
{
	setName(name);
	modifiers()->set(mod);
	setConstructKind(kind);
}

Class::SymbolTypes Class::symbolType() const
{
	return CONTAINER;
}

bool Class::isGeneric()
{
	return typeArguments()->size() > 0;
}

inline bool Class::findInTarget(Expression* target, QSet<Node*>& result, const Model::SymbolMatcher& matcher,
		SymbolTypes symbolTypes, bool exhaustAllScopes) const
{
	bool found = false;
	auto t = target->type();
	if (auto sp = dynamic_cast<SymbolProviderType*>(t))
	{

		if (sp->symbolProvider() && sp->symbolProvider() != this)
			found = sp->symbolProvider()->findSymbols(result, matcher, sp->symbolProvider(), SEARCH_DOWN,
				symbolTypes, exhaustAllScopes);
	}
	SAFE_DELETE(t);
	return found;
}

bool Class::findSymbols(QSet<Node*>& result, const Model::SymbolMatcher& matcher, const Node* source,
				FindSymbolDirection direction, SymbolTypes symbolTypes, bool exhaustAllScopes) const
{
	bool found{};

	if (direction == SEARCH_HERE)
	{
		if (symbolMatches(matcher, symbolTypes))
		{
			found = true;
			result.insert(const_cast<Class*>(this));
		}
	}
	else if (direction == SEARCH_DOWN)
	{
		for (auto c : childrenInScope())
		{
			if (c != typeArguments() && c != friends())
				found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;
		}

		// Look in base classes
		if (exhaustAllScopes || !found)
		{
			if (baseClasses()->size() == 0)
			{
				if (auto implicit = defaultImplicitBaseFromProject())
					found = findInTarget(implicit, result, matcher, symbolTypes, exhaustAllScopes) || found;
			}
			else
				for (auto bc : *baseClasses())
					found = findInTarget(bc, result, matcher, symbolTypes, exhaustAllScopes) || found;
		}
	}
	else if (direction == SEARCH_UP)
	{
		auto ignore = childToSubnode(source);
		for (auto c : childrenInScope())
			if (c != ignore) // Optimize the search by skipping this scope, since we've already searched there
				found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;

		// Look in base classes, but only if we are not trying to resolve a base class name
		ignore = baseClasses()->childToSubnode(source);
		if (!ignore && (exhaustAllScopes || !found))
		{
			if (baseClasses()->size() == 0)
			{
				if (auto implicit = defaultImplicitBaseFromProject())
					found = findInTarget(implicit, result, matcher, symbolTypes, exhaustAllScopes) || found;
			}
			else
				for (auto bc : *baseClasses())
					found = findInTarget(bc, result, matcher, symbolTypes, exhaustAllScopes) || found;
		}

		if ((exhaustAllScopes || !found) && symbolMatches(matcher, symbolTypes))
		{
			found = true;
			result.insert(const_cast<Class*>(this));
		}

		if ((exhaustAllScopes || !found) && parent())
			found = parent()->findSymbols(result, matcher, source, SEARCH_UP, symbolTypes, exhaustAllScopes) || found;
	}

	return found;
}

Expression* Class::defaultImplicitBaseFromProject() const
{
	auto p = parent();
	while (p)
	{
		if (auto proj = DCast<Project>(p))
		{
			if (constructKind() != ConstructKind::Enum && proj->implicitBaseType()) return proj->implicitBaseType();
			if (constructKind() == ConstructKind::Enum && proj->implicitEnumType()) return proj->implicitEnumType();
		}
		p = p->parent();
	}
	return nullptr;
}

QSet<Class*> Class::allBaseClasses()
{
	QSet<Class*> bases;

	for (auto base : *baseClasses())
	{
		auto type = base->type();
		auto ct = dynamic_cast<ClassType*>(type);
		if (ct)
		{
			bases.insert(ct->classDefinition());
			bases.unite(ct->classDefinition()->allBaseClasses());
		}

		SAFE_DELETE(type);
	}

	if (baseClasses()->isEmpty())
	{
		if (auto classDef = implicitBaseFromProject())
		{
				bases.insert(classDef);
				bases.unite(classDef->allBaseClasses());
		}
	}

	return bases;
}

QSet<Class*> Class::directBaseClasses()
{
	QSet<Class*> result;
	for (auto baseClass : *baseClasses())
		if (auto asClass = expressionToClass(baseClass))
			result << asClass;
	if (implicitBaseFromProject() && result.isEmpty())
		result << implicitBaseFromProject();
	return result;
}

Class* Class::implicitBaseFromProject() const
{
	if (auto classDef = expressionToClass(defaultImplicitBaseFromProject()))
	{
		if (this != classDef) return classDef;
	}

	return nullptr;
}

Class* Class::expressionToClass(Expression* expr)
{
	if (expr)
	{
		auto type = std::unique_ptr<Type>(expr->type());
		if (auto ct = dynamic_cast<ClassType*>(type.get()))
			return ct->classDefinition();
	}
	return nullptr;
}

QSet<Class*> Class::directSubClasses()
{
	auto top = root();
	//Find all the classes where this method is subclasses
	QSet<Class*> result;
	QList<Model::Node*> toCheck;
	toCheck.append(top);
	while (!toCheck.isEmpty())
	{
		auto check = toCheck.takeLast();
		if (auto someClass = DCast<Class>(check))
			if (someClass->directBaseClasses().contains(this))
				result << someClass;
		toCheck.append(check->children());
	}
	return result;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qPlatform_Linux
#include    <execinfo.h>
#include    <unistd.h>
#elif   qPlatform_Windows
#include    <Windows.h>
#endif

#include    "../Characters/LineEndings.h"
#include    "../Characters/StringBuilder.h"
#include    "../Execution/Finally.h"

#include    "BackTrace.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;

/*
 ********************************************************************************
 ********************************* Debug::BackTrace *****************************
 ********************************************************************************
 */
wstring    Debug::BackTrace (unsigned int maxFrames)
{
#if     qPlatform_Linux
    // @see http://man7.org/linux/man-pages/man3/backtrace.3.html
    constexpr   size_t  kMaxStackSize_  =   100;        // could look at return size and re-run if equals exactly...
    // @todo combine maxFrames with trial and error on backtrace() calls
    void* stackTraceBuf[kMaxStackSize_] {};
    int nptrs = ::backtrace (stackTraceBuf, NEltsOf (stackTraceBuf));
    char**   syms = ::backtrace_symbols (stackTraceBuf, nptrs);
    if (syms == NULL) {
        //DbgTrace ("%d errno", errno); // perror("backtrace_symbols");
        return wstring {};
    }
    auto&&      cleanup =   Execution::Finally ([syms] () noexcept { if (syms != nullptr) ::free (syms); });
    wstring     out;
    for (int j = 0; j < nptrs; j++) {
        wstring symStr;
        for (const char* p = syms[j]; *p != '\0'; ++p) {
            symStr += *p;
        }
        out += symStr + L";" + Characters::GetEOL<wchar_t> ();
    }
    return out;
#else
    return wstring {};
#endif
}
<commit_msg>hopefully simplified Debug/BackTrace.cpp code<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qPlatform_Linux
#include    <execinfo.h>
#include    <unistd.h>
#elif   qPlatform_Windows
#include    <Windows.h>
#endif

#include    "../Characters/LineEndings.h"
#include    "../Characters/StringBuilder.h"
#include    "../Execution/Finally.h"

#include    "BackTrace.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;

/*
 ********************************************************************************
 ********************************* Debug::BackTrace *****************************
 ********************************************************************************
 */
wstring    Debug::BackTrace (unsigned int maxFrames)
{
#if     qPlatform_Linux
    // @see http://man7.org/linux/man-pages/man3/backtrace.3.html
    constexpr   size_t  kMaxStackSize_  =   100;        // could look at return size and re-run if equals exactly...
    // @todo combine maxFrames with trial and error on backtrace() calls
    void* stackTraceBuf[kMaxStackSize_] {};
    int nptrs = ::backtrace (stackTraceBuf, NEltsOf (stackTraceBuf));
    char**   syms = ::backtrace_symbols (stackTraceBuf, nptrs);
    if (syms == NULL) {
        //DbgTrace ("%d errno", errno); // perror("backtrace_symbols");
        return wstring {};
    }
    auto&&      cleanup =   Execution::Finally ([syms] () noexcept { if (syms != nullptr) ::free (syms); });
    wstring     out;
    for (int j = 0; j < nptrs; j++) {
        wstring symStr	=	 syms[j];
        out += symStr + L";" + Characters::GetEOL<wchar_t> ();
    }
    return out;
#else
    return wstring {};
#endif
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_Range_inl_
#define _Stroika_Foundation_Traversal_Range_inl_

#include    "../Debug/Assertions.h"
#include    "../Math/Overlap.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

            /*
             ********************************************************************************
             RangeTraits::ExplicitRangeTraits_Integral<T, MIN, MAX, LOWER_BOUND_OPEN, UPPER_BOUND_OPEN, SIGNED_DIFF_TYPE, UNSIGNED_DIFF_TYPE>
             ********************************************************************************
             */
#if     qCompilerAndStdLib_constexpr_StaticDataMember_Buggy
            template    <typename T, T MIN, T MAX , Openness LOWER_BOUND_OPEN, Openness UPPER_BOUND_OPEN, typename SIGNED_DIFF_TYPE, typename UNSIGNED_DIFF_TYPE>
            const T RangeTraits::ExplicitRangeTraits_Integral<T, MIN, MAX, LOWER_BOUND_OPEN, UPPER_BOUND_OPEN, SIGNED_DIFF_TYPE, UNSIGNED_DIFF_TYPE>::kLowerBound   =   MIN;
            template    <typename T, T MIN, T MAX , Openness LOWER_BOUND_OPEN, Openness UPPER_BOUND_OPEN, typename SIGNED_DIFF_TYPE, typename UNSIGNED_DIFF_TYPE>
            const T RangeTraits::ExplicitRangeTraits_Integral<T, MIN, MAX, LOWER_BOUND_OPEN, UPPER_BOUND_OPEN, SIGNED_DIFF_TYPE, UNSIGNED_DIFF_TYPE>::kUpperBound   =   MAX;
#endif

            /*
             ********************************************************************************
             ****************** RangeTraits::DefaultRangeTraits<T> **************************
             ********************************************************************************
             */
#if     qCompilerAndStdLib_constexpr_StaticDataMember_Buggy
            template    <typename T>
            const T RangeTraits::DefaultRangeTraits<T>::kLowerBound   =   numeric_limits<T>::lowest ();
            template    <typename T>
            const T RangeTraits::DefaultRangeTraits<T>::kUpperBound   =   numeric_limits<T>::max ();
#endif

            /*
             ********************************************************************************
             ***************************** Range<T, TRAITS> *********************************
             ********************************************************************************
             */
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>::Range ()
                : fBegin_ (TRAITS::kUpperBound)
                , fEnd_ (TRAITS::kLowerBound)
            {
                Require  (TRAITS::kLowerBound <= TRAITS::kUpperBound);    // always required for class
                Require (TRAITS::kLowerBound != TRAITS::kUpperBound);     // you cannot make an empty range if min=max
                Ensure (empty ());
            }
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>::Range (const T& begin, const T& end)
                : fBegin_ (begin)
                , fEnd_ (end)
            {
                Require  (TRAITS::kLowerBound <= TRAITS::kUpperBound);    // always required for class
                Require (TRAITS::kLowerBound <= begin);
                Require (begin <= end);
                Require (end <= TRAITS::kUpperBound);
            }
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>::Range (const Memory::Optional<T>& begin, const Memory::Optional<T>& end)
                : fBegin_ (begin.IsPresent () ? *begin : TRAITS::kLowerBound)
                , fEnd_ (end.IsPresent () ? *end : TRAITS::kUpperBound)
            {
                Require  (TRAITS::kLowerBound <= TRAITS::kUpperBound);    // always required for class
                Require (TRAITS::kLowerBound <= fBegin_);
                Require (fBegin_ <= fEnd_);
                Require (fEnd_ <= TRAITS::kUpperBound);
            }
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>    Range<T, TRAITS>::FullRange ()
            {
                return Range<T, TRAITS> (TRAITS::kLowerBound, TRAITS::kUpperBound);
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::empty () const
            {
                if (fBegin_ > fEnd_) {
                    // internal hack done in Range<T, TRAITS>::Range() - empty range - otherwise not possible to create this situation
                    return true;
                }
                else if (fBegin_ == fEnd_) {
                    return TRAITS::kLowerBoundOpenness == Openness::eOpen and TRAITS::kUpperBoundOpenness == Openness::eOpen;
                }
                return false;
            }
            template    <typename T, typename TRAITS>
            inline  typename TRAITS::UnsignedDifferenceType    Range<T, TRAITS>::GetDistanceSpanned () const
            {
                if (empty ()) {
                    return 0;
                }
                return fEnd_ - fBegin_;
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::Contains (const T& r) const
            {
                if (empty ()) {
                    return false;
                }
                if (fBegin_ < r and r < fEnd_) {
                    return true;
                }
                if (TRAITS::kLowerBoundOpenness == Openness::eClosed and r == fBegin_) {
                    return true;
                }
                if (TRAITS::kUpperBoundOpenness == Openness::eClosed and r == fEnd_) {
                    return true;
                }
                return false;
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::Equals (const Range<T, TRAITS>& rhs) const
            {
                if (empty ()) {
                    return rhs.empty ();
                }
                return fBegin_ == rhs.fBegin_ and fEnd_ == rhs.fEnd_;
            }
#if 0
            template    <typename T, typename TRAITS>
            bool    Range<T, TRAITS>::Overlaps (const Range<T, TRAITS>& rhs) const
            {
                /*
                 *  @todo   RETHINK - because Range has semantics of exclude end - make sure overlap usuage
                 *          here is correct??? Unsure -- LGP 2013-07-05
                 */
                return Math::Overlaps (
                           pair<T, T> (fBegin_, fEnd_),
                           pair<T, T> (rhs.fBegin_, rhs.fEnd_)
                       );
            }
#endif
            template    <typename T, typename TRAITS>
            Range<T, TRAITS> Range<T, TRAITS>::Intersection (const Range<T, TRAITS>& rhs) const
            {
                if (empty () or rhs.empty ()) {
                    return Range ();
                }
                T   l   =   max (fBegin_, rhs.fBegin_);
                T   r   =   min (fEnd_, rhs.fEnd_);
                if (l <= r) {
                    return Range<T, TRAITS> (l, r);
                }
                else {
                    return Range ();
                }
            }
            template    <typename T, typename TRAITS>
            Range<T, TRAITS> Range<T, TRAITS>::UnionBounds (const Range<T, TRAITS>& rhs) const
            {
                if (empty ()) {
                    return rhs;
                }
                if (rhs.empty ()) {
                    return *this;
                }
                Range<T, TRAITS>    result  =   Range<T, TRAITS> (min (GetLowerBound (), rhs.GetLowerBound ()), max (GetUpperBound (), rhs.GetUpperBound ()));
                Ensure (result.GetLowerBound () <= GetLowerBound ());
                Ensure (result.GetLowerBound () <= GetUpperBound ());
                Ensure (result.GetLowerBound () <= rhs.GetLowerBound ());
                Ensure (result.GetLowerBound () <= rhs.GetUpperBound ());
                Ensure (result.GetUpperBound () >= GetLowerBound ());
                Ensure (result.GetUpperBound () >= GetUpperBound ());
                Ensure (result.GetUpperBound () >= rhs.GetLowerBound ());
                Ensure (result.GetUpperBound () >= rhs.GetUpperBound ());
                return result;
            }
            template    <typename T, typename TRAITS>
            inline  T    Range<T, TRAITS>::GetLowerBound () const
            {
                Require (not empty ());
                return fBegin_;
            }
            template    <typename T, typename TRAITS>
            inline  T    Range<T, TRAITS>::GetUpperBound () const
            {
                Require (not empty ());
                return fEnd_;
            }
            template    <typename T, typename TRAITS>
            inline     Openness    Range<T, TRAITS>::GetTraitsLowerBoundOpenness ()
            {
                return TRAITS::kLowerBoundOpenness;
            }
            template    <typename T, typename TRAITS>
            inline     Openness    Range<T, TRAITS>::GetTraitsUpperBoundOpenness ()
            {
                return TRAITS::kUpperBoundOpenness;
            }
            template    <typename T, typename TRAITS>
            inline     T    Range<T, TRAITS>::GetTraitsLowerBound ()
            {
                return TRAITS::kLowerBound;
            }
            template    <typename T, typename TRAITS>
            inline     T    Range<T, TRAITS>::GetTraitsUpperBound ()
            {
                return TRAITS::kUpperBound;
            }
            template    <typename T, typename TRAITS>
            template    <typename... ARGS>
            inline  Characters::String  Range<T, TRAITS>::Format (ARGS&& ... args) const
            {
                return GetLowerBound ().Format (forward<ARGS> (args)...) + L" - " + GetUpperBound  ().Format (forward<ARGS> (args)...);
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::operator== (const Range<T, TRAITS>& rhs) const
            {
                return Equals (rhs);
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::operator!= (const Range<T, TRAITS>& rhs) const
            {
                return not Equals (rhs);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_Range_inl_ */
<commit_msg>tweaks to Range<T, TRAITS>::Format () for when upper==lowerbound<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_Range_inl_
#define _Stroika_Foundation_Traversal_Range_inl_

#include    "../Debug/Assertions.h"
#include    "../Math/Overlap.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

            /*
             ********************************************************************************
             RangeTraits::ExplicitRangeTraits_Integral<T, MIN, MAX, LOWER_BOUND_OPEN, UPPER_BOUND_OPEN, SIGNED_DIFF_TYPE, UNSIGNED_DIFF_TYPE>
             ********************************************************************************
             */
#if     qCompilerAndStdLib_constexpr_StaticDataMember_Buggy
            template    <typename T, T MIN, T MAX , Openness LOWER_BOUND_OPEN, Openness UPPER_BOUND_OPEN, typename SIGNED_DIFF_TYPE, typename UNSIGNED_DIFF_TYPE>
            const T RangeTraits::ExplicitRangeTraits_Integral<T, MIN, MAX, LOWER_BOUND_OPEN, UPPER_BOUND_OPEN, SIGNED_DIFF_TYPE, UNSIGNED_DIFF_TYPE>::kLowerBound   =   MIN;
            template    <typename T, T MIN, T MAX , Openness LOWER_BOUND_OPEN, Openness UPPER_BOUND_OPEN, typename SIGNED_DIFF_TYPE, typename UNSIGNED_DIFF_TYPE>
            const T RangeTraits::ExplicitRangeTraits_Integral<T, MIN, MAX, LOWER_BOUND_OPEN, UPPER_BOUND_OPEN, SIGNED_DIFF_TYPE, UNSIGNED_DIFF_TYPE>::kUpperBound   =   MAX;
#endif

            /*
             ********************************************************************************
             ****************** RangeTraits::DefaultRangeTraits<T> **************************
             ********************************************************************************
             */
#if     qCompilerAndStdLib_constexpr_StaticDataMember_Buggy
            template    <typename T>
            const T RangeTraits::DefaultRangeTraits<T>::kLowerBound   =   numeric_limits<T>::lowest ();
            template    <typename T>
            const T RangeTraits::DefaultRangeTraits<T>::kUpperBound   =   numeric_limits<T>::max ();
#endif

            /*
             ********************************************************************************
             ***************************** Range<T, TRAITS> *********************************
             ********************************************************************************
             */
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>::Range ()
                : fBegin_ (TRAITS::kUpperBound)
                , fEnd_ (TRAITS::kLowerBound)
            {
                Require  (TRAITS::kLowerBound <= TRAITS::kUpperBound);    // always required for class
                Require (TRAITS::kLowerBound != TRAITS::kUpperBound);     // you cannot make an empty range if min=max
                Ensure (empty ());
            }
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>::Range (const T& begin, const T& end)
                : fBegin_ (begin)
                , fEnd_ (end)
            {
                Require  (TRAITS::kLowerBound <= TRAITS::kUpperBound);    // always required for class
                Require (TRAITS::kLowerBound <= begin);
                Require (begin <= end);
                Require (end <= TRAITS::kUpperBound);
            }
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>::Range (const Memory::Optional<T>& begin, const Memory::Optional<T>& end)
                : fBegin_ (begin.IsPresent () ? *begin : TRAITS::kLowerBound)
                , fEnd_ (end.IsPresent () ? *end : TRAITS::kUpperBound)
            {
                Require  (TRAITS::kLowerBound <= TRAITS::kUpperBound);    // always required for class
                Require (TRAITS::kLowerBound <= fBegin_);
                Require (fBegin_ <= fEnd_);
                Require (fEnd_ <= TRAITS::kUpperBound);
            }
            template    <typename T, typename TRAITS>
            inline  Range<T, TRAITS>    Range<T, TRAITS>::FullRange ()
            {
                return Range<T, TRAITS> (TRAITS::kLowerBound, TRAITS::kUpperBound);
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::empty () const
            {
                if (fBegin_ > fEnd_) {
                    // internal hack done in Range<T, TRAITS>::Range() - empty range - otherwise not possible to create this situation
                    return true;
                }
                else if (fBegin_ == fEnd_) {
                    return TRAITS::kLowerBoundOpenness == Openness::eOpen and TRAITS::kUpperBoundOpenness == Openness::eOpen;
                }
                return false;
            }
            template    <typename T, typename TRAITS>
            inline  typename TRAITS::UnsignedDifferenceType    Range<T, TRAITS>::GetDistanceSpanned () const
            {
                if (empty ()) {
                    return 0;
                }
                return fEnd_ - fBegin_;
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::Contains (const T& r) const
            {
                if (empty ()) {
                    return false;
                }
                if (fBegin_ < r and r < fEnd_) {
                    return true;
                }
                if (TRAITS::kLowerBoundOpenness == Openness::eClosed and r == fBegin_) {
                    return true;
                }
                if (TRAITS::kUpperBoundOpenness == Openness::eClosed and r == fEnd_) {
                    return true;
                }
                return false;
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::Equals (const Range<T, TRAITS>& rhs) const
            {
                if (empty ()) {
                    return rhs.empty ();
                }
                return fBegin_ == rhs.fBegin_ and fEnd_ == rhs.fEnd_;
            }
#if 0
            template    <typename T, typename TRAITS>
            bool    Range<T, TRAITS>::Overlaps (const Range<T, TRAITS>& rhs) const
            {
                /*
                 *  @todo   RETHINK - because Range has semantics of exclude end - make sure overlap usuage
                 *          here is correct??? Unsure -- LGP 2013-07-05
                 */
                return Math::Overlaps (
                           pair<T, T> (fBegin_, fEnd_),
                           pair<T, T> (rhs.fBegin_, rhs.fEnd_)
                       );
            }
#endif
            template    <typename T, typename TRAITS>
            Range<T, TRAITS> Range<T, TRAITS>::Intersection (const Range<T, TRAITS>& rhs) const
            {
                if (empty () or rhs.empty ()) {
                    return Range ();
                }
                T   l   =   max (fBegin_, rhs.fBegin_);
                T   r   =   min (fEnd_, rhs.fEnd_);
                if (l <= r) {
                    return Range<T, TRAITS> (l, r);
                }
                else {
                    return Range ();
                }
            }
            template    <typename T, typename TRAITS>
            Range<T, TRAITS> Range<T, TRAITS>::UnionBounds (const Range<T, TRAITS>& rhs) const
            {
                if (empty ()) {
                    return rhs;
                }
                if (rhs.empty ()) {
                    return *this;
                }
                Range<T, TRAITS>    result  =   Range<T, TRAITS> (min (GetLowerBound (), rhs.GetLowerBound ()), max (GetUpperBound (), rhs.GetUpperBound ()));
                Ensure (result.GetLowerBound () <= GetLowerBound ());
                Ensure (result.GetLowerBound () <= GetUpperBound ());
                Ensure (result.GetLowerBound () <= rhs.GetLowerBound ());
                Ensure (result.GetLowerBound () <= rhs.GetUpperBound ());
                Ensure (result.GetUpperBound () >= GetLowerBound ());
                Ensure (result.GetUpperBound () >= GetUpperBound ());
                Ensure (result.GetUpperBound () >= rhs.GetLowerBound ());
                Ensure (result.GetUpperBound () >= rhs.GetUpperBound ());
                return result;
            }
            template    <typename T, typename TRAITS>
            inline  T    Range<T, TRAITS>::GetLowerBound () const
            {
                Require (not empty ());
                return fBegin_;
            }
            template    <typename T, typename TRAITS>
            inline  T    Range<T, TRAITS>::GetUpperBound () const
            {
                Require (not empty ());
                return fEnd_;
            }
            template    <typename T, typename TRAITS>
            inline     Openness    Range<T, TRAITS>::GetTraitsLowerBoundOpenness ()
            {
                return TRAITS::kLowerBoundOpenness;
            }
            template    <typename T, typename TRAITS>
            inline     Openness    Range<T, TRAITS>::GetTraitsUpperBoundOpenness ()
            {
                return TRAITS::kUpperBoundOpenness;
            }
            template    <typename T, typename TRAITS>
            inline     T    Range<T, TRAITS>::GetTraitsLowerBound ()
            {
                return TRAITS::kLowerBound;
            }
            template    <typename T, typename TRAITS>
            inline     T    Range<T, TRAITS>::GetTraitsUpperBound ()
            {
                return TRAITS::kUpperBound;
            }
            template    <typename T, typename TRAITS>
            template    <typename... ARGS>
            inline  Characters::String  Range<T, TRAITS>::Format (ARGS&& ... args) const
            {
                if (GetLowerBound () == GetUpperBound ()) {
                    return GetLowerBound ().Format (forward<ARGS> (args)...);
                }
                else {
                    return GetLowerBound ().Format (forward<ARGS> (args)...) + L" - " + GetUpperBound  ().Format (forward<ARGS> (args)...);
                }
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::operator== (const Range<T, TRAITS>& rhs) const
            {
                return Equals (rhs);
            }
            template    <typename T, typename TRAITS>
            inline  bool    Range<T, TRAITS>::operator!= (const Range<T, TRAITS>& rhs) const
            {
                return not Equals (rhs);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_Range_inl_ */
<|endoftext|>


<commit_before>/**  Unit tests for the GasPedal model class
 *
 * GasPedalTest.cpp
 * Created 3-11-18 By: Smitty
 *
 */

#include "../BaseModelTest/BaseModelTest.hpp"

class GasPedalTest : public BaseModelTest
{
public:
    GasPedalTest() {};

    static void setOriginTest(void)
    {
        int PedalVal = analogRead(MB_GAS_LIN);

        GasPedal pedal;

        pedal.setRawOrigin();

        TEST_ASSERT_INT_WITHIN(1000, pedal.getLinOrigin(), linearVal);
        TEST_ASSERT_INT_WITHIN(1000, pedal.getLogOrigin(), logVal);
    };
};
<commit_msg>updating unit test<commit_after>/**  Unit tests for the GasPedal model class
 *
 * GasPedalTest.cpp
 * Created 3-11-18 By: Smitty
 *
 */

#include "../BaseModelTest/BaseModelTest.hpp"

class GasPedalTest : public BaseModelTest
{
public:
    GasPedalTest() {};

    static void setOriginTest(void)
    {
        int PedalVal = analogRead(MB_GAS_LIN);

        GasPedal pedal;

        pedal.setRawOrigin();

        TEST_ASSERT_INT_WITHIN(1000, pedal.getRawOrigin(), PedalVal);
    };
};
<|endoftext|>