<commit_before>//
//  DefaultTileTexturizer.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 4/16/14.
//
//

#include "DefaultTileTexturizer.hpp"

#include "LayerSet.hpp"
#include "Tile.hpp"
#include "LeveledTexturedMesh.hpp"
#include "TextureIDReference.hpp"
#include "FrameTasksExecutor.hpp"
#include "LayerTilesRenderParameters.hpp"
#include "TileImageProvider.hpp"
#include "DebugTileImageProvider.hpp"
#include "TileImageListener.hpp"
#include "TexturesHandler.hpp"
#warning REMOVE THIS
#include "TileKey.hpp"

class DTT_LTMInitializer : public LazyTextureMappingInitializer {
private:
  const Tile* _tile;
  const Tile* _ancestor;

  float _translationU;
  float _translationV;
  float _scaleU;
  float _scaleV;

  const TileTessellator* _tessellator;
#ifdef C_CODE
  const Vector2I _resolution;
#endif
#ifdef JAVA_CODE
  private final Vector2I _resolution;
#endif

public:
  DTT_LTMInitializer(const Vector2I& resolution,
                     const Tile* tile,
                     const Tile* ancestor,
                     const TileTessellator* tessellator) :
  _resolution(resolution),
  _tile(tile),
  _ancestor(ancestor),
  _tessellator(tessellator),
  _translationU(0),
  _translationV(0),
  _scaleU(1),
  _scaleV(1)
  {

  }

  virtual ~DTT_LTMInitializer() {
#ifdef JAVA_CODE
    super.dispose();
#endif

  }

  void initialize() {
    // The default scale and translation are ok when (tile == _ancestor)
    if (_tile != _ancestor) {
      const Sector tileSector = _tile->_sector;

      const Vector2F lowerTextCoordUV = _tessellator->getTextCoord(_ancestor,
                                                                   tileSector._lower);

      const Vector2F upperTextCoordUV = _tessellator->getTextCoord(_ancestor,
                                                                   tileSector._upper);

      _translationU = lowerTextCoordUV._x;
      _translationV = upperTextCoordUV._y;

      _scaleU = upperTextCoordUV._x - lowerTextCoordUV._x;
      _scaleV = lowerTextCoordUV._y - upperTextCoordUV._y;
    }
  }

  const Vector2F getTranslation() const {
    return Vector2F(_translationU, _translationV);
  }

  const Vector2F getScale() const {
    return Vector2F(_scaleU, _scaleV);
  }

  IFloatBuffer* createTextCoords() const {
    return _tessellator->createTextCoords(_resolution, _tile);
  }

};

class DTT_TileTextureBuilder;

class DTT_TileImageListener : public TileImageListener {
private:
  DTT_TileTextureBuilder* _builder;

public:
  DTT_TileImageListener(DTT_TileTextureBuilder* builder) :
  _builder(builder)
  {
  }

  virtual ~DTT_TileImageListener() {
#ifdef JAVA_CODE
    super.dispose();
#endif
  }

  void imageCreated(const Tile*       tile,
                    const IImage*     image,
                    const Sector&     imageSector,
                    const RectangleF& imageRectangle,
                    const float       alpha);

  void imageCreationError(const Tile* tile,
                          const std::string& error);

  void imageCreationCanceled(const Tile* tile);
};

class DTT_TileTextureBuilder : public RCObject {
private:
  LeveledTexturedMesh* _texturedMesh;

//  DefaultTileTexturizer* _texturizer;
//  TileRasterizer*        _tileRasterizer;
  Tile*                  _tile;

//  std::vector<Petition*> _petitions;
//  int                    _petitionsCount;
//  int                    _stepsDone;

  TileImageProvider* _tileImageProvider;

  TexturesHandler* _texturesHandler;

#ifdef C_CODE
  const Vector2I   _tileTextureResolution;
//  const Vector2I   _tileMeshResolution;
#endif
#ifdef JAVA_CODE
  private final Vector2I _tileTextureResolution;
//  private final Vector2I _tileMeshResolution;
#endif

  IDownloader*     _downloader;

//  const Mesh* _tessellatorMesh;

//  const TileTessellator* _tessellator;

  const bool _logTilesPetitions;

  //  std::vector<TileTextureBuilder_PetitionStatus> _status;
  //  std::vector<long long>                         _requestsIds;

//  bool _finalized;
  bool _canceled;
//  bool _alreadyStarted;

  long long _texturePriority;

  static const TextureIDReference* getTopLevelTextureIdForTile(Tile* tile) {
    LeveledTexturedMesh* mesh = (LeveledTexturedMesh*) tile->getTexturizedMesh();

    return (mesh == NULL) ? NULL : mesh->getTopLevelTextureId();
  }

  static LeveledTexturedMesh* createMesh(Tile* tile,
                                         const Mesh* tessellatorMesh,
                                         const Vector2I tileMeshResolution,
                                         const TileTessellator* tessellator) {
    std::vector<LazyTextureMapping*>* mappings = new std::vector<LazyTextureMapping*>();

    Tile* ancestor = tile;
    bool fallbackSolved = false;
    while (ancestor != NULL && !fallbackSolved) {
      const bool ownedTexCoords = true;
      const bool transparent    = false;
      LazyTextureMapping* mapping = new LazyTextureMapping(new DTT_LTMInitializer(tileMeshResolution,
                                                                                tile,
                                                                                ancestor,
                                                                                tessellator),
                                                           ownedTexCoords,
                                                           transparent);

      if (ancestor != tile) {
        const TextureIDReference* glTextureId = getTopLevelTextureIdForTile(ancestor);
        if (glTextureId != NULL) {
          TextureIDReference* glTextureIdRetainedCopy = glTextureId->createCopy();

          mapping->setGLTextureId(glTextureIdRetainedCopy);
          fallbackSolved = true;
        }
      }

      mappings->push_back(mapping);

      ancestor = ancestor->getParent();
    }

    return new LeveledTexturedMesh(tessellatorMesh,
                                   false,
                                   mappings);
  }

public:

  DTT_TileTextureBuilder(//DefaultTileTexturizer*            texturizer,
//                         TileRasterizer*                   tileRasterizer,
                         const G3MRenderContext*           rc,
                         const LayerTilesRenderParameters* layerTilesRenderParameters,
                         TileImageProvider*                tileImageProvider,
//                         const std::vector<Petition*>&     petitions,
                         IDownloader*                      downloader,
                         Tile*                             tile,
                         const Mesh*                       tessellatorMesh,
                         const TileTessellator*            tessellator,
                         long long                         texturePriority,
                         bool                              logTilesPetitions) :
//  _texturizer(texturizer),
  _tileImageProvider(tileImageProvider),
//  _tileRasterizer(tileRasterizer),
  _texturesHandler(rc->getTexturesHandler()),
  _tileTextureResolution( layerTilesRenderParameters->_tileTextureResolution ),
//  _tileMeshResolution( layerTilesRenderParameters->_tileMeshResolution ),
  _downloader(downloader),
  _tile(tile),
//  _tessellatorMesh(tessellatorMesh),
//  _stepsDone(0),
  _texturedMesh( NULL ),
//  _tessellator(tessellator),
//  _finalized(false),
  _canceled(false),
//  _alreadyStarted(false),
  _texturePriority(texturePriority),
  _logTilesPetitions(logTilesPetitions)
  {
    _texturedMesh = createMesh(tile,
                               tessellatorMesh,
                               layerTilesRenderParameters->_tileMeshResolution,
                               tessellator);
  }

  LeveledTexturedMesh* getTexturedMesh() {
    return _texturedMesh;
  }

//  void cleanTexturedMesh() {
//    _texturedMesh = NULL;
//  }

//  void cleanTile() {
//    _tile = NULL;
//  }

  void start() {
#warning Diego at work!
    if (!_canceled) {
      const TileImageContribution contribution = _tileImageProvider->contribution(_tile);
      if (contribution == NONE) {
        if (_tile != NULL) {
#warning remove this!
          _tile->setTextureSolved(true);
        }
      }
      else {
        _tileImageProvider->create(_tile,
                                   _tileTextureResolution,
                                   new DTT_TileImageListener(this),
                                   true);
      }
    }
  }

  void cancel(bool cleanTile) {
#warning Diego at work!
    _texturedMesh = NULL;
    if (cleanTile) {
      _tile = NULL;
    }
    if (!_canceled) {
      _canceled = true;
      _tileImageProvider->cancel(_tile);
    }
//    if (!_canceled) {
//      _canceled = true;
//
//      if (!_finalized) {
//        for (int i = 0; i < _requestsIds.size(); i++) {
//          const long long requestId = _requestsIds[i];
//          _downloader->cancelRequest(requestId);
//        }
//      }
//      _requestsIds.clear();
//    }
  }

  bool isCanceled() const {
    return _canceled;
  }

  ~DTT_TileTextureBuilder() {
    delete _tileImageProvider;
#ifdef JAVA_CODE
    super.dispose();
#endif
  }

  bool uploadTexture(const IImage*      image,
                     const std::string& textureId) {
    if (_texturedMesh != NULL) {
      const bool generateMipmap = true;

      const TextureIDReference* glTextureId = _texturesHandler->getTextureIDReference(image,
                                                                                GLFormat::rgba(),
                                                                                textureId,
                                                                                generateMipmap);

      if (glTextureId != NULL) {
        if (!_texturedMesh->setGLTextureIdForLevel(0, glTextureId)) {
          delete glTextureId;
          //_texturesHandler->releaseGLTextureId(glTextureId);
        }
      }
    }

    IFactory::instance()->deleteImage(image);
    return true;
  }

  void imageCreated(const IImage*     image,
                    const Sector&     imageSector,
                    const RectangleF& imageRectangle,
                    const float       alpha) {
    if (!_canceled && (_tile != NULL) && (_texturedMesh != NULL)) {

#warning TODO calculate textureId
      const std::string textureId = _tile->getKey().description();
      if (uploadTexture(image, textureId)) {
        //If the image could be properly turn into texture
        _tile->setTextureSolved(true);
      }
    }
  }

  void imageCreationError(const std::string& error) {
#warning Diego at work
    ILogger::instance()->logError("%s", error.c_str());
  }

  void imageCreationCanceled() {
#warning Diego at work
  }

};

void DTT_TileImageListener::imageCreated(const Tile*       tile,
                                         const IImage*     image,
                                         const Sector&     imageSector,
                                         const RectangleF& imageRectangle,
                                         const float       alpha) {
  _builder->imageCreated(image, imageSector, imageRectangle, alpha);
}

void DTT_TileImageListener::imageCreationError(const Tile* tile,
                                               const std::string& error) {
  _builder->imageCreationError(error);
}

void DTT_TileImageListener::imageCreationCanceled(const Tile* tile) {
  _builder->imageCreationCanceled();
}

class DTT_TileTextureBuilderHolder : public ITexturizerData {
private:
  DTT_TileTextureBuilder* _builder;

public:
  DTT_TileTextureBuilderHolder(DTT_TileTextureBuilder* builder) :
  _builder(builder)
  {
  }

  DTT_TileTextureBuilder* get() const {
    return _builder;
  }

  ~DTT_TileTextureBuilderHolder() {
    if (_builder != NULL) {
      _builder->_release();
    }
  }

#ifndef C_CODE
  void unusedMethod() { }
#endif
};

class DTT_TileTextureBuilderStartTask : public FrameTask {
private:
  DTT_TileTextureBuilder* _builder;

public:
  DTT_TileTextureBuilderStartTask(DTT_TileTextureBuilder* builder) :
  _builder(builder)
  {
    _builder->_retain();
  }

  virtual ~DTT_TileTextureBuilderStartTask() {
    _builder->_release();
#ifdef JAVA_CODE
    super.dispose();
#endif
  }

  void execute(const G3MRenderContext* rc) {
    _builder->start();
  }

  bool isCanceled(const G3MRenderContext* rc) {
    return _builder->isCanceled();
  }
};

LeveledTexturedMesh* DefaultTileTexturizer::getMesh(Tile* tile) const {
  DTT_TileTextureBuilderHolder* tileBuilderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();
  return (tileBuilderHolder == NULL) ? NULL : tileBuilderHolder->get()->getTexturedMesh();
}

RenderState DefaultTileTexturizer::getRenderState(LayerSet* layerSet) {
  if (layerSet != NULL) {
    return layerSet->getRenderState();
  }
  return RenderState::ready();
}

void DefaultTileTexturizer::initialize(const G3MContext* context,
                                       const TilesRenderParameters* parameters) {
  // do nothing
}

Mesh* DefaultTileTexturizer::texturize(const G3MRenderContext* rc,
                                       const TileTessellator* tessellator,
                                       TileRasterizer* tileRasterizer,
                                       const LayerTilesRenderParameters* layerTilesRenderParameters,
                                       const LayerSet* layerSet,
                                       bool forceFullRender,
                                       long long texturePriority,
                                       Tile* tile,
                                       Mesh* tessellatorMesh,
                                       Mesh* previousMesh,
                                       bool logTilesPetitions) {
  DTT_TileTextureBuilderHolder* builderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();

#warning Diego at work!
  TileImageProvider* tileImageProvider = new DebugTileImageProvider();

  DTT_TileTextureBuilder* builder;
  if (builderHolder == NULL) {
    builder = new DTT_TileTextureBuilder(//this,
//                                         tileRasterizer,
                                         rc,
                                         layerTilesRenderParameters,
                                         tileImageProvider,
                                         // layerSet->createTileMapPetitions(rc,
                                         //                                  layerTilesRenderParameters,
                                         //                                  tile),
                                         rc->getDownloader(),
                                         tile,
                                         tessellatorMesh,
                                         tessellator,
                                         texturePriority,
                                         logTilesPetitions);
    builderHolder = new DTT_TileTextureBuilderHolder(builder);
    tile->setTexturizerData(builderHolder);
  }
  else {
    builder = builderHolder->get();
  }

  Mesh* texturizedMesh = builder->getTexturedMesh();
  if (forceFullRender) {
    builder->start();
  }
  else {
    rc->getFrameTasksExecutor()->addPreRenderTask( new DTT_TileTextureBuilderStartTask(builder) );
  }

  tile->setTexturizerDirty(false);
  return texturizedMesh;
}

void DefaultTileTexturizer::tileToBeDeleted(Tile* tile,
                                            Mesh* mesh) {
  DTT_TileTextureBuilderHolder* builderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();
  if (builderHolder != NULL) {
    DTT_TileTextureBuilder* builder = builderHolder->get();
    builder->cancel(true /* cleanTile */);
//    builder->cleanTile();
//    builder->cleanTexturedMesh();
  }
}

void DefaultTileTexturizer::tileMeshToBeDeleted(Tile* tile,
                                                Mesh* mesh) {
  DTT_TileTextureBuilderHolder* builderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();
  if (builderHolder != NULL) {
    DTT_TileTextureBuilder* builder = builderHolder->get();
    builder->cancel(false /* cleanTile */);
//    builder->cleanTexturedMesh();
  }
}

bool DefaultTileTexturizer::tileMeetsRenderCriteria(Tile* tile) {
  return false;
}

void DefaultTileTexturizer::justCreatedTopTile(const G3MRenderContext* rc,
                                               Tile* tile,
                                               LayerSet* layerSet) {
  // do nothing
}

void DefaultTileTexturizer::ancestorTexturedSolvedChanged(Tile* tile,
                                                          Tile* ancestorTile,
                                                          bool textureSolved) {
  if (!textureSolved) {
    return;
  }

  if (tile->isTextureSolved()) {
    return;
  }

  LeveledTexturedMesh* ancestorMesh = getMesh(ancestorTile);
  if (ancestorMesh == NULL) {
    return;
  }

  const TextureIDReference* glTextureId = ancestorMesh->getTopLevelTextureId();
  if (glTextureId == NULL) {
    return;
  }

  LeveledTexturedMesh* tileMesh = getMesh(tile);
  if (tileMesh == NULL) {
    return;
  }

  const TextureIDReference* glTextureIdRetainedCopy = glTextureId->createCopy();

  const int level = tile->_level - ancestorTile->_level;
  if (!tileMesh->setGLTextureIdForLevel(level, glTextureIdRetainedCopy)) {
    delete glTextureIdRetainedCopy;
  }
}

bool DefaultTileTexturizer::onTerrainTouchEvent(const G3MEventContext* ec,
                                                const Geodetic3D& position,
                                                const Tile* tile,
                                                LayerSet* layerSet) {
  if (layerSet == NULL) {
    return false;
  }

  return layerSet->onTerrainTouchEvent(ec, position, tile);
}
<commit_msg>Tile's image creation refactoring - NOT YET USABLE<commit_after>//
//  DefaultTileTexturizer.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 4/16/14.
//
//

#include "DefaultTileTexturizer.hpp"

#include "LayerSet.hpp"
#include "Tile.hpp"
#include "LeveledTexturedMesh.hpp"
#include "TextureIDReference.hpp"
#include "FrameTasksExecutor.hpp"
#include "LayerTilesRenderParameters.hpp"
#include "TileImageProvider.hpp"
#include "DebugTileImageProvider.hpp"
#include "TileImageListener.hpp"
#include "TexturesHandler.hpp"
#warning REMOVE THIS
#include "TileKey.hpp"

class DTT_LTMInitializer : public LazyTextureMappingInitializer {
private:
  const Tile* _tile;
  const Tile* _ancestor;

  float _translationU;
  float _translationV;
  float _scaleU;
  float _scaleV;

  const TileTessellator* _tessellator;
#ifdef C_CODE
  const Vector2I _resolution;
#endif
#ifdef JAVA_CODE
  private final Vector2I _resolution;
#endif

public:
  DTT_LTMInitializer(const Vector2I& resolution,
                     const Tile* tile,
                     const Tile* ancestor,
                     const TileTessellator* tessellator) :
  _resolution(resolution),
  _tile(tile),
  _ancestor(ancestor),
  _tessellator(tessellator),
  _translationU(0),
  _translationV(0),
  _scaleU(1),
  _scaleV(1)
  {

  }

  virtual ~DTT_LTMInitializer() {
#ifdef JAVA_CODE
    super.dispose();
#endif

  }

  void initialize() {
    // The default scale and translation are ok when (tile == _ancestor)
    if (_tile != _ancestor) {
      const Sector tileSector = _tile->_sector;

      const Vector2F lowerTextCoordUV = _tessellator->getTextCoord(_ancestor,
                                                                   tileSector._lower);

      const Vector2F upperTextCoordUV = _tessellator->getTextCoord(_ancestor,
                                                                   tileSector._upper);

      _translationU = lowerTextCoordUV._x;
      _translationV = upperTextCoordUV._y;

      _scaleU = upperTextCoordUV._x - lowerTextCoordUV._x;
      _scaleV = lowerTextCoordUV._y - upperTextCoordUV._y;
    }
  }

  const Vector2F getTranslation() const {
    return Vector2F(_translationU, _translationV);
  }

  const Vector2F getScale() const {
    return Vector2F(_scaleU, _scaleV);
  }

  IFloatBuffer* createTextCoords() const {
    return _tessellator->createTextCoords(_resolution, _tile);
  }

};

class DTT_TileTextureBuilder;

class DTT_TileImageListener : public TileImageListener {
private:
  DTT_TileTextureBuilder* _builder;

public:
  DTT_TileImageListener(DTT_TileTextureBuilder* builder) :
  _builder(builder)
  {
  }

  virtual ~DTT_TileImageListener() {
#ifdef JAVA_CODE
    super.dispose();
#endif
  }

  void imageCreated(const Tile*       tile,
                    const IImage*     image,
                    const Sector&     imageSector,
                    const RectangleF& imageRectangle,
                    const float       alpha);

  void imageCreationError(const Tile* tile,
                          const std::string& error);

  void imageCreationCanceled(const Tile* tile);
};

class DTT_TileTextureBuilder : public RCObject {
private:
  LeveledTexturedMesh* _texturedMesh;

//  DefaultTileTexturizer* _texturizer;
//  TileRasterizer*        _tileRasterizer;
  Tile*                  _tile;

//  std::vector<Petition*> _petitions;
//  int                    _petitionsCount;
//  int                    _stepsDone;

  TileImageProvider* _tileImageProvider;

  TexturesHandler* _texturesHandler;

#ifdef C_CODE
  const Vector2I   _tileTextureResolution;
//  const Vector2I   _tileMeshResolution;
#endif
#ifdef JAVA_CODE
  private final Vector2I _tileTextureResolution;
//  private final Vector2I _tileMeshResolution;
#endif

//  IDownloader*     _downloader;

//  const Mesh* _tessellatorMesh;

//  const TileTessellator* _tessellator;

  const bool _logTilesPetitions;

  //  std::vector<TileTextureBuilder_PetitionStatus> _status;
  //  std::vector<long long>                         _requestsIds;

//  bool _finalized;
  bool _canceled;
//  bool _alreadyStarted;

  long long _texturePriority;

  static const TextureIDReference* getTopLevelTextureIdForTile(Tile* tile) {
    LeveledTexturedMesh* mesh = (LeveledTexturedMesh*) tile->getTexturizedMesh();

    return (mesh == NULL) ? NULL : mesh->getTopLevelTextureId();
  }

  static LeveledTexturedMesh* createMesh(Tile* tile,
                                         const Mesh* tessellatorMesh,
                                         const Vector2I tileMeshResolution,
                                         const TileTessellator* tessellator) {
    std::vector<LazyTextureMapping*>* mappings = new std::vector<LazyTextureMapping*>();

    Tile* ancestor = tile;
    bool fallbackSolved = false;
    while (ancestor != NULL && !fallbackSolved) {
      const bool ownedTexCoords = true;
      const bool transparent    = false;
      LazyTextureMapping* mapping = new LazyTextureMapping(new DTT_LTMInitializer(tileMeshResolution,
                                                                                tile,
                                                                                ancestor,
                                                                                tessellator),
                                                           ownedTexCoords,
                                                           transparent);

      if (ancestor != tile) {
        const TextureIDReference* glTextureId = getTopLevelTextureIdForTile(ancestor);
        if (glTextureId != NULL) {
          TextureIDReference* glTextureIdRetainedCopy = glTextureId->createCopy();

          mapping->setGLTextureId(glTextureIdRetainedCopy);
          fallbackSolved = true;
        }
      }

      mappings->push_back(mapping);

      ancestor = ancestor->getParent();
    }

    return new LeveledTexturedMesh(tessellatorMesh,
                                   false,
                                   mappings);
  }

public:

  DTT_TileTextureBuilder(//DefaultTileTexturizer*            texturizer,
//                         TileRasterizer*                   tileRasterizer,
                         const G3MRenderContext*           rc,
                         const LayerTilesRenderParameters* layerTilesRenderParameters,
                         TileImageProvider*                tileImageProvider,
//                         const std::vector<Petition*>&     petitions,
//                         IDownloader*                      downloader,
                         Tile*                             tile,
                         const Mesh*                       tessellatorMesh,
                         const TileTessellator*            tessellator,
                         long long                         texturePriority,
                         bool                              logTilesPetitions) :
//  _texturizer(texturizer),
  _tileImageProvider(tileImageProvider),
//  _tileRasterizer(tileRasterizer),
  _texturesHandler(rc->getTexturesHandler()),
  _tileTextureResolution( layerTilesRenderParameters->_tileTextureResolution ),
//  _tileMeshResolution( layerTilesRenderParameters->_tileMeshResolution ),
//  _downloader(downloader),
  _tile(tile),
//  _tessellatorMesh(tessellatorMesh),
//  _stepsDone(0),
  _texturedMesh( NULL ),
//  _tessellator(tessellator),
//  _finalized(false),
  _canceled(false),
//  _alreadyStarted(false),
  _texturePriority(texturePriority),
  _logTilesPetitions(logTilesPetitions)
  {
    _texturedMesh = createMesh(tile,
                               tessellatorMesh,
                               layerTilesRenderParameters->_tileMeshResolution,
                               tessellator);
  }

  LeveledTexturedMesh* getTexturedMesh() {
    return _texturedMesh;
  }

//  void cleanTexturedMesh() {
//    _texturedMesh = NULL;
//  }

//  void cleanTile() {
//    _tile = NULL;
//  }

  void start() {
#warning Diego at work!
    if (!_canceled) {
      const TileImageContribution contribution = _tileImageProvider->contribution(_tile);
      if (contribution == NONE) {
        if (_tile != NULL) {
#warning remove this!
          _tile->setTextureSolved(true);
        }
      }
      else {
        _tileImageProvider->create(_tile,
                                   _tileTextureResolution,
                                   new DTT_TileImageListener(this),
                                   true);
      }
    }
  }

  void cancel(bool cleanTile) {
#warning Diego at work!
    _texturedMesh = NULL;
    if (cleanTile) {
      _tile = NULL;
    }
    if (!_canceled) {
      _canceled = true;
      _tileImageProvider->cancel(_tile);
    }
//    if (!_canceled) {
//      _canceled = true;
//
//      if (!_finalized) {
//        for (int i = 0; i < _requestsIds.size(); i++) {
//          const long long requestId = _requestsIds[i];
//          _downloader->cancelRequest(requestId);
//        }
//      }
//      _requestsIds.clear();
//    }
  }

  bool isCanceled() const {
    return _canceled;
  }

  ~DTT_TileTextureBuilder() {
    delete _tileImageProvider;
#ifdef JAVA_CODE
    super.dispose();
#endif
  }

  bool uploadTexture(const IImage*      image,
                     const std::string& textureId) {
    if (_texturedMesh != NULL) {
      const bool generateMipmap = true;

      const TextureIDReference* glTextureId = _texturesHandler->getTextureIDReference(image,
                                                                                GLFormat::rgba(),
                                                                                textureId,
                                                                                generateMipmap);

      if (glTextureId != NULL) {
        if (!_texturedMesh->setGLTextureIdForLevel(0, glTextureId)) {
          delete glTextureId;
          //_texturesHandler->releaseGLTextureId(glTextureId);
        }
      }
    }

    IFactory::instance()->deleteImage(image);
    return true;
  }

  void imageCreated(const IImage*     image,
                    const Sector&     imageSector,
                    const RectangleF& imageRectangle,
                    const float       alpha) {
    if (!_canceled && (_tile != NULL) && (_texturedMesh != NULL)) {

#warning TODO calculate textureId
      const std::string textureId = _tile->getKey().description();
      if (uploadTexture(image, textureId)) {
        //If the image could be properly turn into texture
        _tile->setTextureSolved(true);
      }
    }
  }

  void imageCreationError(const std::string& error) {
#warning Diego at work
    ILogger::instance()->logError("%s", error.c_str());
  }

  void imageCreationCanceled() {
#warning Diego at work
  }

};

void DTT_TileImageListener::imageCreated(const Tile*       tile,
                                         const IImage*     image,
                                         const Sector&     imageSector,
                                         const RectangleF& imageRectangle,
                                         const float       alpha) {
  _builder->imageCreated(image, imageSector, imageRectangle, alpha);
}

void DTT_TileImageListener::imageCreationError(const Tile* tile,
                                               const std::string& error) {
  _builder->imageCreationError(error);
}

void DTT_TileImageListener::imageCreationCanceled(const Tile* tile) {
  _builder->imageCreationCanceled();
}

class DTT_TileTextureBuilderHolder : public ITexturizerData {
private:
  DTT_TileTextureBuilder* _builder;

public:
  DTT_TileTextureBuilderHolder(DTT_TileTextureBuilder* builder) :
  _builder(builder)
  {
  }

  DTT_TileTextureBuilder* get() const {
    return _builder;
  }

  ~DTT_TileTextureBuilderHolder() {
    if (_builder != NULL) {
      _builder->_release();
    }
  }

#ifndef C_CODE
  void unusedMethod() { }
#endif
};

class DTT_TileTextureBuilderStartTask : public FrameTask {
private:
  DTT_TileTextureBuilder* _builder;

public:
  DTT_TileTextureBuilderStartTask(DTT_TileTextureBuilder* builder) :
  _builder(builder)
  {
    _builder->_retain();
  }

  virtual ~DTT_TileTextureBuilderStartTask() {
    _builder->_release();
#ifdef JAVA_CODE
    super.dispose();
#endif
  }

  void execute(const G3MRenderContext* rc) {
    _builder->start();
  }

  bool isCanceled(const G3MRenderContext* rc) {
    return _builder->isCanceled();
  }
};

LeveledTexturedMesh* DefaultTileTexturizer::getMesh(Tile* tile) const {
  DTT_TileTextureBuilderHolder* tileBuilderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();
  return (tileBuilderHolder == NULL) ? NULL : tileBuilderHolder->get()->getTexturedMesh();
}

RenderState DefaultTileTexturizer::getRenderState(LayerSet* layerSet) {
  if (layerSet != NULL) {
    return layerSet->getRenderState();
  }
  return RenderState::ready();
}

void DefaultTileTexturizer::initialize(const G3MContext* context,
                                       const TilesRenderParameters* parameters) {
  // do nothing
}

Mesh* DefaultTileTexturizer::texturize(const G3MRenderContext* rc,
                                       const TileTessellator* tessellator,
                                       TileRasterizer* tileRasterizer,
                                       const LayerTilesRenderParameters* layerTilesRenderParameters,
                                       const LayerSet* layerSet,
                                       bool forceFullRender,
                                       long long texturePriority,
                                       Tile* tile,
                                       Mesh* tessellatorMesh,
                                       Mesh* previousMesh,
                                       bool logTilesPetitions) {
  DTT_TileTextureBuilderHolder* builderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();

#warning Diego at work!
  TileImageProvider* tileImageProvider = new DebugTileImageProvider();

  DTT_TileTextureBuilder* builder;
  if (builderHolder == NULL) {
    builder = new DTT_TileTextureBuilder(// this,
                                         // tileRasterizer,
                                         rc,
                                         layerTilesRenderParameters,
                                         tileImageProvider,
                                         // layerSet->createTileMapPetitions(rc,
                                         //                                  layerTilesRenderParameters,
                                         //                                  tile),
                                         // rc->getDownloader(),
                                         tile,
                                         tessellatorMesh,
                                         tessellator,
                                         texturePriority,
                                         logTilesPetitions);
    builderHolder = new DTT_TileTextureBuilderHolder(builder);
    tile->setTexturizerData(builderHolder);
  }
  else {
    builder = builderHolder->get();
  }

  Mesh* texturizedMesh = builder->getTexturedMesh();
  if (forceFullRender) {
    builder->start();
  }
  else {
    rc->getFrameTasksExecutor()->addPreRenderTask( new DTT_TileTextureBuilderStartTask(builder) );
  }

  tile->setTexturizerDirty(false);
  return texturizedMesh;
}

void DefaultTileTexturizer::tileToBeDeleted(Tile* tile,
                                            Mesh* mesh) {
  DTT_TileTextureBuilderHolder* builderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();
  if (builderHolder != NULL) {
    DTT_TileTextureBuilder* builder = builderHolder->get();
    builder->cancel(true /* cleanTile */);
//    builder->cleanTile();
//    builder->cleanTexturedMesh();
  }
}

void DefaultTileTexturizer::tileMeshToBeDeleted(Tile* tile,
                                                Mesh* mesh) {
  DTT_TileTextureBuilderHolder* builderHolder = (DTT_TileTextureBuilderHolder*) tile->getTexturizerData();
  if (builderHolder != NULL) {
    DTT_TileTextureBuilder* builder = builderHolder->get();
    builder->cancel(false /* cleanTile */);
//    builder->cleanTexturedMesh();
  }
}

bool DefaultTileTexturizer::tileMeetsRenderCriteria(Tile* tile) {
  return false;
}

void DefaultTileTexturizer::justCreatedTopTile(const G3MRenderContext* rc,
                                               Tile* tile,
                                               LayerSet* layerSet) {
  // do nothing
}

void DefaultTileTexturizer::ancestorTexturedSolvedChanged(Tile* tile,
                                                          Tile* ancestorTile,
                                                          bool textureSolved) {
  if (!textureSolved) {
    return;
  }

  if (tile->isTextureSolved()) {
    return;
  }

  LeveledTexturedMesh* ancestorMesh = getMesh(ancestorTile);
  if (ancestorMesh == NULL) {
    return;
  }

  const TextureIDReference* glTextureId = ancestorMesh->getTopLevelTextureId();
  if (glTextureId == NULL) {
    return;
  }

  LeveledTexturedMesh* tileMesh = getMesh(tile);
  if (tileMesh == NULL) {
    return;
  }

  const TextureIDReference* glTextureIdRetainedCopy = glTextureId->createCopy();

  const int level = tile->_level - ancestorTile->_level;
  if (!tileMesh->setGLTextureIdForLevel(level, glTextureIdRetainedCopy)) {
    delete glTextureIdRetainedCopy;
  }
}

bool DefaultTileTexturizer::onTerrainTouchEvent(const G3MEventContext* ec,
                                                const Geodetic3D& position,
                                                const Tile* tile,
                                                LayerSet* layerSet) {
  if (layerSet == NULL) {
    return false;
  }

  return layerSet->onTerrainTouchEvent(ec, position, tile);
}
<|endoftext|>


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

#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"

class ExperimentalApiTest : public ExtensionApiTest {
public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }
};

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PermissionsFail) {
  ASSERT_TRUE(RunExtensionTest("permissions/disabled")) << message_;

  // Since the experimental APIs require a flag, this will fail even though
  // It's enabled.
  // TODO(erikkay) This test is currently broken because LoadExtension in
  // ExtensionBrowserTest doesn't actually fail, it just times out.  To fix this
  // I'll need to add an EXTENSION_LOAD_ERROR notification, which is probably
  // too much for the branch.  I'll enable this on trunk later.
  //ASSERT_FALSE(RunExtensionTest("permissions/enabled"))) << message_;
}

IN_PROC_BROWSER_TEST_F(ExperimentalApiTest, PermissionsSucceed) {
  ASSERT_TRUE(RunExtensionTest("permissions/enabled")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExperimentalPermissionsFail) {
  // At the time this test is being created, there is no experimental
  // function that will not be graduating soon, and does not require a
  // tab id as an argument.  So, we need the tab permission to get
  // a tab id.
  ASSERT_TRUE(RunExtensionTest("permissions/experimental_disabled"))
      << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FavIconPermission) {
  ASSERT_TRUE(RunExtensionTest("permissions/favicon")) << message_;
}

// Test functions and APIs that are always allowed (even if you ask for no
// permissions.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, AlwaysAllowed) {
  ASSERT_TRUE(RunExtensionTest("permissions/always_allowed")) << message_;
}

// TODO(gregoryd): run the NaCl test on all systems once
// http://code.google.com/p/chromium/issues/detail?id=51335 is fixed.
// Meanwhile we run it on Mac OSX only, since we can be sure that an x86-32 NaCl
// module will work there.
// Mark as Flaky.  http://crbug.com/51861
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_NaClPermissionEnabled) {
  CommandLine::ForCurrentProcess()->AppendSwitch(switches::kInternalNaCl);
  ASSERT_TRUE(RunExtensionTest("permissions/nacl_enabled")) << message_;
}
#endif
<commit_msg>Shave 10 seconds off browser_tests. Time is wasted in a permission dialog timeout.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"

class ExperimentalApiTest : public ExtensionApiTest {
public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }
};

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PermissionsFail) {
  ASSERT_TRUE(RunExtensionTest("permissions/disabled")) << message_;

  // Since the experimental APIs require a flag, this will fail even though
  // It's enabled.
  // TODO(erikkay) This test is currently broken because LoadExtension in
  // ExtensionBrowserTest doesn't actually fail, it just times out.  To fix this
  // I'll need to add an EXTENSION_LOAD_ERROR notification, which is probably
  // too much for the branch.  I'll enable this on trunk later.
  //ASSERT_FALSE(RunExtensionTest("permissions/enabled"))) << message_;
}

IN_PROC_BROWSER_TEST_F(ExperimentalApiTest, PermissionsSucceed) {
  ASSERT_TRUE(RunExtensionTest("permissions/enabled")) << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExperimentalPermissionsFail) {
  // At the time this test is being created, there is no experimental
  // function that will not be graduating soon, and does not require a
  // tab id as an argument.  So, we need the tab permission to get
  // a tab id.
  ASSERT_TRUE(RunExtensionTest("permissions/experimental_disabled"))
      << message_;
}

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FavIconPermission) {
  ASSERT_TRUE(RunExtensionTest("permissions/favicon")) << message_;
}

// Test functions and APIs that are always allowed (even if you ask for no
// permissions.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, AlwaysAllowed) {
  ASSERT_TRUE(RunExtensionTest("permissions/always_allowed")) << message_;
}

// TODO(gregoryd): run the NaCl test on all systems once
// http://code.google.com/p/chromium/issues/detail?id=51335 is fixed.
// Meanwhile we run it on Mac OSX only, since we can be sure that an x86-32 NaCl
// module will work there.
// Mark as Flaky.  http://crbug.com/51861
//
// FLAKY --> DISABLED since it takes 10sec to timeout a dialog.  Need
// faster timeout.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_NaClPermissionEnabled) {
  CommandLine::ForCurrentProcess()->AppendSwitch(switches::kInternalNaCl);
  ASSERT_TRUE(RunExtensionTest("permissions/nacl_enabled")) << message_;
}
#endif
<|endoftext|>


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

#include "chrome/browser/prerender/prerender_tab_helper.h"

#include "base/metrics/histogram.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/view_messages.h"

namespace prerender {

namespace {

const int kMinHoverThresholdsMs[] = {
  50,
  75,
  100,
  150,
  200,
  250,
  300,
  400,
  500,
  750,
  1000,
  1500,
  2000,
  3000,
  4000,
  5000
};

// Overview of hover-related histograms:
// -- count of hover start
// -- count of hover too short.
// difference between these is pages prerendered
// -- count of prerender used
// -- time from hover commence until click (subtract hover threshold
// from that value to figure out average savings).

enum HoverEvents {
  HOVER_EVENT_START = 0,
  HOVER_EVENT_TOO_SHORT = 1,
  HOVER_EVENT_REPLACED = 2,
  HOVER_EVENT_CLICK = 3,
  HOVER_EVENT_MAX
};

const int kNumHoverThresholds = arraysize(kMinHoverThresholdsMs);

class PerHoverThresholdHistograms {
 public:
  explicit PerHoverThresholdHistograms(int hover_threshold_ms) {
    std::string prefix = std::string("Prerender.HoverStats_") +
        base::IntToString(hover_threshold_ms) + std::string("_");
    count_hover_events_ = base::LinearHistogram::FactoryGet(
        prefix + std::string("Events"),
        1,
        HOVER_EVENT_MAX,
        HOVER_EVENT_MAX + 1,
        base::Histogram::kUmaTargetedHistogramFlag);
    time_hover_until_click_ = base::Histogram::FactoryTimeGet(
        prefix + std::string("TimeToClick"),
        base::TimeDelta::FromMilliseconds(1),
        base::TimeDelta::FromSeconds(60),
        100,
        base::Histogram::kUmaTargetedHistogramFlag);
  }
  base::Histogram* count_hover_events() { return count_hover_events_; }
  base::Histogram* time_hover_until_click() { return time_hover_until_click_; }

 private:
  base::Histogram* count_hover_events_;
  base::Histogram* time_hover_until_click_;
};

enum PAGEVIEW_EVENTS {
  PAGEVIEW_EVENT_NEW_URL = 0,
  PAGEVIEW_EVENT_TOP_SITE_NEW_URL = 1,
  PAGEVIEW_EVENT_LOAD_START = 2,
  PAGEVIEW_EVENT_TOP_SITE_LOAD_START = 3,
  PAGEVIEW_EVENT_MAX = 4
};

void RecordPageviewEvent(PAGEVIEW_EVENTS event) {
  UMA_HISTOGRAM_ENUMERATION("Prerender.PageviewEvents",
                            event, PAGEVIEW_EVENT_MAX);
}

}  // namespace

class PrerenderTabHelper::HoverData {
 public:
  void SetHoverThreshold(int threshold_ms) {
    hover_threshold_ = base::TimeDelta::FromMilliseconds(threshold_ms);
    histograms_.reset(new PerHoverThresholdHistograms(threshold_ms));
  }

  void RecordHover(const GURL& url) {
    VerifyInitialized();

    MaybeStartedPrerendering();

    // Ignore duplicate hover messages.
    if (new_url_ == url)
      return;

    if (!new_url_.is_empty())
      histograms_->count_hover_events()->Add(HOVER_EVENT_TOO_SHORT);

    if (current_url_ == url) {
      // If we came back to URL currently being prerendered, we don't need
      // to "remember" to start prerendering, because we already have that
      // URL prerendered.
      new_url_ = GURL();
    } else {
      // Otherwise, we remember this new URL as something we might soon
      // start prerendering.
      new_url_ = url;
      new_time_ = base::TimeTicks::Now();
    }

    if (!new_url_.is_empty())
      histograms_->count_hover_events()->Add(HOVER_EVENT_START);
  }

  void RecordNavigation(const GURL& url) {
    VerifyInitialized();

    // Artifically call RecordHover with an empty URL to accomplish two things:
    // -- ensure we update what we are currently prerendering
    // -- record if there is a pending new hover, that we "exited" it,
    //    thereby recording an EVENT_TOO_SHORT for it.
    RecordHover(GURL());

    if (current_url_ == url) {
        // Match.  We would have started prerendering the new URL.
        histograms_->count_hover_events()->Add(HOVER_EVENT_CLICK);
        histograms_->time_hover_until_click()->AddTime(
            base::TimeTicks::Now() - current_time_);
        current_url_ = GURL();
    }
  }

 private:
  void VerifyInitialized() {
    DCHECK(histograms_.get() != NULL);
  }

  void MaybeStartedPrerendering() {
    if (!new_url_.is_empty() &&
        base::TimeTicks::Now() - new_time_ > hover_threshold_) {
      if (!current_url_.is_empty())
        histograms_->count_hover_events()->Add(HOVER_EVENT_REPLACED);
      current_url_ = new_url_;
      current_time_ = new_time_;
      new_url_ = GURL();
    }
  }

  scoped_ptr<PerHoverThresholdHistograms> histograms_;

  // The time & url of the hover that is currently being prerendered.
  base::TimeTicks current_time_;
  GURL current_url_;

  // The time & url of a new hover that does not meet the threshold for
  // prerendering and may replace the prerender currently being prerendered.
  base::TimeTicks new_time_;
  GURL new_url_;

  // The threshold for hovering.
  base::TimeDelta hover_threshold_;
};

PrerenderTabHelper::PrerenderTabHelper(TabContentsWrapper* tab)
    : TabContentsObserver(tab->tab_contents()),
      tab_(tab),
      pplt_load_start_(),
      last_hovers_(new HoverData[kNumHoverThresholds]) {
  for (int i = 0; i < kNumHoverThresholds; i++)
    last_hovers_[i].SetHoverThreshold(kMinHoverThresholdsMs[i]);
}

PrerenderTabHelper::~PrerenderTabHelper() {
}

void PrerenderTabHelper::ProvisionalChangeToMainFrameUrl(const GURL& url,
                                                         bool has_opener_set) {
  RecordPageviewEvent(PAGEVIEW_EVENT_NEW_URL);
  if (IsTopSite(url))
    RecordPageviewEvent(PAGEVIEW_EVENT_TOP_SITE_NEW_URL);
  if (!tab_->delegate())
    return;  // PrerenderManager needs a delegate to handle the swap.
  PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
  if (!prerender_manager)
    return;
  if (prerender_manager->IsTabContentsPrerendering(tab_contents()))
    return;
  prerender_manager->MarkTabContentsAsNotPrerendered(tab_contents());
  MaybeUsePrerenderedPage(url, has_opener_set);
}

bool PrerenderTabHelper::OnMessageReceived(const IPC::Message& message) {
  IPC_BEGIN_MESSAGE_MAP(PrerenderTabHelper, message)
    IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame,
                        OnDidStartProvisionalLoadForFrame)
    IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateTargetURL, OnMsgUpdateTargetURL)
  IPC_END_MESSAGE_MAP()
  return false;
}

void PrerenderTabHelper::OnDidStartProvisionalLoadForFrame(int64 frame_id,
                                                           bool is_main_frame,
                                                           bool has_opener_set,
                                                           const GURL& url) {
  if (is_main_frame) {
    RecordPageviewEvent(PAGEVIEW_EVENT_LOAD_START);
    if (IsTopSite(url))
      RecordPageviewEvent(PAGEVIEW_EVENT_TOP_SITE_LOAD_START);

    // Record the beginning of a new PPLT navigation.
    pplt_load_start_ = base::TimeTicks::Now();

    // Update hover stats.
    for (int i = 0; i < kNumHoverThresholds; i++)
      last_hovers_[i].RecordNavigation(url);

    MaybeLogCurrentHover(current_hover_url_ == url);
  }
}

void PrerenderTabHelper::OnMsgUpdateTargetURL(int32 page_id, const GURL& url) {
  for (int i = 0; i < kNumHoverThresholds; i++)
    last_hovers_[i].RecordHover(url);

  if (url != current_hover_url_) {
    MaybeLogCurrentHover(false);
    current_hover_url_ = url;
    current_hover_time_ = base::TimeTicks::Now();
  }
}

void PrerenderTabHelper::DidStopLoading() {
  // Don't include prerendered pages in the PPLT metric until after they are
  // swapped in.

  // Compute the PPLT metric and report it in a histogram, if needed.
  if (!pplt_load_start_.is_null() && !IsPrerendering()) {
    PrerenderManager::RecordPerceivedPageLoadTime(
        base::TimeTicks::Now() - pplt_load_start_, tab_contents());
  }

  // Reset the PPLT metric.
  pplt_load_start_ = base::TimeTicks();
}

PrerenderManager* PrerenderTabHelper::MaybeGetPrerenderManager() const {
  Profile* profile =
      Profile::FromBrowserContext(tab_contents()->browser_context());
  if (!profile)
    return NULL;
  return profile->GetPrerenderManager();
}

bool PrerenderTabHelper::MaybeUsePrerenderedPage(const GURL& url,
                                                 bool has_opener_set) {
  PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
  if (!prerender_manager)
    return false;
  DCHECK(!prerender_manager->IsTabContentsPrerendering(tab_contents()));
  return prerender_manager->MaybeUsePrerenderedPage(tab_contents(),
                                                    url,
                                                    has_opener_set);
}

bool PrerenderTabHelper::IsPrerendering() {
  PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
  if (!prerender_manager)
    return false;
  return prerender_manager->IsTabContentsPrerendering(tab_contents());
}

void PrerenderTabHelper::PrerenderSwappedIn() {
  // Ensure we are not prerendering any more.
  DCHECK(!IsPrerendering());
  if (pplt_load_start_.is_null()) {
    // If we have already finished loading, report a 0 PPLT.
    PrerenderManager::RecordPerceivedPageLoadTime(base::TimeDelta(),
                                                  tab_contents());
  } else {
    // If we have not finished loading yet, rebase the start time to now.
    pplt_load_start_ = base::TimeTicks::Now();
  }
}

void PrerenderTabHelper::MaybeLogCurrentHover(bool was_used) {
  if (current_hover_url_.is_empty())
    return;

  static const int64 min_ms = 0;
  static const int64 max_ms = 2000;
  static const int num_buckets = 100;

  int64 elapsed_ms =
      (base::TimeTicks::Now() - current_hover_time_).InMilliseconds();

  elapsed_ms = std::min(std::max(elapsed_ms, min_ms), max_ms);
  elapsed_ms /= max_ms / num_buckets;

  if (was_used) {
    UMA_HISTOGRAM_ENUMERATION("Prerender.HoverStats_TimeUntilClicked",
                              elapsed_ms, num_buckets);
  } else {
    UMA_HISTOGRAM_ENUMERATION("Prerender.HoverStats_TimeUntilDiscarded",
                              elapsed_ms, num_buckets);
  }

  current_hover_url_ = GURL();
}

bool PrerenderTabHelper::IsTopSite(const GURL& url) const {
  PrerenderManager* pm = MaybeGetPrerenderManager();
  return (pm && pm->IsTopSite(url));
}

}  // namespace prerender
<commit_msg>Use only 1 hover threshold of 250ms for hover histograms. R=cbentzel Review URL: http://codereview.chromium.org/7792105<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prerender/prerender_tab_helper.h"

#include "base/metrics/histogram.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/view_messages.h"

namespace prerender {

namespace {

const int kMinHoverThresholdsMs[] = {
  250
};

// Overview of hover-related histograms:
// -- count of hover start
// -- count of hover too short.
// difference between these is pages prerendered
// -- count of prerender used
// -- time from hover commence until click (subtract hover threshold
// from that value to figure out average savings).

enum HoverEvents {
  HOVER_EVENT_START = 0,
  HOVER_EVENT_TOO_SHORT = 1,
  HOVER_EVENT_REPLACED = 2,
  HOVER_EVENT_CLICK = 3,
  HOVER_EVENT_MAX
};

const int kNumHoverThresholds = arraysize(kMinHoverThresholdsMs);

class PerHoverThresholdHistograms {
 public:
  explicit PerHoverThresholdHistograms(int hover_threshold_ms) {
    std::string prefix = std::string("Prerender.HoverStats_") +
        base::IntToString(hover_threshold_ms) + std::string("_");
    count_hover_events_ = base::LinearHistogram::FactoryGet(
        prefix + std::string("Events"),
        1,
        HOVER_EVENT_MAX,
        HOVER_EVENT_MAX + 1,
        base::Histogram::kUmaTargetedHistogramFlag);
    time_hover_until_click_ = base::Histogram::FactoryTimeGet(
        prefix + std::string("TimeToClick"),
        base::TimeDelta::FromMilliseconds(1),
        base::TimeDelta::FromSeconds(60),
        100,
        base::Histogram::kUmaTargetedHistogramFlag);
  }
  base::Histogram* count_hover_events() { return count_hover_events_; }
  base::Histogram* time_hover_until_click() { return time_hover_until_click_; }

 private:
  base::Histogram* count_hover_events_;
  base::Histogram* time_hover_until_click_;
};

enum PAGEVIEW_EVENTS {
  PAGEVIEW_EVENT_NEW_URL = 0,
  PAGEVIEW_EVENT_TOP_SITE_NEW_URL = 1,
  PAGEVIEW_EVENT_LOAD_START = 2,
  PAGEVIEW_EVENT_TOP_SITE_LOAD_START = 3,
  PAGEVIEW_EVENT_MAX = 4
};

void RecordPageviewEvent(PAGEVIEW_EVENTS event) {
  UMA_HISTOGRAM_ENUMERATION("Prerender.PageviewEvents",
                            event, PAGEVIEW_EVENT_MAX);
}

}  // namespace

class PrerenderTabHelper::HoverData {
 public:
  void SetHoverThreshold(int threshold_ms) {
    hover_threshold_ = base::TimeDelta::FromMilliseconds(threshold_ms);
    histograms_.reset(new PerHoverThresholdHistograms(threshold_ms));
  }

  void RecordHover(const GURL& url) {
    VerifyInitialized();

    MaybeStartedPrerendering();

    // Ignore duplicate hover messages.
    if (new_url_ == url)
      return;

    if (!new_url_.is_empty())
      histograms_->count_hover_events()->Add(HOVER_EVENT_TOO_SHORT);

    if (current_url_ == url) {
      // If we came back to URL currently being prerendered, we don't need
      // to "remember" to start prerendering, because we already have that
      // URL prerendered.
      new_url_ = GURL();
    } else {
      // Otherwise, we remember this new URL as something we might soon
      // start prerendering.
      new_url_ = url;
      new_time_ = base::TimeTicks::Now();
    }

    if (!new_url_.is_empty())
      histograms_->count_hover_events()->Add(HOVER_EVENT_START);
  }

  void RecordNavigation(const GURL& url) {
    VerifyInitialized();

    // Artifically call RecordHover with an empty URL to accomplish two things:
    // -- ensure we update what we are currently prerendering
    // -- record if there is a pending new hover, that we "exited" it,
    //    thereby recording an EVENT_TOO_SHORT for it.
    RecordHover(GURL());

    if (current_url_ == url) {
        // Match.  We would have started prerendering the new URL.
        histograms_->count_hover_events()->Add(HOVER_EVENT_CLICK);
        histograms_->time_hover_until_click()->AddTime(
            base::TimeTicks::Now() - current_time_);
        current_url_ = GURL();
    }
  }

 private:
  void VerifyInitialized() {
    DCHECK(histograms_.get() != NULL);
  }

  void MaybeStartedPrerendering() {
    if (!new_url_.is_empty() &&
        base::TimeTicks::Now() - new_time_ > hover_threshold_) {
      if (!current_url_.is_empty())
        histograms_->count_hover_events()->Add(HOVER_EVENT_REPLACED);
      current_url_ = new_url_;
      current_time_ = new_time_;
      new_url_ = GURL();
    }
  }

  scoped_ptr<PerHoverThresholdHistograms> histograms_;

  // The time & url of the hover that is currently being prerendered.
  base::TimeTicks current_time_;
  GURL current_url_;

  // The time & url of a new hover that does not meet the threshold for
  // prerendering and may replace the prerender currently being prerendered.
  base::TimeTicks new_time_;
  GURL new_url_;

  // The threshold for hovering.
  base::TimeDelta hover_threshold_;
};

PrerenderTabHelper::PrerenderTabHelper(TabContentsWrapper* tab)
    : TabContentsObserver(tab->tab_contents()),
      tab_(tab),
      pplt_load_start_(),
      last_hovers_(new HoverData[kNumHoverThresholds]) {
  for (int i = 0; i < kNumHoverThresholds; i++)
    last_hovers_[i].SetHoverThreshold(kMinHoverThresholdsMs[i]);
}

PrerenderTabHelper::~PrerenderTabHelper() {
}

void PrerenderTabHelper::ProvisionalChangeToMainFrameUrl(const GURL& url,
                                                         bool has_opener_set) {
  RecordPageviewEvent(PAGEVIEW_EVENT_NEW_URL);
  if (IsTopSite(url))
    RecordPageviewEvent(PAGEVIEW_EVENT_TOP_SITE_NEW_URL);
  if (!tab_->delegate())
    return;  // PrerenderManager needs a delegate to handle the swap.
  PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
  if (!prerender_manager)
    return;
  if (prerender_manager->IsTabContentsPrerendering(tab_contents()))
    return;
  prerender_manager->MarkTabContentsAsNotPrerendered(tab_contents());
  MaybeUsePrerenderedPage(url, has_opener_set);
}

bool PrerenderTabHelper::OnMessageReceived(const IPC::Message& message) {
  IPC_BEGIN_MESSAGE_MAP(PrerenderTabHelper, message)
    IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame,
                        OnDidStartProvisionalLoadForFrame)
    IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateTargetURL, OnMsgUpdateTargetURL)
  IPC_END_MESSAGE_MAP()
  return false;
}

void PrerenderTabHelper::OnDidStartProvisionalLoadForFrame(int64 frame_id,
                                                           bool is_main_frame,
                                                           bool has_opener_set,
                                                           const GURL& url) {
  if (is_main_frame) {
    RecordPageviewEvent(PAGEVIEW_EVENT_LOAD_START);
    if (IsTopSite(url))
      RecordPageviewEvent(PAGEVIEW_EVENT_TOP_SITE_LOAD_START);

    // Record the beginning of a new PPLT navigation.
    pplt_load_start_ = base::TimeTicks::Now();

    // Update hover stats.
    for (int i = 0; i < kNumHoverThresholds; i++)
      last_hovers_[i].RecordNavigation(url);

    MaybeLogCurrentHover(current_hover_url_ == url);
  }
}

void PrerenderTabHelper::OnMsgUpdateTargetURL(int32 page_id, const GURL& url) {
  for (int i = 0; i < kNumHoverThresholds; i++)
    last_hovers_[i].RecordHover(url);

  if (url != current_hover_url_) {
    MaybeLogCurrentHover(false);
    current_hover_url_ = url;
    current_hover_time_ = base::TimeTicks::Now();
  }
}

void PrerenderTabHelper::DidStopLoading() {
  // Don't include prerendered pages in the PPLT metric until after they are
  // swapped in.

  // Compute the PPLT metric and report it in a histogram, if needed.
  if (!pplt_load_start_.is_null() && !IsPrerendering()) {
    PrerenderManager::RecordPerceivedPageLoadTime(
        base::TimeTicks::Now() - pplt_load_start_, tab_contents());
  }

  // Reset the PPLT metric.
  pplt_load_start_ = base::TimeTicks();
}

PrerenderManager* PrerenderTabHelper::MaybeGetPrerenderManager() const {
  Profile* profile =
      Profile::FromBrowserContext(tab_contents()->browser_context());
  if (!profile)
    return NULL;
  return profile->GetPrerenderManager();
}

bool PrerenderTabHelper::MaybeUsePrerenderedPage(const GURL& url,
                                                 bool has_opener_set) {
  PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
  if (!prerender_manager)
    return false;
  DCHECK(!prerender_manager->IsTabContentsPrerendering(tab_contents()));
  return prerender_manager->MaybeUsePrerenderedPage(tab_contents(),
                                                    url,
                                                    has_opener_set);
}

bool PrerenderTabHelper::IsPrerendering() {
  PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
  if (!prerender_manager)
    return false;
  return prerender_manager->IsTabContentsPrerendering(tab_contents());
}

void PrerenderTabHelper::PrerenderSwappedIn() {
  // Ensure we are not prerendering any more.
  DCHECK(!IsPrerendering());
  if (pplt_load_start_.is_null()) {
    // If we have already finished loading, report a 0 PPLT.
    PrerenderManager::RecordPerceivedPageLoadTime(base::TimeDelta(),
                                                  tab_contents());
  } else {
    // If we have not finished loading yet, rebase the start time to now.
    pplt_load_start_ = base::TimeTicks::Now();
  }
}

void PrerenderTabHelper::MaybeLogCurrentHover(bool was_used) {
  if (current_hover_url_.is_empty())
    return;

  static const int64 min_ms = 0;
  static const int64 max_ms = 2000;
  static const int num_buckets = 100;

  int64 elapsed_ms =
      (base::TimeTicks::Now() - current_hover_time_).InMilliseconds();

  elapsed_ms = std::min(std::max(elapsed_ms, min_ms), max_ms);
  elapsed_ms /= max_ms / num_buckets;

  if (was_used) {
    UMA_HISTOGRAM_ENUMERATION("Prerender.HoverStats_TimeUntilClicked",
                              elapsed_ms, num_buckets);
  } else {
    UMA_HISTOGRAM_ENUMERATION("Prerender.HoverStats_TimeUntilDiscarded",
                              elapsed_ms, num_buckets);
  }

  current_hover_url_ = GURL();
}

bool PrerenderTabHelper::IsTopSite(const GURL& url) const {
  PrerenderManager* pm = MaybeGetPrerenderManager();
  return (pm && pm->IsTopSite(url));
}

}  // namespace prerender
<|endoftext|>


<commit_before>/* Begin CVS Header
   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/utilities/CProcessReport.cpp,v $
   $Revision: 1.7 $
   $Name:  $
   $Author: shoops $
   $Date: 2005/06/28 19:47:15 $
   End CVS Header */

#include "copasi.h"

#include "utilities/CVector.h"
#include "CProcessReport.h"
#include "report/CCopasiObject.h"

CProcessReportItem::CProcessReportItem():
    CCopasiParameter("NoName", CCopasiParameter::DOUBLE),
    mEndValue()
{
  mEndValue = mValue;
  mValue.pVOID = NULL;
}

CProcessReportItem::CProcessReportItem(const std::string & name,
                                       const Type & type,
                                       const void * pValue,
                                       const void * pEndValue):
    CCopasiParameter(name, type, pEndValue, NULL, "ProcessReportItem"),
    mEndValue(),
    mHasEndValue(pEndValue != NULL)
{
  mEndValue = mValue;
  mValue.pVOID = const_cast<void *>(pValue);
}

CProcessReportItem::CProcessReportItem(const CProcessReportItem & src):
    CCopasiParameter(src.getObjectName(), src.getType(), src.mEndValue.pVOID, NULL, "ProcessReportItem"),
    mEndValue()
{
  mEndValue = mValue;
  mValue = src.mValue;
}

CProcessReportItem::~CProcessReportItem()
{
  mValue = mEndValue;
}

const bool & CProcessReportItem::hasEndValue() const {return mHasEndValue;}

const CCopasiParameter::Value & CProcessReportItem::getEndValue() const
  {return mEndValue;}

CCopasiParameter::Value & CProcessReportItem::getEndValue()
{return mEndValue;}

CProcessReport::CProcessReport():
    mProcessReportItemList(1)
{mProcessReportItemList[0] = NULL;}

CProcessReport::~CProcessReport()
{
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    pdelete(mProcessReportItemList[i]);
}

unsigned C_INT32 CProcessReport::addItem(const std::string & name,
    const CCopasiParameter::Type & type,
    const void * pValue,
    const void * pEndValue)
{
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] == NULL) break;

  unsigned C_INT32 handle = i;

  if (i == imax) // We need to resize.
    {
      CVector< CProcessReportItem * > tmp = mProcessReportItemList;
      mProcessReportItemList.resize(2 * imax); // Note, imax is never zero

      for (i = 0; i < imax; i++)  // Copy existing items
        mProcessReportItemList[i] = tmp[i];

      imax *= 2;
      while (i < imax) mProcessReportItemList[i++] = NULL;
    }

  mProcessReportItemList[handle] = new CProcessReportItem(name, type, pValue, pEndValue);
  return handle;
}

bool CProcessReport::progress()
{
  bool success = true;
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] && !progress(i)) success = false;

  return success;
}

bool CProcessReport::progress(const unsigned C_INT32 & handle)
{return isValidHandle(handle);}

bool CProcessReport::proceed()
{return true;}

bool CProcessReport::reset()
{
  bool success = true;
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] && !reset(i)) success = false;

  return success;
}

bool CProcessReport::reset(const unsigned C_INT32 & handle)
{return isValidHandle(handle);}

bool CProcessReport::finish()
{
  bool success = true;
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] && !finish(i)) success = false;

  return success;
}

bool CProcessReport::finish(const unsigned C_INT32 & handle)
{
  if (!isValidHandle(handle)) return false;

  pdelete(mProcessReportItemList[handle]);
  return true;
}

bool CProcessReport::isValidHandle(const unsigned C_INT32 handle) const
  {
    return (handle < mProcessReportItemList.size() &&
            mProcessReportItemList[handle] != NULL);
  }

bool CProcessReport::setName(const std::string & name)
{
  mName = name;
  return true;
}
<commit_msg>Initialize hadEndValue porperly.<commit_after>/* Begin CVS Header
   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/utilities/CProcessReport.cpp,v $
   $Revision: 1.8 $
   $Name:  $
   $Author: shoops $
   $Date: 2005/06/28 20:03:32 $
   End CVS Header */

#include "copasi.h"

#include "utilities/CVector.h"
#include "CProcessReport.h"
#include "report/CCopasiObject.h"

CProcessReportItem::CProcessReportItem():
    CCopasiParameter("NoName", CCopasiParameter::DOUBLE),
    mEndValue(),
    mHasEndValue(false)
{
  mEndValue = mValue;
  mValue.pDOUBLE = NULL;
}

CProcessReportItem::CProcessReportItem(const std::string & name,
                                       const Type & type,
                                       const void * pValue,
                                       const void * pEndValue):
    CCopasiParameter(name, type, pEndValue, NULL, "ProcessReportItem"),
    mEndValue(),
    mHasEndValue(pEndValue != NULL)
{
  mEndValue = mValue;
  mValue.pVOID = const_cast<void *>(pValue);
}

CProcessReportItem::CProcessReportItem(const CProcessReportItem & src):
    CCopasiParameter(src.getObjectName(), src.getType(), src.mEndValue.pVOID, NULL, "ProcessReportItem"),
    mEndValue(),
    mHasEndValue(src.mHasEndValue)
{
  mEndValue = mValue;
  mValue = src.mValue;
}

CProcessReportItem::~CProcessReportItem()
{
  mValue = mEndValue;
}

const bool & CProcessReportItem::hasEndValue() const {return mHasEndValue;}

const CCopasiParameter::Value & CProcessReportItem::getEndValue() const
  {return mEndValue;}

CCopasiParameter::Value & CProcessReportItem::getEndValue()
{return mEndValue;}

CProcessReport::CProcessReport():
    mProcessReportItemList(1)
{mProcessReportItemList[0] = NULL;}

CProcessReport::~CProcessReport()
{
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    pdelete(mProcessReportItemList[i]);
}

unsigned C_INT32 CProcessReport::addItem(const std::string & name,
    const CCopasiParameter::Type & type,
    const void * pValue,
    const void * pEndValue)
{
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] == NULL) break;

  unsigned C_INT32 handle = i;

  if (i == imax) // We need to resize.
    {
      CVector< CProcessReportItem * > tmp = mProcessReportItemList;
      mProcessReportItemList.resize(2 * imax); // Note, imax is never zero

      for (i = 0; i < imax; i++)  // Copy existing items
        mProcessReportItemList[i] = tmp[i];

      imax *= 2;
      while (i < imax) mProcessReportItemList[i++] = NULL;
    }

  mProcessReportItemList[handle] = new CProcessReportItem(name, type, pValue, pEndValue);
  return handle;
}

bool CProcessReport::progress()
{
  bool success = true;
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] && !progress(i)) success = false;

  return success;
}

bool CProcessReport::progress(const unsigned C_INT32 & handle)
{return isValidHandle(handle);}

bool CProcessReport::proceed()
{return true;}

bool CProcessReport::reset()
{
  bool success = true;
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] && !reset(i)) success = false;

  return success;
}

bool CProcessReport::reset(const unsigned C_INT32 & handle)
{return isValidHandle(handle);}

bool CProcessReport::finish()
{
  bool success = true;
  unsigned C_INT32 i, imax = mProcessReportItemList.size();

  for (i = 0; i < imax; i++)
    if (mProcessReportItemList[i] && !finish(i)) success = false;

  return success;
}

bool CProcessReport::finish(const unsigned C_INT32 & handle)
{
  if (!isValidHandle(handle)) return false;

  pdelete(mProcessReportItemList[handle]);
  return true;
}

bool CProcessReport::isValidHandle(const unsigned C_INT32 handle) const
  {
    return (handle < mProcessReportItemList.size() &&
            mProcessReportItemList[handle] != NULL);
  }

bool CProcessReport::setName(const std::string & name)
{
  mName = name;
  return true;
}
<|endoftext|>


<commit_before>#include "musicsystemtraymenu.h"
#include "musicuiobject.h"

#include <QWidgetAction>
#include <QToolButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>

MusicSystemTrayMenu::MusicSystemTrayMenu(QWidget *parent)
    : QMenu(parent)
{
    setStyleSheet(MusicUIObject::MMenuStyle02);
    createPlayWidgetActions();
    addAction(m_widgetAction);

    m_showLrcAction = new QAction(QIcon(":/contextMenu/lrc"),tr("showDeskLrc"),this);
    connect(m_showLrcAction,SIGNAL(triggered()),SLOT(showDesktopLrc()));
    m_lockLrcAction = new QAction(QIcon(":/contextMenu/lock"),tr("lockLrc"),this);
    connect(m_lockLrcAction,SIGNAL(triggered()),SIGNAL(setWindowLockedChanged()));

    addSeparator();
    addAction(QIcon(":/contextMenu/window"),tr("showMainWindow"),parent,SLOT(showNormal()));
    addSeparator();
    addAction(QIcon(":/contextMenu/setting"),tr("showSetting"),parent,SLOT(musicSetting()));
    addAction(m_showLrcAction);
    addSeparator();
    addAction(m_lockLrcAction);
    addSeparator();
    addAction(QIcon(":/contextMenu/quit"),tr("appClose"),parent,SLOT(quitWindowClose()));
}

MusicSystemTrayMenu::~MusicSystemTrayMenu()
{
    delete m_showText;
    delete m_PlayOrStop;
    delete m_showLrcAction;
    delete m_lockLrcAction;
    delete m_widgetAction;
}

void MusicSystemTrayMenu::createPlayWidgetActions()
{
    m_widgetAction = new QWidgetAction(this);
    QWidget *widgetActionContainer = new QWidget(this);
    QVBoxLayout *vbox = new QVBoxLayout(widgetActionContainer);
    vbox->setMargin(0);

    QWidget *widgetContainer = new QWidget(widgetActionContainer);
    QHBoxLayout *box = new QHBoxLayout(widgetContainer);
    box->setMargin(0);

    QToolButton *previousPlay = new QToolButton(widgetContainer);
    QToolButton *nextPlay = new QToolButton(widgetContainer);
    m_PlayOrStop = new QToolButton(widgetContainer);

    previousPlay->setIcon(QIcon(QString::fromUtf8(":/contextMenu/sysprivious")));
    nextPlay->setIcon(QIcon(QString::fromUtf8(":/contextMenu/sysnext")));
    m_PlayOrStop->setIcon(QIcon(QString::fromUtf8(":/contextMenu/sysplay")));

    previousPlay->setIconSize(QSize(40,40));
    nextPlay->setIconSize(QSize(40,40));
    m_PlayOrStop->setIconSize(QSize(45,45));

    previousPlay->setStyleSheet(MusicUIObject::MToolButtonStyle01);
    nextPlay->setStyleSheet(MusicUIObject::MToolButtonStyle01);
    m_PlayOrStop->setStyleSheet(MusicUIObject::MToolButtonStyle01);

    previousPlay->setCursor(QCursor(Qt::PointingHandCursor));
    nextPlay->setCursor(QCursor(Qt::PointingHandCursor));
    m_PlayOrStop->setCursor(QCursor(Qt::PointingHandCursor));

    previousPlay->setToolTip(tr("Privious"));
    nextPlay->setToolTip(tr("Next"));
    m_PlayOrStop->setToolTip(tr("Play"));

    box->addWidget(previousPlay);
    box->addWidget(m_PlayOrStop);
    box->addWidget(nextPlay);

    m_showText = new QLabel(widgetActionContainer);
    m_showText->setAlignment(Qt::AlignCenter);
    m_showText->setStyleSheet(MusicUIObject::MCustomStyle12);
    vbox->addWidget(widgetContainer);
    vbox->addWidget(m_showText);
    widgetActionContainer->setLayout(vbox);
    m_widgetAction->setDefaultWidget(widgetActionContainer);

    connect(previousPlay, SIGNAL(clicked()), parent(), SLOT(musicPlayPrivious()));
    connect(nextPlay, SIGNAL(clicked()), parent(), SLOT(musicPlayNext()));
    connect(m_PlayOrStop, SIGNAL(clicked()), parent(), SLOT(musicKey()));
}

void MusicSystemTrayMenu::setLabelText(const QString &text) const
{
    QFontMetrics str(font());
    m_showText->setText(str.elidedText(text, Qt::ElideRight,160));
    m_showText->setToolTip(text);
}

void MusicSystemTrayMenu::showDesktopLrc(const QString &show) const
{
    m_showLrcAction->setText((show == "true") ? tr("hideDeskLrc") : tr("showDeskLrc"));
    m_lockLrcAction->setEnabled((show == "true") ? true : false);
}

void MusicSystemTrayMenu::lockDesktopLrc(bool lock)
{
    m_lockLrcAction->setText(!lock ? tr("lockLrc") : tr("unlockLrc"));
}

void MusicSystemTrayMenu::showPlayStatus(bool status) const
{
    m_PlayOrStop->setIcon(QIcon(QString::fromUtf8(!status ? ":/contextMenu/sysstop"
                                                          : ":/contextMenu/sysplay")) );
}

void MusicSystemTrayMenu::showDesktopLrc()
{
    bool show = m_showLrcAction->text().trimmed() == tr("showDeskLrc").trimmed();
    m_showLrcAction->setText(show ? tr("hideDeskLrc") : tr("showDeskLrc"));
    m_lockLrcAction->setEnabled(show);
    emit setShowDesktopLrc(show);
}
<commit_msg>clean code for musicsystemtray[256528]<commit_after>#include "musicsystemtraymenu.h"
#include "musicuiobject.h"

#include <QWidgetAction>
#include <QToolButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>

MusicSystemTrayMenu::MusicSystemTrayMenu(QWidget *parent)
    : QMenu(parent)
{
    setStyleSheet(MusicUIObject::MMenuStyle02);
    createPlayWidgetActions();
    addAction(m_widgetAction);

    m_showLrcAction = new QAction(QIcon(":/contextMenu/lrc"),tr("showDeskLrc"), this);
    connect(m_showLrcAction, SIGNAL(triggered()), SLOT(showDesktopLrc()));
    m_lockLrcAction = new QAction(QIcon(":/contextMenu/lock"), tr("lockLrc"), this);
    connect(m_lockLrcAction, SIGNAL(triggered()), SIGNAL(setWindowLockedChanged()));

    addSeparator();
    addAction(QIcon(":/contextMenu/window"), tr("showMainWindow"), parent, SLOT(showNormal()));
    addSeparator();
    addAction(QIcon(":/contextMenu/setting"), tr("showSetting"), parent, SLOT(musicSetting()));
    addAction(m_showLrcAction);
    addSeparator();
    addAction(m_lockLrcAction);
    addSeparator();
    addAction(QIcon(":/contextMenu/quit"), tr("appClose"), parent, SLOT(quitWindowClose()));
}

MusicSystemTrayMenu::~MusicSystemTrayMenu()
{
    delete m_showText;
    delete m_PlayOrStop;
    delete m_showLrcAction;
    delete m_lockLrcAction;
    delete m_widgetAction;
}

void MusicSystemTrayMenu::createPlayWidgetActions()
{
    m_widgetAction = new QWidgetAction(this);
    QWidget *widgetActionContainer = new QWidget(this);
    QVBoxLayout *vbox = new QVBoxLayout(widgetActionContainer);
    vbox->setMargin(0);

    QWidget *widgetContainer = new QWidget(widgetActionContainer);
    QHBoxLayout *box = new QHBoxLayout(widgetContainer);
    box->setMargin(0);

    QToolButton *previousPlay = new QToolButton(widgetContainer);
    QToolButton *nextPlay = new QToolButton(widgetContainer);
    m_PlayOrStop = new QToolButton(widgetContainer);

    previousPlay->setIcon(QIcon(QString::fromUtf8(":/contextMenu/sysprivious")));
    nextPlay->setIcon(QIcon(QString::fromUtf8(":/contextMenu/sysnext")));
    m_PlayOrStop->setIcon(QIcon(QString::fromUtf8(":/contextMenu/sysplay")));

    previousPlay->setIconSize(QSize(40, 40));
    nextPlay->setIconSize(QSize(40, 40));
    m_PlayOrStop->setIconSize(QSize(45, 45));

    previousPlay->setStyleSheet(MusicUIObject::MToolButtonStyle01);
    nextPlay->setStyleSheet(MusicUIObject::MToolButtonStyle01);
    m_PlayOrStop->setStyleSheet(MusicUIObject::MToolButtonStyle01);

    previousPlay->setCursor(QCursor(Qt::PointingHandCursor));
    nextPlay->setCursor(QCursor(Qt::PointingHandCursor));
    m_PlayOrStop->setCursor(QCursor(Qt::PointingHandCursor));

    previousPlay->setToolTip(tr("Privious"));
    nextPlay->setToolTip(tr("Next"));
    m_PlayOrStop->setToolTip(tr("Play"));

    box->addWidget(previousPlay);
    box->addWidget(m_PlayOrStop);
    box->addWidget(nextPlay);

    m_showText = new QLabel(widgetActionContainer);
    m_showText->setAlignment(Qt::AlignCenter);
    m_showText->setStyleSheet(MusicUIObject::MCustomStyle12);
    vbox->addWidget(widgetContainer);
    vbox->addWidget(m_showText);
    widgetActionContainer->setLayout(vbox);
    m_widgetAction->setDefaultWidget(widgetActionContainer);

    connect(previousPlay, SIGNAL(clicked()), parent(), SLOT(musicPlayPrivious()));
    connect(nextPlay, SIGNAL(clicked()), parent(), SLOT(musicPlayNext()));
    connect(m_PlayOrStop, SIGNAL(clicked()), parent(), SLOT(musicKey()));
}

void MusicSystemTrayMenu::setLabelText(const QString &text) const
{
    QFontMetrics str(font());
    m_showText->setText(str.elidedText(text, Qt::ElideRight,160));
    m_showText->setToolTip(text);
}

void MusicSystemTrayMenu::showDesktopLrc(const QString &show) const
{
    m_showLrcAction->setText((show == "true") ? tr("hideDeskLrc") : tr("showDeskLrc"));
    m_lockLrcAction->setEnabled((show == "true") ? true : false);
}

void MusicSystemTrayMenu::lockDesktopLrc(bool lock)
{
    m_lockLrcAction->setText(!lock ? tr("lockLrc") : tr("unlockLrc"));
}

void MusicSystemTrayMenu::showPlayStatus(bool status) const
{
    m_PlayOrStop->setIcon(QIcon(QString::fromUtf8(!status ? ":/contextMenu/sysstop"
                                                          : ":/contextMenu/sysplay")) );
}

void MusicSystemTrayMenu::showDesktopLrc()
{
    bool show = m_showLrcAction->text().trimmed() == tr("showDeskLrc").trimmed();
    m_showLrcAction->setText(show ? tr("hideDeskLrc") : tr("showDeskLrc"));
    m_lockLrcAction->setEnabled(show);
    emit setShowDesktopLrc(show);
}
<|endoftext|>


<commit_before>/*
 *  despot2fm.cpp
 *
 *  Created by Tobias Wood on 2015/06/03.
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>
#include <Eigen/Dense>
#include "ceres/ceres.h"

#include "Util.h"
#include "ImageIO.h"
#include "Args.h"
#include "Models.h"
#include "ApplyTypes.h"
#include "SSFPSequence.h"
#include "SequenceCereal.h"

class FMCost : public ceres::CostFunction {
private:
    const Eigen::ArrayXd &m_data;
    double m_T1, m_B1;
    QI::SSFPSequence m_sequence;

public:
    FMCost(const Eigen::ArrayXd &d, const QI::SSFPSequence &s,
           const double T1, const double B1) :
        m_data(d), m_T1(T1), m_B1(B1), m_sequence(s)
    {
        mutable_parameter_block_sizes()->push_back(3);
        set_num_residuals(d.size());
    }

    Eigen::ArrayXd residuals(const Eigen::VectorXd &p) const {
        Eigen::ArrayXd s = QI::One_SSFP_Echo_Magnitude(m_sequence.FA, m_sequence.PhaseInc, m_sequence.TR, p[0], m_T1, p[1], p[2], m_B1);
        Eigen::ArrayXd diff = s - m_data;
        return diff;
    }

    bool Evaluate(double const* const* parameters,
                  double* resids,
                  double** jacobians) const override
    {
        Eigen::Map<const Eigen::Array3d> p(parameters[0]);
        Eigen::Map<Eigen::ArrayXd> r(resids, m_data.size());
        r = residuals(p);
        if (jacobians && jacobians[0]) {
            Eigen::Map<Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> j(jacobians[0], m_data.size(), p.size());
            j = QI::One_SSFP_Echo_Derivs(m_sequence.FA, m_sequence.PhaseInc, m_sequence.TR, p[0], m_T1, p[1], p[2], m_B1);
        }
        return true;
    }

};

class LM_FM : public QI::ApplyF::Algorithm {
protected:
    QI::SSFPSequence m_sequence;
    bool m_asymmetric = false, m_debug = false;
public:
    LM_FM(QI::SSFPSequence s, const bool a, const bool d) :
        m_sequence(s), m_asymmetric(a), m_debug(d)
    {}

    size_t numInputs() const override  { return m_sequence.count(); }
    size_t numConsts() const override  { return 2; }
    size_t numOutputs() const override { return 3; }
    size_t dataSize() const override   { return m_sequence.size(); }
    float zero() const override { return 0.f; }
    std::vector<float> defaultConsts() const override {
        std::vector<float> def(2, 1.0f); // T1 & B1
        return def;
    }

    bool apply(const std::vector<TInput> &inputs, const std::vector<TConst> &consts,
               const TIndex &, // Unused
               std::vector<TOutput> &outputs, TConst &residual,
               TInput &resids, TIterations &its) const override
    {
        const double T1 = consts[0];
        const double B1 = consts[1];
        if (std::isfinite(T1) && (T1 > m_sequence.TR)) {
            // Improve scaling by dividing the PD down to something sensible.
            // This gets scaled back up at the end.
            Eigen::Map<const Eigen::ArrayXf> indata(inputs[0].GetDataPointer(), inputs[0].Size());
            Eigen::ArrayXd data = indata.cast<double>() / indata.maxCoeff();

            std::vector<double> f0_starts = {0, 0.4/m_sequence.TR};
            if (this->m_asymmetric) {
                f0_starts.push_back(0.2/m_sequence.TR);
                f0_starts.push_back(-0.2/m_sequence.TR);
                f0_starts.push_back(-0.4/m_sequence.TR);
            }

            double best = std::numeric_limits<double>::infinity();
            Eigen::Array3d p, bestP;
            ceres::Problem problem;
            problem.AddResidualBlock(new FMCost(data, m_sequence, T1, B1), NULL, p.data());
            problem.SetParameterLowerBound(p.data(), 0, 1.);
            problem.SetParameterLowerBound(p.data(), 1, m_sequence.TR);
            problem.SetParameterUpperBound(p.data(), 1, T1);
            problem.SetParameterLowerBound(p.data(), 2, -0.5/m_sequence.TR);
            problem.SetParameterUpperBound(p.data(), 2,  0.5/m_sequence.TR);
            ceres::Solver::Options options;
            ceres::Solver::Summary summary;
            options.max_num_iterations = 75;
            options.function_tolerance = 1e-6;
            options.gradient_tolerance = 1e-7;
            options.parameter_tolerance = 1e-5;
            if (!m_debug) options.logging_type = ceres::SILENT;
            for (const double &f0 : f0_starts) {
                p = {5., std::max(0.1 * T1, 1.5*m_sequence.TR), f0}; // Yarnykh gives T2 = 0.045 * T1 in brain, but best to overestimate for CSF
                ceres::Solve(options, &problem, &summary);
                if (!summary.IsSolutionUsable()) {
                    std::cerr << summary.FullReport() << std::endl;
                    std::cerr << "T1: " << T1 << " B1: " << B1 << std::endl;
                    std::cerr << "Parameters: " << p.transpose() << std::endl;
                    std::cerr << "Data: " << indata.transpose() << std::endl;
                    return false;
                }
                double r = summary.final_cost;
                if (r < best) {
                    best = r;
                    bestP = p;
                    its = summary.iterations.size();
                }
            }
            if (m_debug) std::cout << summary.FullReport() << std::endl;
            outputs[0] = bestP[0] * indata.maxCoeff();
            outputs[1] = bestP[1];
            outputs[2] = bestP[2];

            residual = best * indata.maxCoeff();
            if (resids.Size() > 0) {
                assert(resids.Size() == data.size());
                std::vector<double> r_temp(data.size());
                p = bestP; // Make sure the correct parameters are in the block
                problem.Evaluate(ceres::Problem::EvaluateOptions(), NULL, &r_temp, NULL, NULL);
                for (int i = 0; i < r_temp.size(); i++)
                    resids[i] = r_temp[i];
            }
        } else {
            outputs[0] = 0.;
            outputs[1] = 0.;
            outputs[2] = 0.;
            residual = 0;
            resids.Fill(0.);
            its = 0;
        }
        return true;
    }
};

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
    Eigen::initParallel();
    args::ArgumentParser parser("Calculates a T2 map from SSFP data and a T1 map.\nhttp://github.com/spinicist/QUIT");

    args::Positional<std::string> t1_path(parser, "T1_MAP", "Input T1 map");
    args::Positional<std::string> ssfp_path(parser, "SSFP_FILE", "Input SSFP file");

    args::HelpFlag help(parser, "HELP", "Show this help message", {'h', "help"});
    args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
    args::ValueFlag<int> threads(parser, "THREADS", "Use N threads (default=4, 0=hardware limit)", {'T', "threads"}, 4);
    args::ValueFlag<std::string> outarg(parser, "OUTPREFIX", "Add a prefix to output filenames", {'o', "out"});
    args::ValueFlag<std::string> B1(parser, "B1", "B1 map (ratio) file", {'b', "B1"});
    args::ValueFlag<std::string> mask(parser, "MASK", "Only process voxels within the mask", {'m', "mask"});
    args::Flag asym(parser, "ASYM", "Fit +/- off-resonance frequency", {'A', "asym"});
    args::ValueFlag<std::string> subregion(parser, "SUBREGION", "Process subregion starting at voxel I,J,K with size SI,SJ,SK", {'s', "subregion"});
    args::Flag debug(parser, "DEBUG", "Output debugging messages", {'d', "debug"});
    args::Flag resids(parser, "RESIDS", "Write out residuals for each data-point", {'r', "resids"});
    QI::ParseArgs(parser, argc, argv, verbose);

    if (verbose) std::cout << "Reading T1 Map from: " << QI::CheckPos(t1_path) << std::endl;
    auto T1 = QI::ReadImage(QI::CheckPos(t1_path));
    if (verbose) std::cout << "Opening SSFP file: " << QI::CheckPos(ssfp_path) << std::endl;
    auto ssfpData = QI::ReadVectorImage<float>(QI::CheckPos(ssfp_path));

    auto ssfp_sequence = QI::ReadSequence<QI::SSFPSequence>(std::cin, verbose);
    auto apply = QI::ApplyF::New();
    std::shared_ptr<LM_FM> algo = std::make_shared<LM_FM>(ssfp_sequence, asym, debug);
    apply->SetVerbose(verbose);
    apply->SetAlgorithm(algo);
    apply->SetOutputAllResiduals(resids);
    if (verbose) std::cout << "Using " << threads.Get() << " threads" << std::endl;
    apply->SetPoolsize(threads.Get());
    apply->SetSplitsPerThread(threads.Get()); // Fairly unbalanced algorithm
    apply->SetInput(0, ssfpData);
    apply->SetConst(0, T1);
    if (B1) apply->SetConst(1, QI::ReadImage(B1.Get()));
    if (mask) apply->SetMask(QI::ReadImage(mask.Get()));
    if (subregion) apply->SetSubregion(QI::RegionArg(args::get(subregion)));
    if (verbose) {
        std::cout << "Processing" << std::endl;
        auto monitor = QI::GenericMonitor::New();
        apply->AddObserver(itk::ProgressEvent(), monitor);
    }
    apply->Update();
    if (verbose) {
        std::cout << "Elapsed time was " << apply->GetTotalTime() << "s" << std::endl;
        std::cout << "Writing results files." << std::endl;
    }
    std::string outPrefix = args::get(outarg) + "FM_";
    QI::WriteImage(apply->GetOutput(0), outPrefix + "PD" + QI::OutExt());
    QI::WriteImage(apply->GetOutput(1), outPrefix + "T2" + QI::OutExt());
    QI::WriteImage(apply->GetOutput(2), outPrefix + "f0" + QI::OutExt());
    QI::WriteImage(apply->GetIterationsOutput(), outPrefix + "its" + QI::OutExt());
    QI::WriteScaledImage(apply->GetResidualOutput(), apply->GetOutput(0), outPrefix + "residual" + QI::OutExt());
    if (resids) {
        QI::WriteScaledVectorImage(apply->GetAllResidualsOutput(), apply->GetOutput(0), outPrefix + "all_residuals" + QI::OutExt());
    }
    return EXIT_SUCCESS;
}
<commit_msg>BUG: Lower bound on qidespot2fm f0 not set correctly<commit_after>/*
 *  despot2fm.cpp
 *
 *  Created by Tobias Wood on 2015/06/03.
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>
#include <Eigen/Dense>
#include "ceres/ceres.h"

#include "Util.h"
#include "ImageIO.h"
#include "Args.h"
#include "Models.h"
#include "ApplyTypes.h"
#include "SSFPSequence.h"
#include "SequenceCereal.h"

class FMCost : public ceres::CostFunction {
private:
    const Eigen::ArrayXd &m_data;
    double m_T1, m_B1;
    QI::SSFPSequence m_sequence;

public:
    FMCost(const Eigen::ArrayXd &d, const QI::SSFPSequence &s,
           const double T1, const double B1) :
        m_data(d), m_T1(T1), m_B1(B1), m_sequence(s)
    {
        mutable_parameter_block_sizes()->push_back(3);
        set_num_residuals(d.size());
    }

    Eigen::ArrayXd residuals(const Eigen::VectorXd &p) const {
        Eigen::ArrayXd s = QI::One_SSFP_Echo_Magnitude(m_sequence.FA, m_sequence.PhaseInc, m_sequence.TR, p[0], m_T1, p[1], p[2], m_B1);
        Eigen::ArrayXd diff = s - m_data;
        return diff;
    }

    bool Evaluate(double const* const* parameters,
                  double* resids,
                  double** jacobians) const override
    {
        Eigen::Map<const Eigen::Array3d> p(parameters[0]);
        Eigen::Map<Eigen::ArrayXd> r(resids, m_data.size());
        r = residuals(p);
        if (jacobians && jacobians[0]) {
            Eigen::Map<Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> j(jacobians[0], m_data.size(), p.size());
            j = QI::One_SSFP_Echo_Derivs(m_sequence.FA, m_sequence.PhaseInc, m_sequence.TR, p[0], m_T1, p[1], p[2], m_B1);
        }
        return true;
    }

};

class LM_FM : public QI::ApplyF::Algorithm {
protected:
    QI::SSFPSequence m_sequence;
    bool m_asymmetric = false, m_debug = false;
public:
    LM_FM(QI::SSFPSequence s, const bool a, const bool d) :
        m_sequence(s), m_asymmetric(a), m_debug(d)
    {}

    size_t numInputs() const override  { return m_sequence.count(); }
    size_t numConsts() const override  { return 2; }
    size_t numOutputs() const override { return 3; }
    size_t dataSize() const override   { return m_sequence.size(); }
    float zero() const override { return 0.f; }
    std::vector<float> defaultConsts() const override {
        std::vector<float> def(2, 1.0f); // T1 & B1
        return def;
    }

    bool apply(const std::vector<TInput> &inputs, const std::vector<TConst> &consts,
               const TIndex &, // Unused
               std::vector<TOutput> &outputs, TConst &residual,
               TInput &resids, TIterations &its) const override
    {
        const double T1 = consts[0];
        const double B1 = consts[1];
        if (std::isfinite(T1) && (T1 > m_sequence.TR)) {
            // Improve scaling by dividing the PD down to something sensible.
            // This gets scaled back up at the end.
            Eigen::Map<const Eigen::ArrayXf> indata(inputs[0].GetDataPointer(), inputs[0].Size());
            Eigen::ArrayXd data = indata.cast<double>() / indata.maxCoeff();

            std::vector<double> f0_starts = {0, 0.4/m_sequence.TR};
            if (this->m_asymmetric) {
                f0_starts.push_back(0.2/m_sequence.TR);
                f0_starts.push_back(-0.2/m_sequence.TR);
                f0_starts.push_back(-0.4/m_sequence.TR);
            }

            double best = std::numeric_limits<double>::infinity();
            Eigen::Array3d p, bestP;
            ceres::Problem problem;
            problem.AddResidualBlock(new FMCost(data, m_sequence, T1, B1), NULL, p.data());
            problem.SetParameterLowerBound(p.data(), 0, 1.);
            problem.SetParameterLowerBound(p.data(), 1, m_sequence.TR);
            problem.SetParameterUpperBound(p.data(), 1, T1);
            if (this->m_asymmetric) {
                problem.SetParameterLowerBound(p.data(), 2, -0.5/m_sequence.TR);
            } else {
                problem.SetParameterLowerBound(p.data(), 2, 0.0);
            }
            problem.SetParameterUpperBound(p.data(), 2,  0.5/m_sequence.TR);
            ceres::Solver::Options options;
            ceres::Solver::Summary summary;
            options.max_num_iterations = 75;
            options.function_tolerance = 1e-6;
            options.gradient_tolerance = 1e-7;
            options.parameter_tolerance = 1e-5;
            if (!m_debug) options.logging_type = ceres::SILENT;
            for (const double &f0 : f0_starts) {
                p = {5., std::max(0.1 * T1, 1.5*m_sequence.TR), f0}; // Yarnykh gives T2 = 0.045 * T1 in brain, but best to overestimate for CSF
                ceres::Solve(options, &problem, &summary);
                if (!summary.IsSolutionUsable()) {
                    std::cerr << summary.FullReport() << std::endl;
                    std::cerr << "T1: " << T1 << " B1: " << B1 << std::endl;
                    std::cerr << "Parameters: " << p.transpose() << std::endl;
                    std::cerr << "Data: " << indata.transpose() << std::endl;
                    return false;
                }
                double r = summary.final_cost;
                if (r < best) {
                    best = r;
                    bestP = p;
                    its = summary.iterations.size();
                }
            }
            if (m_debug) std::cout << summary.FullReport() << std::endl;
            outputs[0] = bestP[0] * indata.maxCoeff();
            outputs[1] = bestP[1];
            outputs[2] = bestP[2];

            residual = best * indata.maxCoeff();
            if (resids.Size() > 0) {
                assert(resids.Size() == data.size());
                std::vector<double> r_temp(data.size());
                p = bestP; // Make sure the correct parameters are in the block
                problem.Evaluate(ceres::Problem::EvaluateOptions(), NULL, &r_temp, NULL, NULL);
                for (int i = 0; i < r_temp.size(); i++)
                    resids[i] = r_temp[i];
            }
        } else {
            outputs[0] = 0.;
            outputs[1] = 0.;
            outputs[2] = 0.;
            residual = 0;
            resids.Fill(0.);
            its = 0;
        }
        return true;
    }
};

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
    Eigen::initParallel();
    args::ArgumentParser parser("Calculates a T2 map from SSFP data and a T1 map.\nhttp://github.com/spinicist/QUIT");

    args::Positional<std::string> t1_path(parser, "T1_MAP", "Input T1 map");
    args::Positional<std::string> ssfp_path(parser, "SSFP_FILE", "Input SSFP file");

    args::HelpFlag help(parser, "HELP", "Show this help message", {'h', "help"});
    args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
    args::ValueFlag<int> threads(parser, "THREADS", "Use N threads (default=4, 0=hardware limit)", {'T', "threads"}, 4);
    args::ValueFlag<std::string> outarg(parser, "OUTPREFIX", "Add a prefix to output filenames", {'o', "out"});
    args::ValueFlag<std::string> B1(parser, "B1", "B1 map (ratio) file", {'b', "B1"});
    args::ValueFlag<std::string> mask(parser, "MASK", "Only process voxels within the mask", {'m', "mask"});
    args::Flag asym(parser, "ASYM", "Fit +/- off-resonance frequency", {'A', "asym"});
    args::ValueFlag<std::string> subregion(parser, "SUBREGION", "Process subregion starting at voxel I,J,K with size SI,SJ,SK", {'s', "subregion"});
    args::Flag debug(parser, "DEBUG", "Output debugging messages", {'d', "debug"});
    args::Flag resids(parser, "RESIDS", "Write out residuals for each data-point", {'r', "resids"});
    QI::ParseArgs(parser, argc, argv, verbose);

    if (verbose) std::cout << "Reading T1 Map from: " << QI::CheckPos(t1_path) << std::endl;
    auto T1 = QI::ReadImage(QI::CheckPos(t1_path));
    if (verbose) std::cout << "Opening SSFP file: " << QI::CheckPos(ssfp_path) << std::endl;
    auto ssfpData = QI::ReadVectorImage<float>(QI::CheckPos(ssfp_path));

    auto ssfp_sequence = QI::ReadSequence<QI::SSFPSequence>(std::cin, verbose);
    auto apply = QI::ApplyF::New();
    std::shared_ptr<LM_FM> algo = std::make_shared<LM_FM>(ssfp_sequence, asym, debug);
    apply->SetVerbose(verbose);
    apply->SetAlgorithm(algo);
    apply->SetOutputAllResiduals(resids);
    if (verbose) std::cout << "Using " << threads.Get() << " threads" << std::endl;
    apply->SetPoolsize(threads.Get());
    apply->SetSplitsPerThread(threads.Get()); // Fairly unbalanced algorithm
    apply->SetInput(0, ssfpData);
    apply->SetConst(0, T1);
    if (B1) apply->SetConst(1, QI::ReadImage(B1.Get()));
    if (mask) apply->SetMask(QI::ReadImage(mask.Get()));
    if (subregion) apply->SetSubregion(QI::RegionArg(args::get(subregion)));
    if (verbose) {
        std::cout << "Processing" << std::endl;
        auto monitor = QI::GenericMonitor::New();
        apply->AddObserver(itk::ProgressEvent(), monitor);
    }
    apply->Update();
    if (verbose) {
        std::cout << "Elapsed time was " << apply->GetTotalTime() << "s" << std::endl;
        std::cout << "Writing results files." << std::endl;
    }
    std::string outPrefix = args::get(outarg) + "FM_";
    QI::WriteImage(apply->GetOutput(0), outPrefix + "PD" + QI::OutExt());
    QI::WriteImage(apply->GetOutput(1), outPrefix + "T2" + QI::OutExt());
    QI::WriteImage(apply->GetOutput(2), outPrefix + "f0" + QI::OutExt());
    QI::WriteImage(apply->GetIterationsOutput(), outPrefix + "its" + QI::OutExt());
    QI::WriteScaledImage(apply->GetResidualOutput(), apply->GetOutput(0), outPrefix + "residual" + QI::OutExt());
    if (resids) {
        QI::WriteScaledVectorImage(apply->GetAllResidualsOutput(), apply->GetOutput(0), outPrefix + "all_residuals" + QI::OutExt());
    }
    return EXIT_SUCCESS;
}
<|endoftext|>