<commit_before>/*
 * Copyright 2016 CodiLime
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "visualisation/trigram.h"

#include <stdio.h>
#include <string.h>

#include <algorithm>
#include <functional>
#include <vector>

#include <QLabel>
#include <QMouseEvent>
#include <QPainter>
#include <QSlider>
#include <QPixmap>
#include <QBitmap>
#include <QHBoxLayout>

namespace veles {
namespace visualisation {

const int k_minimum_brightness = 25;
const int k_maximum_brightness = 103;
const double k_brightness_heuristic_threshold = 0.66;
const int k_brightness_heuristic_min = 38;
const int k_brightness_heuristic_max = 66;
// decrease this to reduce noise (but you may lose data if you overdo it)
const double k_brightness_heuristic_scaling = 2.5;

TrigramWidget::TrigramWidget(QWidget *parent) :
  VisualisationWidget(parent), angle(0), c_sph(0), c_cyl(0), c_pos(0),
  shape_(EVisualisationShape::CUBE), mode_(EVisualisationMode::TRIGRAM),
  brightness_((k_maximum_brightness + k_minimum_brightness) / 2),
  brightness_slider_(nullptr), is_playing_(true),
  use_brightness_heuristic_(true) {}

TrigramWidget::~TrigramWidget() {
  makeCurrent();
  delete texture;
  delete databuf;
  doneCurrent();
}

void TrigramWidget::setBrightness(const int value) {
  brightness_ = value;
  c_brightness = static_cast<float>(value) * value * value;
  c_brightness /= getDataSize();
}

void TrigramWidget::setMode(EVisualisationMode mode, bool animate) {
  mode_ = mode;
  if (mode_ == EVisualisationMode::LAYERED_DIGRAM && !animate) {
    c_pos = 1;
  } else if (mode_ == EVisualisationMode::TRIGRAM && !animate) {
    c_pos = 0;
  }
}

void TrigramWidget::refresh() {
  if (use_brightness_heuristic_) {
    autoSetBrightness();
  }
  setBrightness(brightness_);
  makeCurrent();
  delete texture;
  delete databuf;
  initTextures();
  doneCurrent();
}

QIcon TrigramWidget::getColoredIcon(QString path, bool black_only) {
  QPixmap pixmap(path);
  QPixmap mask;
  if (black_only) {
    mask = pixmap.createMaskFromColor(QColor("black"), Qt::MaskOutColor);
  } else {
    mask = pixmap.createMaskFromColor(QColor("white"), Qt::MaskInColor);
  }
  pixmap.fill(palette().color(QPalette::WindowText));
  pixmap.setMask(mask);
  return QIcon(pixmap);
}

bool TrigramWidget::prepareOptionsPanel(QBoxLayout *layout) {
  VisualisationWidget::prepareOptionsPanel(layout);

  QLabel *brightness_label = new QLabel("Brightness: ");
  brightness_label->setAlignment(Qt::AlignTop);
  layout->addWidget(brightness_label);

  brightness_ = suggestBrightness();
  brightness_slider_ = new QSlider(Qt::Horizontal);
  brightness_slider_->setMinimum(k_minimum_brightness);
  brightness_slider_->setMaximum(k_maximum_brightness);
  brightness_slider_->setValue(brightness_);
  connect(brightness_slider_, SIGNAL(valueChanged(int)), this,
          SLOT(brightnessSliderMoved(int)));
  layout->addWidget(brightness_slider_);

  use_heuristic_checkbox_ = new QCheckBox(
    "Automatically adjust brightness");
  use_heuristic_checkbox_->setChecked(use_brightness_heuristic_);
  connect(use_heuristic_checkbox_, SIGNAL(stateChanged(int)),
          this, SLOT(setUseBrightnessHeuristic(int)));
  layout->addWidget(use_heuristic_checkbox_);

  pause_button_ = new QPushButton();
  pause_button_->setIcon(getColoredIcon(":/images/pause.png"));
  layout->addWidget(pause_button_);
  connect(pause_button_, SIGNAL(released()),
          this, SLOT(playPause()));

  QHBoxLayout *shape_box = new QHBoxLayout();
  cube_button_ = new QPushButton();
  cube_button_->setIcon(getColoredIcon(":/images/cube.png", false));
  cube_button_->setIconSize(QSize(32, 32));
  connect(cube_button_, &QPushButton::released,
          std::bind(&TrigramWidget::setShape, this,
                    EVisualisationShape::CUBE));
  shape_box->addWidget(cube_button_);

  cylinder_button_ = new QPushButton();
  cylinder_button_->setIcon(getColoredIcon(":/images/cylinder.png", false));
  cylinder_button_->setIconSize(QSize(32, 32));
  connect(cylinder_button_, &QPushButton::released,
          std::bind(&TrigramWidget::setShape, this,
                    EVisualisationShape::CYLINDER));
  shape_box->addWidget(cylinder_button_);

  sphere_button_ = new QPushButton();
  sphere_button_->setIcon(getColoredIcon(":/images/sphere.png"));
  sphere_button_->setIconSize(QSize(32, 32));

  connect(sphere_button_, &QPushButton::released,
          std::bind(&TrigramWidget::setShape, this,
                    EVisualisationShape::SPHERE));
  shape_box->addWidget(sphere_button_);

  layout->addLayout(shape_box);

  return true;
}

int TrigramWidget::suggestBrightness() {
  int size = getDataSize();
  auto data = reinterpret_cast<const uint8_t*>(getData());
  if (size < 100) {
    return (k_minimum_brightness + k_maximum_brightness) / 2;
  }
  std::vector<uint64_t> counts(256, 0);
  for (int i = 0; i < size; ++i) {
    counts[data[i]] += 1;
  }
  std::sort(counts.begin(), counts.end());
  int offset = 0, sum = 0;
  while (offset < 255 && sum < k_brightness_heuristic_threshold * size) {
    sum += counts[255 - offset];
    offset += 1;
  }
  offset = static_cast<int>(static_cast<double>(offset)
                            / k_brightness_heuristic_scaling);
  return std::max(k_brightness_heuristic_min,
                  k_brightness_heuristic_max - offset);
}

void TrigramWidget::playPause() {
  QPixmap pixmap;
  if (is_playing_) {
    pause_button_->setIcon(getColoredIcon(":/images/play.png"));
  } else {
    pause_button_->setIcon(getColoredIcon(":/images/pause.png"));
  }
  is_playing_ = !is_playing_;
}

void TrigramWidget::setShape(EVisualisationShape shape) {
  shape_ = shape;
}

void TrigramWidget::brightnessSliderMoved(int value) {
  if (value == brightness_) return;
  use_brightness_heuristic_ = false;
  use_heuristic_checkbox_->setChecked(false);
  setBrightness(value);
}

void TrigramWidget::setUseBrightnessHeuristic(int state) {
  use_brightness_heuristic_ = state;
  if (use_brightness_heuristic_) {
    autoSetBrightness();
  }
}

void TrigramWidget::autoSetBrightness() {
  auto new_brightness = suggestBrightness();
  if (new_brightness == brightness_) return;
  brightness_ = new_brightness;
  if (brightness_slider_ != nullptr) {
    brightness_slider_->setValue(brightness_);
  }
  setBrightness(brightness_);
}

void TrigramWidget::timerEvent(QTimerEvent *e) {
  if (is_playing_) {
    angle += 0.5f;
  }

  if (shape_ == EVisualisationShape::CYLINDER) {
    c_cyl += 0.01;
  } else {
    c_cyl -= 0.01;
  }
  if (shape_ == EVisualisationShape::SPHERE) {
    c_sph += 0.01;
  } else {
    c_sph -= 0.01;
  }
  if (c_cyl > 1) c_cyl = 1;
  if (c_cyl < 0) c_cyl = 0;
  if (c_sph > 1) c_sph = 1;
  if (c_sph < 0) c_sph = 0;

  if (mode_ == EVisualisationMode::LAYERED_DIGRAM && c_pos < 1) {
    c_pos += 0.01;
    if (c_pos > 1) c_pos = 1;
  }
  if (mode_ != EVisualisationMode::LAYERED_DIGRAM && c_pos) {
    c_pos -= 0.01;
    if (c_pos < 0) c_pos = 0;
  }
  update();
}

void TrigramWidget::initializeVisualisationGL() {
  initializeOpenGLFunctions();

  glClearColor(0, 0, 0, 1);

  autoSetBrightness();

  initShaders();
  initTextures();
  initGeometry();
  setBrightness(brightness_);
}

void TrigramWidget::initShaders() {
  if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex,
                                       ":/trigram/vshader.glsl"))
    close();

  // Compile fragment shader
  if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment,
                                       ":/trigram/fshader.glsl"))
    close();

  // Link shader pipeline
  if (!program.link()) close();

  timer.start(12, this);
}

void TrigramWidget::initTextures() {
  int size = getDataSize();
  const uint8_t *data = reinterpret_cast<const uint8_t*>(getData());

  databuf = new QOpenGLBuffer(QOpenGLBuffer::Type(GL_TEXTURE_BUFFER));
  databuf->create();
  databuf->bind();
  databuf->allocate(data, size);
  databuf->release();

  texture = new QOpenGLTexture(QOpenGLTexture::TargetBuffer);
  texture->setSize(size);
  texture->setFormat(QOpenGLTexture::R8U);
  texture->create();
  texture->bind();
  glTexBuffer(GL_TEXTURE_BUFFER, QOpenGLTexture::R8U, databuf->bufferId());
}

void TrigramWidget::initGeometry() {
  vao.create();
}

void TrigramWidget::resizeGL(int w, int h) {
  width = w;
  height = h;
}

void TrigramWidget::paintGL() {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glEnable(GL_BLEND);
  glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
  unsigned size = getDataSize();

  program.bind();
  texture->bind();
  vao.bind();

  QMatrix4x4 mp, m;
  mp.setToIdentity();
  mp.perspective(45, static_cast<double>(width) / height, 0.01f, 100.0f);
  m.setToIdentity();
  m.translate(0.0f, 0.0f, -5.0f);
  m.rotate(90, 0, 0, 1);
  m.rotate(angle, 0.5, 1, 0);
  int loc_sz = program.uniformLocation("sz");
  program.setUniformValue("tx", 0);
  program.setUniformValue("c_cyl", c_cyl);
  program.setUniformValue("c_sph", c_sph);
  program.setUniformValue("c_pos", c_pos);
  program.setUniformValue("xfrm", mp * m);
  program.setUniformValue("c_brightness", c_brightness);
  glUniform1ui(loc_sz, size);
  glDrawArrays(GL_POINTS, 0, size - 2);
}

}  // namespace visualisation
}  // namespace veles
<commit_msg>trigram: Fix scaling for height > width.<commit_after>/*
 * Copyright 2016 CodiLime
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "visualisation/trigram.h"

#include <stdio.h>
#include <string.h>

#include <algorithm>
#include <functional>
#include <vector>

#include <QLabel>
#include <QMouseEvent>
#include <QPainter>
#include <QSlider>
#include <QPixmap>
#include <QBitmap>
#include <QHBoxLayout>

namespace veles {
namespace visualisation {

const int k_minimum_brightness = 25;
const int k_maximum_brightness = 103;
const double k_brightness_heuristic_threshold = 0.66;
const int k_brightness_heuristic_min = 38;
const int k_brightness_heuristic_max = 66;
// decrease this to reduce noise (but you may lose data if you overdo it)
const double k_brightness_heuristic_scaling = 2.5;

TrigramWidget::TrigramWidget(QWidget *parent) :
  VisualisationWidget(parent), angle(0), c_sph(0), c_cyl(0), c_pos(0),
  shape_(EVisualisationShape::CUBE), mode_(EVisualisationMode::TRIGRAM),
  brightness_((k_maximum_brightness + k_minimum_brightness) / 2),
  brightness_slider_(nullptr), is_playing_(true),
  use_brightness_heuristic_(true) {}

TrigramWidget::~TrigramWidget() {
  makeCurrent();
  delete texture;
  delete databuf;
  doneCurrent();
}

void TrigramWidget::setBrightness(const int value) {
  brightness_ = value;
  c_brightness = static_cast<float>(value) * value * value;
  c_brightness /= getDataSize();
}

void TrigramWidget::setMode(EVisualisationMode mode, bool animate) {
  mode_ = mode;
  if (mode_ == EVisualisationMode::LAYERED_DIGRAM && !animate) {
    c_pos = 1;
  } else if (mode_ == EVisualisationMode::TRIGRAM && !animate) {
    c_pos = 0;
  }
}

void TrigramWidget::refresh() {
  if (use_brightness_heuristic_) {
    autoSetBrightness();
  }
  setBrightness(brightness_);
  makeCurrent();
  delete texture;
  delete databuf;
  initTextures();
  doneCurrent();
}

QIcon TrigramWidget::getColoredIcon(QString path, bool black_only) {
  QPixmap pixmap(path);
  QPixmap mask;
  if (black_only) {
    mask = pixmap.createMaskFromColor(QColor("black"), Qt::MaskOutColor);
  } else {
    mask = pixmap.createMaskFromColor(QColor("white"), Qt::MaskInColor);
  }
  pixmap.fill(palette().color(QPalette::WindowText));
  pixmap.setMask(mask);
  return QIcon(pixmap);
}

bool TrigramWidget::prepareOptionsPanel(QBoxLayout *layout) {
  VisualisationWidget::prepareOptionsPanel(layout);

  QLabel *brightness_label = new QLabel("Brightness: ");
  brightness_label->setAlignment(Qt::AlignTop);
  layout->addWidget(brightness_label);

  brightness_ = suggestBrightness();
  brightness_slider_ = new QSlider(Qt::Horizontal);
  brightness_slider_->setMinimum(k_minimum_brightness);
  brightness_slider_->setMaximum(k_maximum_brightness);
  brightness_slider_->setValue(brightness_);
  connect(brightness_slider_, SIGNAL(valueChanged(int)), this,
          SLOT(brightnessSliderMoved(int)));
  layout->addWidget(brightness_slider_);

  use_heuristic_checkbox_ = new QCheckBox(
    "Automatically adjust brightness");
  use_heuristic_checkbox_->setChecked(use_brightness_heuristic_);
  connect(use_heuristic_checkbox_, SIGNAL(stateChanged(int)),
          this, SLOT(setUseBrightnessHeuristic(int)));
  layout->addWidget(use_heuristic_checkbox_);

  pause_button_ = new QPushButton();
  pause_button_->setIcon(getColoredIcon(":/images/pause.png"));
  layout->addWidget(pause_button_);
  connect(pause_button_, SIGNAL(released()),
          this, SLOT(playPause()));

  QHBoxLayout *shape_box = new QHBoxLayout();
  cube_button_ = new QPushButton();
  cube_button_->setIcon(getColoredIcon(":/images/cube.png", false));
  cube_button_->setIconSize(QSize(32, 32));
  connect(cube_button_, &QPushButton::released,
          std::bind(&TrigramWidget::setShape, this,
                    EVisualisationShape::CUBE));
  shape_box->addWidget(cube_button_);

  cylinder_button_ = new QPushButton();
  cylinder_button_->setIcon(getColoredIcon(":/images/cylinder.png", false));
  cylinder_button_->setIconSize(QSize(32, 32));
  connect(cylinder_button_, &QPushButton::released,
          std::bind(&TrigramWidget::setShape, this,
                    EVisualisationShape::CYLINDER));
  shape_box->addWidget(cylinder_button_);

  sphere_button_ = new QPushButton();
  sphere_button_->setIcon(getColoredIcon(":/images/sphere.png"));
  sphere_button_->setIconSize(QSize(32, 32));

  connect(sphere_button_, &QPushButton::released,
          std::bind(&TrigramWidget::setShape, this,
                    EVisualisationShape::SPHERE));
  shape_box->addWidget(sphere_button_);

  layout->addLayout(shape_box);

  return true;
}

int TrigramWidget::suggestBrightness() {
  int size = getDataSize();
  auto data = reinterpret_cast<const uint8_t*>(getData());
  if (size < 100) {
    return (k_minimum_brightness + k_maximum_brightness) / 2;
  }
  std::vector<uint64_t> counts(256, 0);
  for (int i = 0; i < size; ++i) {
    counts[data[i]] += 1;
  }
  std::sort(counts.begin(), counts.end());
  int offset = 0, sum = 0;
  while (offset < 255 && sum < k_brightness_heuristic_threshold * size) {
    sum += counts[255 - offset];
    offset += 1;
  }
  offset = static_cast<int>(static_cast<double>(offset)
                            / k_brightness_heuristic_scaling);
  return std::max(k_brightness_heuristic_min,
                  k_brightness_heuristic_max - offset);
}

void TrigramWidget::playPause() {
  QPixmap pixmap;
  if (is_playing_) {
    pause_button_->setIcon(getColoredIcon(":/images/play.png"));
  } else {
    pause_button_->setIcon(getColoredIcon(":/images/pause.png"));
  }
  is_playing_ = !is_playing_;
}

void TrigramWidget::setShape(EVisualisationShape shape) {
  shape_ = shape;
}

void TrigramWidget::brightnessSliderMoved(int value) {
  if (value == brightness_) return;
  use_brightness_heuristic_ = false;
  use_heuristic_checkbox_->setChecked(false);
  setBrightness(value);
}

void TrigramWidget::setUseBrightnessHeuristic(int state) {
  use_brightness_heuristic_ = state;
  if (use_brightness_heuristic_) {
    autoSetBrightness();
  }
}

void TrigramWidget::autoSetBrightness() {
  auto new_brightness = suggestBrightness();
  if (new_brightness == brightness_) return;
  brightness_ = new_brightness;
  if (brightness_slider_ != nullptr) {
    brightness_slider_->setValue(brightness_);
  }
  setBrightness(brightness_);
}

void TrigramWidget::timerEvent(QTimerEvent *e) {
  if (is_playing_) {
    angle += 0.5f;
  }

  if (shape_ == EVisualisationShape::CYLINDER) {
    c_cyl += 0.01;
  } else {
    c_cyl -= 0.01;
  }
  if (shape_ == EVisualisationShape::SPHERE) {
    c_sph += 0.01;
  } else {
    c_sph -= 0.01;
  }
  if (c_cyl > 1) c_cyl = 1;
  if (c_cyl < 0) c_cyl = 0;
  if (c_sph > 1) c_sph = 1;
  if (c_sph < 0) c_sph = 0;

  if (mode_ == EVisualisationMode::LAYERED_DIGRAM && c_pos < 1) {
    c_pos += 0.01;
    if (c_pos > 1) c_pos = 1;
  }
  if (mode_ != EVisualisationMode::LAYERED_DIGRAM && c_pos) {
    c_pos -= 0.01;
    if (c_pos < 0) c_pos = 0;
  }
  update();
}

void TrigramWidget::initializeVisualisationGL() {
  initializeOpenGLFunctions();

  glClearColor(0, 0, 0, 1);

  autoSetBrightness();

  initShaders();
  initTextures();
  initGeometry();
  setBrightness(brightness_);
}

void TrigramWidget::initShaders() {
  if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex,
                                       ":/trigram/vshader.glsl"))
    close();

  // Compile fragment shader
  if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment,
                                       ":/trigram/fshader.glsl"))
    close();

  // Link shader pipeline
  if (!program.link()) close();

  timer.start(12, this);
}

void TrigramWidget::initTextures() {
  int size = getDataSize();
  const uint8_t *data = reinterpret_cast<const uint8_t*>(getData());

  databuf = new QOpenGLBuffer(QOpenGLBuffer::Type(GL_TEXTURE_BUFFER));
  databuf->create();
  databuf->bind();
  databuf->allocate(data, size);
  databuf->release();

  texture = new QOpenGLTexture(QOpenGLTexture::TargetBuffer);
  texture->setSize(size);
  texture->setFormat(QOpenGLTexture::R8U);
  texture->create();
  texture->bind();
  glTexBuffer(GL_TEXTURE_BUFFER, QOpenGLTexture::R8U, databuf->bufferId());
}

void TrigramWidget::initGeometry() {
  vao.create();
}

void TrigramWidget::resizeGL(int w, int h) {
  width = w;
  height = h;
}

void TrigramWidget::paintGL() {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glEnable(GL_BLEND);
  glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
  unsigned size = getDataSize();

  program.bind();
  texture->bind();
  vao.bind();

  QMatrix4x4 mp, m;
  mp.setToIdentity();
  if (width > height) {
    mp.perspective(45, static_cast<double>(width) / height, 0.01f, 100.0f);
  } else {
    // wtf h4x.  gluPerspective fixes the viewport wrt y field of view, and
    // we need to fix it to x instead.  So, rotate the world, fix to new y,
    // rotate it back.
    mp.rotate(90, 0, 0, 1);
    mp.perspective(45, static_cast<double>(height) / width, 0.01f, 100.0f);
    mp.rotate(-90, 0, 0, 1);
  }
  m.setToIdentity();
  m.translate(0.0f, 0.0f, -5.0f);
  m.rotate(90, 0, 0, 1);
  m.rotate(angle, 0.5, 1, 0);
  int loc_sz = program.uniformLocation("sz");
  program.setUniformValue("tx", 0);
  program.setUniformValue("c_cyl", c_cyl);
  program.setUniformValue("c_sph", c_sph);
  program.setUniformValue("c_pos", c_pos);
  program.setUniformValue("xfrm", mp * m);
  program.setUniformValue("c_brightness", c_brightness);
  glUniform1ui(loc_sz, size);
  glDrawArrays(GL_POINTS, 0, size - 2);
}

}  // namespace visualisation
}  // namespace veles
<|endoftext|>


<commit_before>/*
 * test_plane_sw_normal_mode.cpp
 *
 *  Created on: 14 Nov 2019
 *      Author: Pedro Peixoto <ppeixoto@usp.br>
 */

#if !SWEET_USE_PLANE_SPECTRAL_SPACE
	#error "Spectral space not activated"
#endif

#if SWEET_GUI
#	error	"GUI not supported"
#endif

#include <sweet/plane/PlaneData.hpp>
#include <sweet/SimulationVariables.hpp>
#include <sweet/plane/PlaneOperators.hpp>
#include "test_plane_sw_normal_modes/SWE_Plane_Normal_Modes.hpp"

#include <ostream>
#include <cmath>

PlaneDataConfig planeDataConfigInstance;
PlaneDataConfig *planeDataConfig = &planeDataConfigInstance;

SimulationVariables simVars;

int main(
		int i_argc,
		char *i_argv[]
)
{
	// override flag
	SimulationVariables simVars;

	if (!simVars.setupFromMainParameters(i_argc, i_argv))
		return -1;

	planeDataConfigInstance.setupAuto(simVars.disc.space_res_physical, simVars.disc.space_res_spectral, simVars.misc.reuse_spectral_transformation_plans);

	std::cout << "*************************************************************" << std::endl;
	std::cout << "Testing normal mode conversion tool" << std::endl;
	std::cout << "*************************************************************" << std::endl;
	//std::size_t res[2] = {res_x, res_y};

	//std::size_t test_max_freqx = planeDataConfig->spectral_real_modes[0];
	//std::size_t test_max_freqy = planeDataConfig->spectral_real_modes[1];

	std::cout << "*************************************************************" << std::endl;
	planeDataConfig->printInformation();
	std::cout << "*************************************************************" << std::endl;
	std::cout << std::endl;

	PlaneData h(planeDataConfig);
	PlaneData u(planeDataConfig);
	PlaneData v(planeDataConfig);

	// Spectral mode to be converted (x,y) respectively
	std::size_t k0, k1;

	double igwest_mode=1.0;
	double igeast_mode=0.0;
	double geo_mode=0.0;

	//Normal modes to be generated

	//std::size_t max_modes_x = planeDataConfig->spectral_real_modes[0];
	//std::size_t max_modes_y = planeDataConfig->spectral_real_modes[1];
	k0=5;
	k1=3;
	h.spectral_set_zero();
	u.spectral_set_zero();
	v.spectral_set_zero();
	//std::cout<< "out:" << h.planeDataConfig->spectral_data_size[1] << std::endl;

	SWE_Plane_Normal_Modes::add_normal_mode(
								k0, k1,
								igwest_mode,
								igeast_mode,
								geo_mode,
								h,
								u,
								v,
								simVars
						);

	std::cout << "SUCCESSFULLY FINISHED" << std::endl;

	return 0;
}
<commit_msg>not a pedro bug on plane_data spectral get/set!<commit_after>/*
 * test_plane_sw_normal_mode.cpp
 *
 *  Created on: 14 Nov 2019
 *      Author: Pedro Peixoto <ppeixoto@usp.br>
 */

#if !SWEET_USE_PLANE_SPECTRAL_SPACE
	#error "Spectral space not activated"
#endif

#if SWEET_GUI
#	error	"GUI not supported"
#endif

#include <sweet/plane/PlaneData.hpp>
#include <sweet/SimulationVariables.hpp>
#include <sweet/plane/PlaneOperators.hpp>
#include "test_plane_sw_normal_modes/SWE_Plane_Normal_Modes.hpp"

#include <ostream>
#include <cmath>

PlaneDataConfig planeDataConfigInstance;
PlaneDataConfig *planeDataConfig = &planeDataConfigInstance;

SimulationVariables simVars;

int main(
		int i_argc,
		char *i_argv[]
)
{
	// override flag
	SimulationVariables simVars;

	if (!simVars.setupFromMainParameters(i_argc, i_argv))
		return -1;

	planeDataConfigInstance.setupAuto(simVars.disc.space_res_physical, simVars.disc.space_res_spectral, simVars.misc.reuse_spectral_transformation_plans);

	std::cout << "*************************************************************" << std::endl;
	std::cout << "Testing normal mode conversion tool" << std::endl;
	std::cout << "*************************************************************" << std::endl;
	//std::size_t res[2] = {res_x, res_y};

	//std::size_t test_max_freqx = planeDataConfig->spectral_real_modes[0];
	//std::size_t test_max_freqy = planeDataConfig->spectral_real_modes[1];

	std::cout << "*************************************************************" << std::endl;
	planeDataConfig->printInformation();
	std::cout << "*************************************************************" << std::endl;
	std::cout << std::endl;

	PlaneData h(planeDataConfig);
	PlaneData u(planeDataConfig);
	PlaneData v(planeDataConfig);

	// Spectral mode to be converted (x,y) respectively
	std::size_t k0, k1;

	double igwest_mode=1.0;
	double igeast_mode=0.0;
	double geo_mode=0.0;

	//Normal modes to be generated

	//std::size_t max_modes_x = planeDataConfig->spectral_real_modes[0];
	//std::size_t max_modes_y = planeDataConfig->spectral_real_modes[1];
	k0=2;
	k1=3;
	h.spectral_set_zero();
	u.spectral_set_zero();
	v.spectral_set_zero();
	//std::cout<< "out:" << h.planeDataConfig->spectral_data_size[1] << std::endl;

	SWE_Plane_Normal_Modes::add_normal_mode(
								k0, k1,
								igwest_mode,
								igeast_mode,
								geo_mode,
								h,
								u,
								v,
								simVars
						);

	std::cout << "SUCCESSFULLY FINISHED" << std::endl;

	return 0;
}
<|endoftext|>


<commit_before>#pragma once

class local_datagram_client final {
public:
  local_datagram_client(const char* _Nonnull path) : endpoint_(path),
                                                     io_service_(),
                                                     work_(io_service_),
                                                     socket_(io_service_) {
    socket_.open();
    thread_ = std::thread([this] { (this->io_service_).run(); });
  }

  ~local_datagram_client(void) {
    io_service_.post(boost::bind(&local_datagram_client::do_stop, this));
    thread_.join();
  }

  void send_to(const std::vector<uint8_t>& v) {
    auto ptr = std::make_shared<buffer>(v);
    io_service_.post(boost::bind(&local_datagram_client::do_send, this, ptr));
  }

private:
  class buffer final {
  public:
    buffer(const std::vector<uint8_t> v) {
      v_ = v;
    }

    buffer(const uint8_t* _Nonnull p, size_t length) {
      v_.resize(length);
      memcpy(&(v_[0]), p, length);
    }

    const std::vector<uint8_t>& get_vector(void) const { return v_; }

  private:
    std::vector<uint8_t> v_;
  };

  void do_send(const std::shared_ptr<buffer>& ptr) {
    socket_.async_send_to(boost::asio::buffer(ptr->get_vector()), endpoint_,
                          boost::bind(&local_datagram_client::handle_send, this, ptr));
  }

  void handle_send(const std::shared_ptr<buffer>& ptr) {
    // buffer will be released.
  }

  void do_stop(void) {
    io_service_.stop();
  }

  boost::asio::local::datagram_protocol::endpoint endpoint_;
  boost::asio::io_service io_service_;
  boost::asio::io_service::work work_;
  boost::asio::local::datagram_protocol::socket socket_;
  std::thread thread_;
};
<commit_msg>add local_datagram_client::send_to(const uint8_t*, size_t)<commit_after>#pragma once

class local_datagram_client final {
public:
  local_datagram_client(const char* _Nonnull path) : endpoint_(path),
                                                     io_service_(),
                                                     work_(io_service_),
                                                     socket_(io_service_) {
    socket_.open();
    thread_ = std::thread([this] { (this->io_service_).run(); });
  }

  ~local_datagram_client(void) {
    io_service_.post(boost::bind(&local_datagram_client::do_stop, this));
    thread_.join();
  }

  void send_to(const std::vector<uint8_t>& v) {
    auto ptr = std::make_shared<buffer>(v);
    io_service_.post(boost::bind(&local_datagram_client::do_send, this, ptr));
  }

  void send_to(const uint8_t* _Nonnull p, size_t length) {
    auto ptr = std::make_shared<buffer>(p, length);
    io_service_.post(boost::bind(&local_datagram_client::do_send, this, ptr));
  }

private:
  class buffer final {
  public:
    buffer(const std::vector<uint8_t> v) {
      v_ = v;
    }

    buffer(const uint8_t* _Nonnull p, size_t length) {
      v_.resize(length);
      memcpy(&(v_[0]), p, length);
    }

    const std::vector<uint8_t>& get_vector(void) const { return v_; }

  private:
    std::vector<uint8_t> v_;
  };

  void do_send(const std::shared_ptr<buffer>& ptr) {
    socket_.async_send_to(boost::asio::buffer(ptr->get_vector()), endpoint_,
                          boost::bind(&local_datagram_client::handle_send, this, ptr));
  }

  void handle_send(const std::shared_ptr<buffer>& ptr) {
    // buffer will be released.
  }

  void do_stop(void) {
    io_service_.stop();
  }

  boost::asio::local::datagram_protocol::endpoint endpoint_;
  boost::asio::io_service io_service_;
  boost::asio::io_service::work work_;
  boost::asio::local::datagram_protocol::socket socket_;
  std::thread thread_;
};
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2006-2009 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <vw/Plate/IndexService.h>
using namespace vw::platefile;

#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

// ----------------------------------------------------------------------------------
//                                 PRIVATE METHODS
// ----------------------------------------------------------------------------------

std::vector<std::string> IndexServiceImpl::glob_plate_filenames(std::string const& root_directory)  {

  std::vector<std::string> result;

  if ( !fs::exists( root_directory ) )
    vw_throw(IOErr() << "Could not access the root directory: \"" << root_directory << "\"");

  // Create a regular expression for matching the pattern 'plate_<number>.blob"
  boost::regex re;
  re.assign(".*\\.plate", boost::regex_constants::icase);

  fs::directory_iterator end_itr; // default construction yields past-the-end

  // Iterate through the files in the platefile directory and return
  // any that match the regex above.
  for ( fs::directory_iterator itr( root_directory ); itr != end_itr; ++itr ) {
    if (boost::regex_match(itr->leaf(), re))
      result.push_back(itr->leaf());
  }

  return result;
}

IndexServiceImpl::IndexServiceRecord IndexServiceImpl::add_index(std::string root_directory,
                                                                 std::string plate_filename,
                                                                 boost::shared_ptr<Index> index) {

    // Build up an IndexServiceRecord
    IndexServiceRecord rec;
    rec.short_plate_filename = plate_filename;
    rec.full_plate_filename = root_directory + "/" + plate_filename;
    rec.index = index;

    // Store the record in a std::map by platefile_id
    m_indices[index->index_header().platefile_id()]  = rec;
    return rec;
}

/// Fetch an IndexServiceRecord for a given platefile_id, or throw an
/// exception if no record is found.  This is the first step in most
/// of the RPC handlers below, so the code is factored out here for
/// convenience.
IndexServiceImpl::IndexServiceRecord IndexServiceImpl::get_index_record_for_platefile_id(int platefile_id) {

  if (m_indices.find(platefile_id) == m_indices.end())
    vw_throw(InvalidPlatefileErr() << "No platefile matching this platefile_id could be found.");

  return m_indices[platefile_id];

}

// ----------------------------------------------------------------------------------
//                                 PUBLIC METHODS
// ----------------------------------------------------------------------------------

IndexServiceImpl::IndexServiceImpl(std::string root_directory) :
  m_root_directory( fs::system_complete(root_directory).string() ) {

  std::cout << "Starting Index Service\n";

  // Search for all platefiles in the given root_directory.  A
  // platefile is any directory ending in *.plate.
  std::vector<std::string> platefiles = glob_plate_filenames(m_root_directory);
  if (platefiles.size() < 1)
    vw_throw(ArgumentErr() << "Error: could not find any platefiles in the root directory.");

  for (unsigned i = 0 ; i < platefiles.size(); ++i) {

    // Open each new platefile.  This will return a LocalIndex which we store using add_index()
    boost::shared_ptr<Index> idx = Index::construct_open(m_root_directory + "/" + platefiles[i]);
    this->add_index(m_root_directory, platefiles[i], idx);
  }

}

void IndexServiceImpl::OpenRequest(::google::protobuf::RpcController* controller,
                                   const IndexOpenRequest* request,
                                   IndexOpenReply* response,
                                   ::google::protobuf::Closure* done) {

  index_list_type::iterator iter = m_indices.begin();
  while (iter != m_indices.end()) {
    if ( (*iter).second.short_plate_filename == request->plate_name() ) {

      // If we find a matching short_plate_filename in m_indices, then
      // we return the index header.
      response->set_short_plate_filename( (*iter).second.short_plate_filename );
      response->set_full_plate_filename( (*iter).second.full_plate_filename );
      *(response->mutable_index_header()) = (*iter).second.index->index_header();
      done->Run();
      return;

    }
    ++iter;
  }

  // If we reach this point, then there is no matching plate file
  // being tracked by this IndexService.  Return an error.
  vw_throw(InvalidPlatefileErr() << "No platefile matching this plate_name could be found.");
}

void IndexServiceImpl::CreateRequest(::google::protobuf::RpcController* controller,
                                     const IndexCreateRequest* request,
                                     IndexOpenReply* response,
                                     ::google::protobuf::Closure* done) {

  // Try OPEN: the index may already exist and be open.  If so, we do
  // nothing but return the necessary info in the IndexOpenReply.
  index_list_type::iterator iter = m_indices.begin();
  while (iter != m_indices.end()) {
    if ( (*iter).second.short_plate_filename == request->plate_name() ) {

      // If we find a matching short_plate_filename in m_indices, then
      // we return the index header.
      response->set_short_plate_filename( (*iter).second.short_plate_filename );
      response->set_full_plate_filename( (*iter).second.full_plate_filename );
      *(response->mutable_index_header()) = (*iter).second.index->index_header();
      done->Run();
      return;

    }
    ++iter;
  }

  // If the index is not already open...
  std::string url = m_root_directory + "/" + request->plate_name();
  boost::shared_ptr<Index> idx;
  try {
    if (!exists( fs::path( url, fs::native ) ) ) {

      // CREATE: If there was no index already open by that name, and
      // no platefile on disk, then we try to create it.
      fs::create_directory(url);
      idx = Index::construct_create(url, request->index_header());

    } else {

      // REOPEN: If a platefile actually does appear to exist on disk,
      // but we had not previously opened it, we open it here.
      idx = Index::construct_open(url);

    }
  } catch (IOErr &e) {
    vw_throw(PlatefileCreationErr() << e.what());
    return; // never reached
  }

  IndexServiceRecord rec = this->add_index(m_root_directory, request->plate_name(), idx);
  response->set_short_plate_filename( rec.short_plate_filename );
  response->set_full_plate_filename( rec.full_plate_filename );
  *(response->mutable_index_header()) = rec.index->index_header();
  done->Run();
}

void IndexServiceImpl::InfoRequest(::google::protobuf::RpcController* controller,
                                   const IndexInfoRequest* request,
                                   IndexInfoReply* response,
                                   ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  response->set_short_plate_filename(rec.short_plate_filename);
  response->set_full_plate_filename(rec.full_plate_filename);
  *(response->mutable_index_header()) = rec.index->index_header();
  done->Run();
}

void IndexServiceImpl::ListRequest(::google::protobuf::RpcController* controller,
                                   const IndexListRequest* request,
                                   IndexListReply* response,
                                   ::google::protobuf::Closure* done) {

  for (index_list_type::const_iterator i = m_indices.begin(), end = m_indices.end(); i != end; ++i) {

    IndexServiceRecord rec = i->second;

#define should_filter_out(field) \
    request->has_ ## field() && rec.index->index_header().has_ ## field() && request->field() != rec.index->index_header().field()

    if (should_filter_out(tile_filetype))
      continue;

    if (should_filter_out(pixel_format))
      continue;

    if (should_filter_out(channel_type))
      continue;

    if (should_filter_out(type))
      continue;

#undef should_filter_out

    response->add_platefile_names(rec.short_plate_filename);
  }

  done->Run();
}

void IndexServiceImpl::ReadRequest(::google::protobuf::RpcController* controller,
                                   const IndexReadRequest* request,
                                   IndexReadReply* response,
                                   ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  IndexRecord record = rec.index->read_request(request->col(),
                                               request->row(),
                                               request->depth(),
                                               request->transaction_id(),
                                               request->exact_transaction_match());
  *(response->mutable_index_record()) = record;
  done->Run();
}

void IndexServiceImpl::WriteRequest(::google::protobuf::RpcController* controller,
                                    const IndexWriteRequest* request,
                                    IndexWriteReply* response,
                                    ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  int blob_id = rec.index->write_request(request->size());
  response->set_blob_id(blob_id);
  done->Run();
}

void IndexServiceImpl::WriteComplete(::google::protobuf::RpcController* controller,
                                     const IndexWriteComplete* request,
                                     RpcNullMessage* response,
                                     ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  rec.index->write_complete(request->header(), request->record());
  // This message has no response
  done->Run();
}

void IndexServiceImpl::TransactionRequest(::google::protobuf::RpcController* controller,
                                          const IndexTransactionRequest* request,
                                          IndexTransactionReply* response,
                                          ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Parse out the list of root tiles that will be effected by this transaction_id.
  std::vector<TileHeader> tile_headers;
  for (int i = 0; i < request->tile_headers_size(); ++i)
    tile_headers.push_back(request->tile_headers(i));

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  int transaction_id = rec.index->transaction_request(request->description(), tile_headers);
  response->set_transaction_id(transaction_id);
  done->Run();
}

void IndexServiceImpl::RootComplete(::google::protobuf::RpcController* controller,
                                    const IndexRootComplete* request,
                                    RpcNullMessage* response,
                                    ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Parse out the list of root tiles that will be effected by this transaction_id.
  std::vector<TileHeader> tile_headers;
  for (int i = 0; i < request->tile_headers_size(); ++i)
    tile_headers.push_back(request->tile_headers(i));

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  rec.index->root_complete(request->transaction_id(), tile_headers);
  // This message has no response.
  done->Run();
}

void IndexServiceImpl::TransactionComplete(::google::protobuf::RpcController* controller,
                                           const IndexTransactionComplete* request,
                                           RpcNullMessage* response,
                                           ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  rec.index->transaction_complete(request->transaction_id());
  // This message has no response.
  done->Run();
}

void IndexServiceImpl::TransactionCursor(::google::protobuf::RpcController* controller,
                                         const IndexTransactionCursorRequest* request,
                                         IndexTransactionCursorReply* response,
                                         ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  int transaction_id = rec.index->transaction_cursor();
  response->set_transaction_id(transaction_id);
  done->Run();
}

void IndexServiceImpl::DepthRequest(::google::protobuf::RpcController* controller,
                                    const IndexDepthRequest* request,
                                    IndexDepthReply* response,
                                    ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  response->set_depth(rec.index->max_depth());
  done->Run();
}

<commit_msg>let the index server start up with no plates<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2006-2009 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <vw/Plate/IndexService.h>
using namespace vw::platefile;

#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

// ----------------------------------------------------------------------------------
//                                 PRIVATE METHODS
// ----------------------------------------------------------------------------------

std::vector<std::string> IndexServiceImpl::glob_plate_filenames(std::string const& root_directory)  {

  std::vector<std::string> result;

  if ( !fs::exists( root_directory ) )
    vw_throw(IOErr() << "Could not access the root directory: \"" << root_directory << "\"");

  // Create a regular expression for matching the pattern 'plate_<number>.blob"
  boost::regex re;
  re.assign(".*\\.plate", boost::regex_constants::icase);

  fs::directory_iterator end_itr; // default construction yields past-the-end

  // Iterate through the files in the platefile directory and return
  // any that match the regex above.
  for ( fs::directory_iterator itr( root_directory ); itr != end_itr; ++itr ) {
    if (boost::regex_match(itr->leaf(), re))
      result.push_back(itr->leaf());
  }

  return result;
}

IndexServiceImpl::IndexServiceRecord IndexServiceImpl::add_index(std::string root_directory,
                                                                 std::string plate_filename,
                                                                 boost::shared_ptr<Index> index) {

    // Build up an IndexServiceRecord
    IndexServiceRecord rec;
    rec.short_plate_filename = plate_filename;
    rec.full_plate_filename = root_directory + "/" + plate_filename;
    rec.index = index;

    // Store the record in a std::map by platefile_id
    m_indices[index->index_header().platefile_id()]  = rec;
    return rec;
}

/// Fetch an IndexServiceRecord for a given platefile_id, or throw an
/// exception if no record is found.  This is the first step in most
/// of the RPC handlers below, so the code is factored out here for
/// convenience.
IndexServiceImpl::IndexServiceRecord IndexServiceImpl::get_index_record_for_platefile_id(int platefile_id) {

  if (m_indices.find(platefile_id) == m_indices.end())
    vw_throw(InvalidPlatefileErr() << "No platefile matching this platefile_id could be found.");

  return m_indices[platefile_id];

}

// ----------------------------------------------------------------------------------
//                                 PUBLIC METHODS
// ----------------------------------------------------------------------------------

IndexServiceImpl::IndexServiceImpl(std::string root_directory) :
  m_root_directory( fs::system_complete(root_directory).string() ) {

  std::cout << "Starting Index Service\n";

  // Search for all platefiles in the given root_directory.  A
  // platefile is any directory ending in *.plate.
  std::vector<std::string> platefiles = glob_plate_filenames(m_root_directory);
  if (platefiles.size() < 1)
    vw_out(InfoMessage, "plate:index_service") << "Warning: could not find any platefiles in the root directory.";

  for (unsigned i = 0 ; i < platefiles.size(); ++i) {

    // Open each new platefile.  This will return a LocalIndex which we store using add_index()
    boost::shared_ptr<Index> idx = Index::construct_open(m_root_directory + "/" + platefiles[i]);
    this->add_index(m_root_directory, platefiles[i], idx);
  }

}

void IndexServiceImpl::OpenRequest(::google::protobuf::RpcController* controller,
                                   const IndexOpenRequest* request,
                                   IndexOpenReply* response,
                                   ::google::protobuf::Closure* done) {

  index_list_type::iterator iter = m_indices.begin();
  while (iter != m_indices.end()) {
    if ( (*iter).second.short_plate_filename == request->plate_name() ) {

      // If we find a matching short_plate_filename in m_indices, then
      // we return the index header.
      response->set_short_plate_filename( (*iter).second.short_plate_filename );
      response->set_full_plate_filename( (*iter).second.full_plate_filename );
      *(response->mutable_index_header()) = (*iter).second.index->index_header();
      done->Run();
      return;

    }
    ++iter;
  }

  // If we reach this point, then there is no matching plate file
  // being tracked by this IndexService.  Return an error.
  vw_throw(InvalidPlatefileErr() << "No platefile matching this plate_name could be found.");
}

void IndexServiceImpl::CreateRequest(::google::protobuf::RpcController* controller,
                                     const IndexCreateRequest* request,
                                     IndexOpenReply* response,
                                     ::google::protobuf::Closure* done) {

  // Try OPEN: the index may already exist and be open.  If so, we do
  // nothing but return the necessary info in the IndexOpenReply.
  index_list_type::iterator iter = m_indices.begin();
  while (iter != m_indices.end()) {
    if ( (*iter).second.short_plate_filename == request->plate_name() ) {

      // If we find a matching short_plate_filename in m_indices, then
      // we return the index header.
      response->set_short_plate_filename( (*iter).second.short_plate_filename );
      response->set_full_plate_filename( (*iter).second.full_plate_filename );
      *(response->mutable_index_header()) = (*iter).second.index->index_header();
      done->Run();
      return;

    }
    ++iter;
  }

  // If the index is not already open...
  std::string url = m_root_directory + "/" + request->plate_name();
  boost::shared_ptr<Index> idx;
  try {
    if (!exists( fs::path( url, fs::native ) ) ) {

      // CREATE: If there was no index already open by that name, and
      // no platefile on disk, then we try to create it.
      fs::create_directory(url);
      idx = Index::construct_create(url, request->index_header());

    } else {

      // REOPEN: If a platefile actually does appear to exist on disk,
      // but we had not previously opened it, we open it here.
      idx = Index::construct_open(url);

    }
  } catch (IOErr &e) {
    vw_throw(PlatefileCreationErr() << e.what());
    return; // never reached
  }

  IndexServiceRecord rec = this->add_index(m_root_directory, request->plate_name(), idx);
  response->set_short_plate_filename( rec.short_plate_filename );
  response->set_full_plate_filename( rec.full_plate_filename );
  *(response->mutable_index_header()) = rec.index->index_header();
  done->Run();
}

void IndexServiceImpl::InfoRequest(::google::protobuf::RpcController* controller,
                                   const IndexInfoRequest* request,
                                   IndexInfoReply* response,
                                   ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  response->set_short_plate_filename(rec.short_plate_filename);
  response->set_full_plate_filename(rec.full_plate_filename);
  *(response->mutable_index_header()) = rec.index->index_header();
  done->Run();
}

void IndexServiceImpl::ListRequest(::google::protobuf::RpcController* controller,
                                   const IndexListRequest* request,
                                   IndexListReply* response,
                                   ::google::protobuf::Closure* done) {

  for (index_list_type::const_iterator i = m_indices.begin(), end = m_indices.end(); i != end; ++i) {

    IndexServiceRecord rec = i->second;

#define should_filter_out(field) \
    request->has_ ## field() && rec.index->index_header().has_ ## field() && request->field() != rec.index->index_header().field()

    if (should_filter_out(tile_filetype))
      continue;

    if (should_filter_out(pixel_format))
      continue;

    if (should_filter_out(channel_type))
      continue;

    if (should_filter_out(type))
      continue;

#undef should_filter_out

    response->add_platefile_names(rec.short_plate_filename);
  }

  done->Run();
}

void IndexServiceImpl::ReadRequest(::google::protobuf::RpcController* controller,
                                   const IndexReadRequest* request,
                                   IndexReadReply* response,
                                   ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  IndexRecord record = rec.index->read_request(request->col(),
                                               request->row(),
                                               request->depth(),
                                               request->transaction_id(),
                                               request->exact_transaction_match());
  *(response->mutable_index_record()) = record;
  done->Run();
}

void IndexServiceImpl::WriteRequest(::google::protobuf::RpcController* controller,
                                    const IndexWriteRequest* request,
                                    IndexWriteReply* response,
                                    ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  int blob_id = rec.index->write_request(request->size());
  response->set_blob_id(blob_id);
  done->Run();
}

void IndexServiceImpl::WriteComplete(::google::protobuf::RpcController* controller,
                                     const IndexWriteComplete* request,
                                     RpcNullMessage* response,
                                     ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  rec.index->write_complete(request->header(), request->record());
  // This message has no response
  done->Run();
}

void IndexServiceImpl::TransactionRequest(::google::protobuf::RpcController* controller,
                                          const IndexTransactionRequest* request,
                                          IndexTransactionReply* response,
                                          ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Parse out the list of root tiles that will be effected by this transaction_id.
  std::vector<TileHeader> tile_headers;
  for (int i = 0; i < request->tile_headers_size(); ++i)
    tile_headers.push_back(request->tile_headers(i));

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  int transaction_id = rec.index->transaction_request(request->description(), tile_headers);
  response->set_transaction_id(transaction_id);
  done->Run();
}

void IndexServiceImpl::RootComplete(::google::protobuf::RpcController* controller,
                                    const IndexRootComplete* request,
                                    RpcNullMessage* response,
                                    ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Parse out the list of root tiles that will be effected by this transaction_id.
  std::vector<TileHeader> tile_headers;
  for (int i = 0; i < request->tile_headers_size(); ++i)
    tile_headers.push_back(request->tile_headers(i));

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  rec.index->root_complete(request->transaction_id(), tile_headers);
  // This message has no response.
  done->Run();
}

void IndexServiceImpl::TransactionComplete(::google::protobuf::RpcController* controller,
                                           const IndexTransactionComplete* request,
                                           RpcNullMessage* response,
                                           ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  rec.index->transaction_complete(request->transaction_id());
  // This message has no response.
  done->Run();
}

void IndexServiceImpl::TransactionCursor(::google::protobuf::RpcController* controller,
                                         const IndexTransactionCursorRequest* request,
                                         IndexTransactionCursorReply* response,
                                         ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  int transaction_id = rec.index->transaction_cursor();
  response->set_transaction_id(transaction_id);
  done->Run();
}

void IndexServiceImpl::DepthRequest(::google::protobuf::RpcController* controller,
                                    const IndexDepthRequest* request,
                                    IndexDepthReply* response,
                                    ::google::protobuf::Closure* done) {

  // Fetch the index service record
  IndexServiceRecord rec = get_index_record_for_platefile_id(request->platefile_id());

  // Access the data in the index.  Return the data on success, or
  // notify the remote client of our failure if we did not succeed.
  response->set_depth(rec.index->max_depth());
  done->Run();
}

<|endoftext|>


<commit_before>/*
    Copyright (C) 2011  Lasath Fernando <kde@lasath.org>
    Copyright (C) 2013  Lasath Fernando <davidedmundson@kde.org>

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "messages-model.h"

#include <QPixmap>

#include "debug.h"
#include <KLocalizedString>
#include <KConfig>

#include <TelepathyQt/ReceivedMessage>
#include <TelepathyQt/TextChannel>
#include <TelepathyQt/Account>

#include <KTp/message-processor.h>
#include <KTp/message-context.h>
#include <KTp/Logger/scrollback-manager.h>

class MessagePrivate
{
  public:
    MessagePrivate(const KTp::Message &message);

    KTp::Message message;
    MessagesModel::DeliveryStatus deliveryStatus;
    QDateTime deliveryReportReceiveTime;
};

MessagePrivate::MessagePrivate(const KTp::Message &message) :
        message(message),
        deliveryStatus(MessagesModel::DeliveryStatusUnknown)
{
}

class MessagesModel::MessagesModelPrivate
{
  public:
    Tp::TextChannelPtr textChannel;
    Tp::AccountPtr account;
    ScrollbackManager *logManager;
    QList<MessagePrivate> messages;
    // For fast lookup of original messages upon receipt of a message delivery report.
    QHash<QString /*messageToken*/, QPersistentModelIndex> messagesByMessageToken;
    bool visible;
    bool logsLoaded;
};

MessagesModel::MessagesModel(const Tp::AccountPtr &account, QObject *parent) :
        QAbstractListModel(parent),
        d(new MessagesModelPrivate)
{
    d->account = account;
    d->visible = false;

    d->logManager = new ScrollbackManager(this);
    d->logsLoaded = false;
    connect(d->logManager, SIGNAL(fetched(QList<KTp::Message>)), SLOT(onHistoryFetched(QList<KTp::Message>)));

    //Load configuration for number of message to show
    KConfig config(QLatin1String("ktelepathyrc"));
    KConfigGroup tabConfig = config.group("Behavior");
    d->logManager->setScrollbackLength(tabConfig.readEntry<int>("scrollbackLength", 10));
}

QHash<int, QByteArray> MessagesModel::roleNames() const
{
    QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
    roles[TextRole] = "text";
    roles[TimeRole] = "time";
    roles[TypeRole] = "type";
    roles[SenderIdRole] = "senderId";
    roles[SenderAliasRole] = "senderAlias";
    roles[SenderAvatarRole] = "senderAvatar";
    roles[DeliveryStatusRole] = "deliveryStatus";
    roles[DeliveryReportReceiveTimeRole] = "deliveryReportReceiveTime";
    return roles;
}

Tp::TextChannelPtr MessagesModel::textChannel() const
{
    return d->textChannel;
}

bool MessagesModel::verifyPendingOperation(Tp::PendingOperation *op)
{
    bool operationSucceeded = true;

    if (op->isError()) {
        qCWarning(KTP_DECLARATIVE) << op->errorName() << "+" << op->errorMessage();
        operationSucceeded = false;
    }

    return operationSucceeded;
}

void MessagesModel::setupChannelSignals(const Tp::TextChannelPtr &channel)
{
    connect(channel.data(),
            SIGNAL(messageReceived(Tp::ReceivedMessage)),
            SLOT(onMessageReceived(Tp::ReceivedMessage)));
    connect(channel.data(),
            SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
            SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
    connect(channel.data(),
            SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)),
            SLOT(onPendingMessageRemoved()));
}

void MessagesModel::setTextChannel(const Tp::TextChannelPtr &channel)
{
    Q_ASSERT(channel != d->textChannel);
    setupChannelSignals(channel);

    if (d->textChannel) {
        removeChannelSignals(d->textChannel);
    }

    d->textChannel = channel;

    d->logManager->setTextChannel(d->account, d->textChannel);

    //Load messages unless they have already been loaded
    if(!d->logsLoaded) {
        d->logManager->fetchScrollback();
    }

    QList<Tp::ReceivedMessage> messageQueue = channel->messageQueue();
    Q_FOREACH(const Tp::ReceivedMessage &message, messageQueue) {
        bool messageAlreadyInModel = false;
        Q_FOREACH(const MessagePrivate &current, d->messages) {
            //FIXME: docs say messageToken can return an empty string. What to do if that happens?
            //Tp::Message has an == operator. maybe I can use that?
            if (current.message.token() == message.messageToken()) {
                messageAlreadyInModel = true;
                break;
            }
        }
        if (!messageAlreadyInModel) {
            onMessageReceived(message);
        }
    }
}

void MessagesModel::onHistoryFetched(const QList<KTp::Message> &messages)
{
    if (!messages.isEmpty()) {
        //Add all messages before the ones already present in the channel
        beginInsertRows(QModelIndex(), 0, messages.count() - 1);
        for(int i=messages.size()-1;i>=0;i--) {
            d->messages.prepend(messages[i]);
        }
        endInsertRows();
    }
    d->logsLoaded = true;
}

void MessagesModel::onMessageReceived(const Tp::ReceivedMessage &message)
{
    int unreadCount = d->textChannel->messageQueue().size();
    if (message.isDeliveryReport()) {
        d->textChannel->acknowledge(QList<Tp::ReceivedMessage>() << message);

        Tp::ReceivedMessage::DeliveryDetails deliveryDetails = message.deliveryDetails();
        if(!deliveryDetails.hasOriginalToken()) {
            qCWarning(KTP_DECLARATIVE) << "Delivery report without original message token received.";
            // Matching the delivery report to the original message is impossible without the token.
            return;
        }

        QPersistentModelIndex originalMessageIndex = d->messagesByMessageToken.value(
                    deliveryDetails.originalToken());
        if (!originalMessageIndex.isValid() || originalMessageIndex.row() >= d->messages.count()) {
            // The original message for this delivery report was not found.
            return;
        }

        MessagePrivate &originalMessage = d->messages[originalMessageIndex.row()];
        originalMessage.deliveryReportReceiveTime = message.received();
        switch(deliveryDetails.status()) {
        case Tp::DeliveryStatusPermanentlyFailed:
        case Tp::DeliveryStatusTemporarilyFailed:
            originalMessage.deliveryStatus = DeliveryStatusFailed;
            if (deliveryDetails.hasDebugMessage()) {
                qCDebug(KTP_DECLARATIVE) << "Delivery failure debug message:" << deliveryDetails.debugMessage();
            }
            break;
        case Tp::DeliveryStatusDelivered:
            originalMessage.deliveryStatus = DeliveryStatusDelivered;
            break;
        case Tp::DeliveryStatusRead:
            originalMessage.deliveryStatus = DeliveryStatusRead;
            break;
        default:
            originalMessage.deliveryStatus = DeliveryStatusUnknown;
            break;
        }
        Q_EMIT dataChanged(originalMessageIndex, originalMessageIndex);
    } else {
        int newMessageIndex = 0;
        const QDateTime sentTimestamp = message.sent();
        if (sentTimestamp.isValid()) {
            for (int i = d->messages.count() - 1; i >= 0; --i) {
                if (sentTimestamp > d->messages.at(i).message.time()) {
                    newMessageIndex = i;
                    break;
                }
            }
        } else {
            newMessageIndex = rowCount();
        }
        beginInsertRows(QModelIndex(), newMessageIndex, newMessageIndex);

        d->messages.insert(newMessageIndex, KTp::MessageProcessor::instance()->processIncomingMessage(
                               message, d->account, d->textChannel));

        endInsertRows();

        if (d->visible) {
            acknowledgeAllMessages();
        } else {
            Q_EMIT unreadCountChanged(unreadCount);
        }
    }
}

void MessagesModel::onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &messageToken)
{
    Q_UNUSED(flags);

    int length = rowCount();
    beginInsertRows(QModelIndex(), length, length);

    const KTp::Message &newMessage = KTp::MessageProcessor::instance()->processIncomingMessage(
                message, d->account, d->textChannel);
    d->messages.append(newMessage);

    if (!messageToken.isEmpty()) {
        // Insert the message into the lookup table for delivery reports.
        const QPersistentModelIndex modelIndex = createIndex(length, 0);
        d->messagesByMessageToken.insert(messageToken, modelIndex);
    }

    endInsertRows();
}

void MessagesModel::onPendingMessageRemoved()
{
    Q_EMIT unreadCountChanged(unreadCount());
}

QVariant MessagesModel::data(const QModelIndex &index, int role) const
{
    QVariant result;

    if (index.isValid() && index.row() < rowCount(index.parent())) {
        const MessagePrivate m = d->messages[index.row()];

        switch (role) {
        case TextRole:
            result = m.message.finalizedMessage();
            break;
        case TypeRole:
            if (m.message.type() == Tp::ChannelTextMessageTypeAction) {
                result = MessageTypeAction;
            } else {
                if (m.message.direction() == KTp::Message::LocalToRemote) {
                    result = MessageTypeOutgoing;
                } else {
                    result = MessageTypeIncoming;
                }
            }
            break;
        case TimeRole:
            result = m.message.time();
            break;
        case SenderIdRole:
            result = m.message.senderId();
            break;
        case SenderAliasRole:
            result = m.message.senderAlias();
            break;
        case SenderAvatarRole:
            if (m.message.sender()) {
                result = QVariant::fromValue(m.message.sender()->avatarPixmap());
            }
            break;
        case DeliveryStatusRole:
            result = m.deliveryStatus;
            break;
        case DeliveryReportReceiveTimeRole:
            result = m.deliveryReportReceiveTime;
            break;
        };
    } else {
        qWarning() << "Attempting to access data at invalid index (" << index << ")";
    }

    return result;
}

int MessagesModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return d->messages.size();
}

void MessagesModel::sendNewMessage(const QString &message)
{
    if (message.isEmpty()) {
        qCWarning(KTP_DECLARATIVE) << "Attempting to send empty string";
    } else {
        Tp::PendingOperation *op;
        QString modifiedMessage = message;
        if (d->textChannel->supportsMessageType(Tp::ChannelTextMessageTypeAction)
                && modifiedMessage.startsWith(QLatin1String("/me "))) {
            //remove "/me " from the start of the message
            modifiedMessage.remove(0,4);
            op = d->textChannel->send(modifiedMessage, Tp::ChannelTextMessageTypeAction);
        } else {
            op = d->textChannel->send(modifiedMessage);
        }
        connect(op,
                SIGNAL(finished(Tp::PendingOperation*)),
                SLOT(verifyPendingOperation(Tp::PendingOperation*)));
    }
}

void MessagesModel::removeChannelSignals(const Tp::TextChannelPtr &channel)
{
    QObject::disconnect(channel.data(),
                        SIGNAL(messageReceived(Tp::ReceivedMessage)),
                        this,
                        SLOT(onMessageReceived(Tp::ReceivedMessage))
                       );
    QObject::disconnect(channel.data(),
                        SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
                        this,
                        SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString))
                       );
}

int MessagesModel::unreadCount() const
{
    return d->textChannel->messageQueue().size();
}

void MessagesModel::acknowledgeAllMessages()
{
    QList<Tp::ReceivedMessage> queue = d->textChannel->messageQueue();

    d->textChannel->acknowledge(queue);
    Q_EMIT unreadCountChanged(queue.size());
}

void MessagesModel::setVisibleToUser(bool visible)
{
    if (d->visible != visible) {
        d->visible = visible;
        Q_EMIT visibleToUserChanged(d->visible);
    }

    if (visible) {
        acknowledgeAllMessages();
    }
}

bool MessagesModel::isVisibleToUser() const
{
    return d->visible;
}

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

bool MessagesModel::shouldStartOpened() const
{
    return d->textChannel->isRequested();
}
<commit_msg>[declarative] Guard for empty channel<commit_after>/*
    Copyright (C) 2011  Lasath Fernando <kde@lasath.org>
    Copyright (C) 2013  Lasath Fernando <davidedmundson@kde.org>

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "messages-model.h"

#include <QPixmap>

#include "debug.h"
#include <KLocalizedString>
#include <KConfig>

#include <TelepathyQt/ReceivedMessage>
#include <TelepathyQt/TextChannel>
#include <TelepathyQt/Account>

#include <KTp/message-processor.h>
#include <KTp/message-context.h>
#include <KTp/Logger/scrollback-manager.h>

class MessagePrivate
{
  public:
    MessagePrivate(const KTp::Message &message);

    KTp::Message message;
    MessagesModel::DeliveryStatus deliveryStatus;
    QDateTime deliveryReportReceiveTime;
};

MessagePrivate::MessagePrivate(const KTp::Message &message) :
        message(message),
        deliveryStatus(MessagesModel::DeliveryStatusUnknown)
{
}

class MessagesModel::MessagesModelPrivate
{
  public:
    Tp::TextChannelPtr textChannel;
    Tp::AccountPtr account;
    ScrollbackManager *logManager;
    QList<MessagePrivate> messages;
    // For fast lookup of original messages upon receipt of a message delivery report.
    QHash<QString /*messageToken*/, QPersistentModelIndex> messagesByMessageToken;
    bool visible;
    bool logsLoaded;
};

MessagesModel::MessagesModel(const Tp::AccountPtr &account, QObject *parent) :
        QAbstractListModel(parent),
        d(new MessagesModelPrivate)
{
    d->account = account;
    d->visible = false;

    d->logManager = new ScrollbackManager(this);
    d->logsLoaded = false;
    connect(d->logManager, SIGNAL(fetched(QList<KTp::Message>)), SLOT(onHistoryFetched(QList<KTp::Message>)));

    //Load configuration for number of message to show
    KConfig config(QLatin1String("ktelepathyrc"));
    KConfigGroup tabConfig = config.group("Behavior");
    d->logManager->setScrollbackLength(tabConfig.readEntry<int>("scrollbackLength", 10));
}

QHash<int, QByteArray> MessagesModel::roleNames() const
{
    QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
    roles[TextRole] = "text";
    roles[TimeRole] = "time";
    roles[TypeRole] = "type";
    roles[SenderIdRole] = "senderId";
    roles[SenderAliasRole] = "senderAlias";
    roles[SenderAvatarRole] = "senderAvatar";
    roles[DeliveryStatusRole] = "deliveryStatus";
    roles[DeliveryReportReceiveTimeRole] = "deliveryReportReceiveTime";
    return roles;
}

Tp::TextChannelPtr MessagesModel::textChannel() const
{
    return d->textChannel;
}

bool MessagesModel::verifyPendingOperation(Tp::PendingOperation *op)
{
    bool operationSucceeded = true;

    if (op->isError()) {
        qCWarning(KTP_DECLARATIVE) << op->errorName() << "+" << op->errorMessage();
        operationSucceeded = false;
    }

    return operationSucceeded;
}

void MessagesModel::setupChannelSignals(const Tp::TextChannelPtr &channel)
{
    connect(channel.data(),
            SIGNAL(messageReceived(Tp::ReceivedMessage)),
            SLOT(onMessageReceived(Tp::ReceivedMessage)));
    connect(channel.data(),
            SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
            SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
    connect(channel.data(),
            SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)),
            SLOT(onPendingMessageRemoved()));
}

void MessagesModel::setTextChannel(const Tp::TextChannelPtr &channel)
{
    Q_ASSERT(channel != d->textChannel);
    setupChannelSignals(channel);

    if (d->textChannel) {
        removeChannelSignals(d->textChannel);
    }

    d->textChannel = channel;

    d->logManager->setTextChannel(d->account, d->textChannel);

    //Load messages unless they have already been loaded
    if(!d->logsLoaded) {
        d->logManager->fetchScrollback();
    }

    QList<Tp::ReceivedMessage> messageQueue = channel->messageQueue();
    Q_FOREACH(const Tp::ReceivedMessage &message, messageQueue) {
        bool messageAlreadyInModel = false;
        Q_FOREACH(const MessagePrivate &current, d->messages) {
            //FIXME: docs say messageToken can return an empty string. What to do if that happens?
            //Tp::Message has an == operator. maybe I can use that?
            if (current.message.token() == message.messageToken()) {
                messageAlreadyInModel = true;
                break;
            }
        }
        if (!messageAlreadyInModel) {
            onMessageReceived(message);
        }
    }
}

void MessagesModel::onHistoryFetched(const QList<KTp::Message> &messages)
{
    if (!messages.isEmpty()) {
        //Add all messages before the ones already present in the channel
        beginInsertRows(QModelIndex(), 0, messages.count() - 1);
        for(int i=messages.size()-1;i>=0;i--) {
            d->messages.prepend(messages[i]);
        }
        endInsertRows();
    }
    d->logsLoaded = true;
}

void MessagesModel::onMessageReceived(const Tp::ReceivedMessage &message)
{
    int unreadCount = d->textChannel->messageQueue().size();
    if (message.isDeliveryReport()) {
        d->textChannel->acknowledge(QList<Tp::ReceivedMessage>() << message);

        Tp::ReceivedMessage::DeliveryDetails deliveryDetails = message.deliveryDetails();
        if(!deliveryDetails.hasOriginalToken()) {
            qCWarning(KTP_DECLARATIVE) << "Delivery report without original message token received.";
            // Matching the delivery report to the original message is impossible without the token.
            return;
        }

        QPersistentModelIndex originalMessageIndex = d->messagesByMessageToken.value(
                    deliveryDetails.originalToken());
        if (!originalMessageIndex.isValid() || originalMessageIndex.row() >= d->messages.count()) {
            // The original message for this delivery report was not found.
            return;
        }

        MessagePrivate &originalMessage = d->messages[originalMessageIndex.row()];
        originalMessage.deliveryReportReceiveTime = message.received();
        switch(deliveryDetails.status()) {
        case Tp::DeliveryStatusPermanentlyFailed:
        case Tp::DeliveryStatusTemporarilyFailed:
            originalMessage.deliveryStatus = DeliveryStatusFailed;
            if (deliveryDetails.hasDebugMessage()) {
                qCDebug(KTP_DECLARATIVE) << "Delivery failure debug message:" << deliveryDetails.debugMessage();
            }
            break;
        case Tp::DeliveryStatusDelivered:
            originalMessage.deliveryStatus = DeliveryStatusDelivered;
            break;
        case Tp::DeliveryStatusRead:
            originalMessage.deliveryStatus = DeliveryStatusRead;
            break;
        default:
            originalMessage.deliveryStatus = DeliveryStatusUnknown;
            break;
        }
        Q_EMIT dataChanged(originalMessageIndex, originalMessageIndex);
    } else {
        int newMessageIndex = 0;
        const QDateTime sentTimestamp = message.sent();
        if (sentTimestamp.isValid()) {
            for (int i = d->messages.count() - 1; i >= 0; --i) {
                if (sentTimestamp > d->messages.at(i).message.time()) {
                    newMessageIndex = i;
                    break;
                }
            }
        } else {
            newMessageIndex = rowCount();
        }
        beginInsertRows(QModelIndex(), newMessageIndex, newMessageIndex);

        d->messages.insert(newMessageIndex, KTp::MessageProcessor::instance()->processIncomingMessage(
                               message, d->account, d->textChannel));

        endInsertRows();

        if (d->visible) {
            acknowledgeAllMessages();
        } else {
            Q_EMIT unreadCountChanged(unreadCount);
        }
    }
}

void MessagesModel::onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &messageToken)
{
    Q_UNUSED(flags);

    int length = rowCount();
    beginInsertRows(QModelIndex(), length, length);

    const KTp::Message &newMessage = KTp::MessageProcessor::instance()->processIncomingMessage(
                message, d->account, d->textChannel);
    d->messages.append(newMessage);

    if (!messageToken.isEmpty()) {
        // Insert the message into the lookup table for delivery reports.
        const QPersistentModelIndex modelIndex = createIndex(length, 0);
        d->messagesByMessageToken.insert(messageToken, modelIndex);
    }

    endInsertRows();
}

void MessagesModel::onPendingMessageRemoved()
{
    Q_EMIT unreadCountChanged(unreadCount());
}

QVariant MessagesModel::data(const QModelIndex &index, int role) const
{
    QVariant result;

    if (index.isValid() && index.row() < rowCount(index.parent())) {
        const MessagePrivate m = d->messages[index.row()];

        switch (role) {
        case TextRole:
            result = m.message.finalizedMessage();
            break;
        case TypeRole:
            if (m.message.type() == Tp::ChannelTextMessageTypeAction) {
                result = MessageTypeAction;
            } else {
                if (m.message.direction() == KTp::Message::LocalToRemote) {
                    result = MessageTypeOutgoing;
                } else {
                    result = MessageTypeIncoming;
                }
            }
            break;
        case TimeRole:
            result = m.message.time();
            break;
        case SenderIdRole:
            result = m.message.senderId();
            break;
        case SenderAliasRole:
            result = m.message.senderAlias();
            break;
        case SenderAvatarRole:
            if (m.message.sender()) {
                result = QVariant::fromValue(m.message.sender()->avatarPixmap());
            }
            break;
        case DeliveryStatusRole:
            result = m.deliveryStatus;
            break;
        case DeliveryReportReceiveTimeRole:
            result = m.deliveryReportReceiveTime;
            break;
        };
    } else {
        qWarning() << "Attempting to access data at invalid index (" << index << ")";
    }

    return result;
}

int MessagesModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return d->messages.size();
}

void MessagesModel::sendNewMessage(const QString &message)
{
    if (message.isEmpty()) {
        qCWarning(KTP_DECLARATIVE) << "Attempting to send empty string";
    } else {
        Tp::PendingOperation *op;
        QString modifiedMessage = message;
        if (d->textChannel->supportsMessageType(Tp::ChannelTextMessageTypeAction)
                && modifiedMessage.startsWith(QLatin1String("/me "))) {
            //remove "/me " from the start of the message
            modifiedMessage.remove(0,4);
            op = d->textChannel->send(modifiedMessage, Tp::ChannelTextMessageTypeAction);
        } else {
            op = d->textChannel->send(modifiedMessage);
        }
        connect(op,
                SIGNAL(finished(Tp::PendingOperation*)),
                SLOT(verifyPendingOperation(Tp::PendingOperation*)));
    }
}

void MessagesModel::removeChannelSignals(const Tp::TextChannelPtr &channel)
{
    QObject::disconnect(channel.data(),
                        SIGNAL(messageReceived(Tp::ReceivedMessage)),
                        this,
                        SLOT(onMessageReceived(Tp::ReceivedMessage))
                       );
    QObject::disconnect(channel.data(),
                        SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
                        this,
                        SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString))
                       );
}

int MessagesModel::unreadCount() const
{
    return d->textChannel->messageQueue().size();
}

void MessagesModel::acknowledgeAllMessages()
{
    if (d->textChannel.isNull()) {
        return;
    }

    QList<Tp::ReceivedMessage> queue = d->textChannel->messageQueue();

    d->textChannel->acknowledge(queue);
    Q_EMIT unreadCountChanged(queue.size());
}

void MessagesModel::setVisibleToUser(bool visible)
{
    if (d->visible != visible) {
        d->visible = visible;
        Q_EMIT visibleToUserChanged(d->visible);
    }

    if (visible) {
        acknowledgeAllMessages();
    }
}

bool MessagesModel::isVisibleToUser() const
{
    return d->visible;
}

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

bool MessagesModel::shouldStartOpened() const
{
    return d->textChannel->isRequested();
}
<|endoftext|>


<commit_before>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-list-model.h"

#include "account-item.h"

#include <KDebug>
#include <KIcon>

#include <TelepathyQt4/Account>

AccountsListModel::AccountsListModel(QObject *parent)
 : QAbstractListModel(parent)
{
    kDebug();
}

AccountsListModel::~AccountsListModel()
{
    kDebug();
}

int AccountsListModel::rowCount(const QModelIndex & parent) const
{
    // If the index is the root item, then return the row count.
    if (parent == QModelIndex()) {
       return m_accounts.size();
    }

    // Otherwise, return 0 (as this is a list model, so all items
    // are children of the root item).
    return 0;
}

int AccountsListModel::columnCount(const QModelIndex& parent) const
{
    Q_UNUSED(parent);

    // Column count is always 1
    return 1;
}

QVariant AccountsListModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid()) {
        return QVariant();
    }

    QVariant data;
    Tp::AccountPtr account = m_accounts.at(index.row())->account();

    switch(role)
    {
    case Qt::DisplayRole:
        data = QVariant(account->displayName());
        break;

    case Qt::DecorationRole:
        data = QVariant(m_accounts.at(index.row())->icon());
        break;

    case Qt::CheckStateRole:
        if(account->isEnabled()) {
            data = QVariant(Qt::Checked);
        }
        else {
            data = QVariant(Qt::Unchecked);
        }
        break;

    case AccountsListModel::ConnectionStateDisplayRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateString());
        break;

    case AccountsListModel::ConnectionStateIconRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateIcon());
        break;

    case AccountsListModel::ConnectionErrorMessageDisplayRole:
        data = QVariant(m_accounts.at(index.row())->connectionStatusReason());
        break;

    case AccountsListModel::ConnectionProtocolNameRole:
        data = QVariant(m_accounts.at(index.row())->connectionProtocolName());
        break;

    default:
        break;
    }

    return data;
}

bool AccountsListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid()) {
        return false;
    }

    if(role == Qt::CheckStateRole) {
        m_accounts.at(index.row())->account()->setEnabled(value.toInt() == Qt::Checked);
        return true;
    }

    return false;
}

QModelIndex AccountsListModel::index(int row, int column, const QModelIndex& parent) const
{
    if(row < 0 || column < 0 || parent != QModelIndex()) {
        return QModelIndex();
    }

    if(row < rowCount() && column < columnCount()) {
        return createIndex(row, column);
    }

    return QModelIndex();
}

Qt::ItemFlags AccountsListModel::flags(const QModelIndex &index) const
{
    if(!index.isValid()) {
        return QAbstractItemModel::flags(index);
    }
    return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

void AccountsListModel::addAccount(const Tp::AccountPtr &account)
{
    kDebug() << "Creating a new AccountItem from account:" << account.data();

    // Check if the account is already in the model.
    bool found = false;

    if (!found) {
        foreach (const AccountItem* ai, m_accounts) {
            if (ai->account() == account) {
                found = true;
                break;
            }
        }
    }

    if (found) {
        kWarning() << "Requested to add account"
                   << account.data()
                   << "to model, but it is already present. Doing nothing.";
    } else {
        kDebug() << "Account not already in model. Create new AccountItem from account:"
                 << account.data();

        AccountItem *item = new AccountItem(account, this);

        beginInsertRows(QModelIndex(), m_accounts.size(), m_accounts.size());
        m_accounts.append(item);
        endInsertRows();

        connect(item, SIGNAL(removed()), SLOT(onAccountItemRemoved()));
        connect(item, SIGNAL(updated()), SLOT(onAccountItemUpdated()));
    }
}

void AccountsListModel::removeAccount(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kDebug() << "Can't remove Account: Invalid index";
        return;
    }
    AccountItem *accountItem = m_accounts.at(index.row());

    Q_ASSERT(accountItem);

    accountItem->remove();
}

AccountItem* AccountsListModel::itemForIndex(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kWarning() << "Invalid index" << index;
        return 0;
    }

    AccountItem *accountItem = m_accounts.at(index.row());
    return accountItem;
}

void AccountsListModel::onAccountItemRemoved()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    // We can be pretty sure that there is only one reference to a specific AccountItem in the list
    // If we screw up here, the styling delegate will screw up even more
    beginRemoveRows(QModelIndex(), m_accounts.indexOf(item), m_accounts.indexOf(item));
    m_accounts.removeAll(item);
    endRemoveRows();

    // FIXME: Workaround until the KWidgetItemDelegate gets fixed (probably KDE 4.7)
    reset();
    delete item;
}

void AccountsListModel::onAccountItemUpdated()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    QModelIndex index = createIndex(m_accounts.lastIndexOf(item), 0);
    emit dataChanged(index, index);
}

void AccountsListModel::onTitleForCustomPages(QString mandatoryPage, QList<QString> optionalPage)
{
    kDebug();

    emit setTitleForCustomPages(mandatoryPage, optionalPage);
}

#include "accounts-list-model.moc"
<commit_msg>Switch accounts model list to ErrorDictionary<commit_after>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-list-model.h"

#include "account-item.h"

#include <KDebug>
#include <KIcon>

#include <TelepathyQt4/Account>

#include "common/error-dictionary.h"

AccountsListModel::AccountsListModel(QObject *parent)
 : QAbstractListModel(parent)
{
    kDebug();
}

AccountsListModel::~AccountsListModel()
{
    kDebug();
}

int AccountsListModel::rowCount(const QModelIndex & parent) const
{
    // If the index is the root item, then return the row count.
    if (parent == QModelIndex()) {
       return m_accounts.size();
    }

    // Otherwise, return 0 (as this is a list model, so all items
    // are children of the root item).
    return 0;
}

int AccountsListModel::columnCount(const QModelIndex& parent) const
{
    Q_UNUSED(parent);

    // Column count is always 1
    return 1;
}

QVariant AccountsListModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid()) {
        return QVariant();
    }

    QVariant data;
    Tp::AccountPtr account = m_accounts.at(index.row())->account();

    switch(role)
    {
    case Qt::DisplayRole:
        data = QVariant(account->displayName());
        break;

    case Qt::DecorationRole:
        data = QVariant(m_accounts.at(index.row())->icon());
        break;

    case Qt::CheckStateRole:
        if(account->isEnabled()) {
            data = QVariant(Qt::Checked);
        }
        else {
            data = QVariant(Qt::Unchecked);
        }
        break;

    case AccountsListModel::ConnectionStateDisplayRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateString());
        break;

    case AccountsListModel::ConnectionStateIconRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateIcon());
        break;

    case AccountsListModel::ConnectionErrorMessageDisplayRole:
        data = QVariant(ErrorDictionary::instance()->displayShortErrorMessage(m_accounts.at(index.row())->account().data()->connectionError()));
        break;

    case AccountsListModel::ConnectionProtocolNameRole:
        data = QVariant(m_accounts.at(index.row())->connectionProtocolName());
        break;

    default:
        break;
    }

    return data;
}

bool AccountsListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid()) {
        return false;
    }
    kDebug();
    if(role == Qt::CheckStateRole) {
        m_accounts.at(index.row())->account()->setEnabled(value.toInt() == Qt::Checked);
        kDebug() << "shit";
        return true;
    }

    return false;
}

QModelIndex AccountsListModel::index(int row, int column, const QModelIndex& parent) const
{
    if(row < 0 || column < 0 || parent != QModelIndex()) {
        return QModelIndex();
    }

    if(row < rowCount() && column < columnCount()) {
        return createIndex(row, column);
    }

    return QModelIndex();
}

Qt::ItemFlags AccountsListModel::flags(const QModelIndex &index) const
{
    if(!index.isValid()) {
        return QAbstractItemModel::flags(index);
    }
    return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

void AccountsListModel::addAccount(const Tp::AccountPtr &account)
{
    kDebug() << "Creating a new AccountItem from account:" << account.data();

    // Check if the account is already in the model.
    bool found = false;

    if (!found) {
        foreach (const AccountItem* ai, m_accounts) {
            if (ai->account() == account) {
                found = true;
                break;
            }
        }
    }

    if (found) {
        kWarning() << "Requested to add account"
                   << account.data()
                   << "to model, but it is already present. Doing nothing.";
    } else {
        kDebug() << "Account not already in model. Create new AccountItem from account:"
                 << account.data();

        AccountItem *item = new AccountItem(account, this);

        beginInsertRows(QModelIndex(), m_accounts.size(), m_accounts.size());
        m_accounts.append(item);
        endInsertRows();

        connect(item, SIGNAL(removed()), SLOT(onAccountItemRemoved()));
        connect(item, SIGNAL(updated()), SLOT(onAccountItemUpdated()));
    }
}

void AccountsListModel::removeAccount(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kDebug() << "Can't remove Account: Invalid index";
        return;
    }
    AccountItem *accountItem = m_accounts.at(index.row());

    Q_ASSERT(accountItem);

    accountItem->remove();
}

AccountItem* AccountsListModel::itemForIndex(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kWarning() << "Invalid index" << index;
        return 0;
    }

    AccountItem *accountItem = m_accounts.at(index.row());
    return accountItem;
}

void AccountsListModel::onAccountItemRemoved()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    // We can be pretty sure that there is only one reference to a specific AccountItem in the list
    // If we screw up here, the styling delegate will screw up even more
    beginRemoveRows(QModelIndex(), m_accounts.indexOf(item), m_accounts.indexOf(item));
    m_accounts.removeAll(item);
    endRemoveRows();

    // FIXME: Workaround until the KWidgetItemDelegate gets fixed (probably KDE 4.7)
    reset();
    delete item;
}

void AccountsListModel::onAccountItemUpdated()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    QModelIndex index = createIndex(m_accounts.lastIndexOf(item), 0);
    emit dataChanged(index, index);
}

void AccountsListModel::onTitleForCustomPages(QString mandatoryPage, QList<QString> optionalPage)
{
    kDebug();

    emit setTitleForCustomPages(mandatoryPage, optionalPage);
}

#include "accounts-list-model.moc"
<|endoftext|>