<commit_before>/**
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Disa Mhembere (disa@jhu.edu)
 *
 * This file is part of FlashGraph.
 *
 * 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 CURRENT_KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <signal.h>
#include <google/profiler.h>

#include <vector>
#include <algorithm>

#include "thread.h"
#include "io_interface.h"
#include "container.h"
#include "concurrency.h"

#include "vertex_index.h"
#include "graph_engine.h"
#include "graph_config.h"

vsize_t CURRENT_K; // Min degree necessary to be part of the k-core graph
vsize_t PREVIOUS_K;
bool all_greater_than_core = true;

class kcore_vertex: public compute_directed_vertex
{
  bool deleted;
  vsize_t core;
  vsize_t degree;

public:
	kcore_vertex() {
	}

  kcore_vertex(vertex_id_t id, const vertex_index &index1):
    compute_directed_vertex(id, index1) {
	const directed_vertex_index &index = (const directed_vertex_index &) index1;
    this->degree = index.get_num_in_edges(id) + index.get_num_out_edges(id);
    this->core = degree == 0 ? 0 :
                degree == 1 ? 1 : -1; // Everyone between kmin < core > kmax will get this core
    this->deleted = degree == 0 ? true : false; // If your degree you're already deleted
  }

  bool is_deleted() const {
    return deleted;
  }

  void _delete() {
    this->deleted = true;
  }

  void set_core(vsize_t core) {
    this->core = core;
  }

  const vsize_t get_core() const {
    return this->core;
  }

  vsize_t get_degree() {
    return degree;
  }

  void run(vertex_program &prog);

	void run(vertex_program &prog, const page_vertex &vertex);

	void run_on_message(vertex_program &prog, const vertex_message &msg);
};

// If I am to be deleted, multicast this message to all my neighbors
// and activate them
class deleted_message: public vertex_message
{
  public:
  deleted_message(): vertex_message(sizeof(deleted_message), true) {
  }
};

void multicast_delete_msg(vertex_program &prog,
      const page_vertex &vertex, edge_type E)
{
  int num_dests = vertex.get_num_edges(E);
  edge_seq_iterator it = vertex.get_neigh_seq_it(E, 0, num_dests);

  // Doesn't matter who sent it, just --degree on reception
  deleted_message msg;
  prog.multicast_msg(it, msg);
}

void kcore_vertex::run(vertex_program &prog) {
  if ( degree > CURRENT_K ) {
    return;
  }

  if (!is_deleted()) {
    vertex_id_t id = get_id();
    request_vertices(&id, 1); // put my edgelist in page cache

    if (all_greater_than_core) {
      all_greater_than_core = false;
    }
  }
}

void kcore_vertex::run(vertex_program &prog, const page_vertex &vertex) {
  if (is_deleted()) {
    return; // Nothing to be done here
  }

  if ( get_degree() < CURRENT_K ) {
    set_core(CURRENT_K - (CURRENT_K - get_degree())); // TODO: Verify
    _delete();

    // Send two multicast messages - [IN_EDGE, OUT_EDGE]
    multicast_delete_msg(prog, vertex, IN_EDGE);
    multicast_delete_msg(prog, vertex, OUT_EDGE);
  }

}

void kcore_vertex::run_on_message(vertex_program &prog, const vertex_message &msg) {
  if (is_deleted()) {
    return; // nothing to be done here
  }
  // else
  degree--;
}

class count_vertex_query: public vertex_query
{
	size_t num;
public:
	count_vertex_query() {
		num = 0;
	}

	virtual void run(graph_engine &graph, compute_vertex &v) {
		kcore_vertex &kcore_v = (kcore_vertex &) v;
		if (!kcore_v.is_deleted())
			num++;
	}

	virtual void merge(graph_engine &graph, vertex_query::ptr q) {
		count_vertex_query *cvq = (count_vertex_query *) q.get();
		num += cvq->num;
	}

	virtual ptr clone() {
		return vertex_query::ptr(new count_vertex_query());
	}

	size_t get_num() const {
		return num;
	}
};

// Max degree corresponds to the highest core
class max_degree_query: public vertex_query
{
  vsize_t max_degree;
public:
  max_degree_query() {
    max_degree = 0;
  }

  virtual void run(graph_engine &graph, compute_vertex &v) {
    if (graph.get_vertex_edges(v.get_id()) > max_degree) {
      max_degree = graph.get_vertex_edges(v.get_id());
    }
  }

  virtual void merge(graph_engine &graph, vertex_query::ptr q) {
    max_degree_query *mdq = (max_degree_query *) q.get();
    if (max_degree < mdq->max_degree) {
      max_degree = mdq->max_degree;
    }
  }

  virtual ptr clone() {
    return vertex_query::ptr(new max_degree_query());
  }

  vsize_t get_max_degree() const {
    return max_degree;
  }
};

// Figure out the lowest REMAINING degree in the graph
class min_degree_query: public vertex_query
{
  vsize_t min_degree;
public:
  min_degree_query() {
    min_degree = std::numeric_limits<vsize_t>::max();
  }

  virtual void run(graph_engine &graph, compute_vertex &v) {
    kcore_vertex kcore_v = (kcore_vertex&) v;
    if (!kcore_v.is_deleted()) {
      if (kcore_v.get_degree() < min_degree) {
        min_degree = kcore_v.get_degree();
      }
    }
  }

  virtual void merge(graph_engine &graph, vertex_query::ptr q) {
    min_degree_query *mdq = (min_degree_query *) q.get();
    if (min_degree > mdq->min_degree) {
      min_degree = mdq->min_degree;
    }
  }

  virtual ptr clone() {
    return vertex_query::ptr(new min_degree_query());
  }

  vsize_t get_min_degree() const {
    return min_degree;
  }
};

void int_handler(int sig_num)
{
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	exit(0);
}

void print_usage()
{
	fprintf(stderr,
			"k-core [options] conf_file graph_file index_file kmin [kmax] (=Max Degree)\n");
	fprintf(stderr, "-c confs: add more configurations to the system\n");
	graph_conf.print_help();
	params.print_help();
}

// Helpers
void print_func(vertex_id_t i) {
  std::cout << " " << i;
}
void print_active(std::vector<vertex_id_t> v) {
  std::cout << "[";
    for_each (v.begin(), v.end(), print_func);
  std::cout <<  " ]\n";
}
// End Helpers

int main(int argc, char *argv[])
{
	int opt;
	std::string confs;
	int num_opts = 0;
	while ((opt = getopt(argc, argv, "c:")) != -1) {
		num_opts++;
		switch (opt) {
			case 'c':
				confs = optarg;
				num_opts++;
				break;
			default:
				print_usage();
		}
	}
	argv += 1 + num_opts;
	argc -= 1 + num_opts;

	if (argc < 4) {
		print_usage();
		exit(-1);
	}

	std::string conf_file = argv[0];
	std::string graph_file = argv[1];
	std::string index_file = argv[2];
	CURRENT_K = atol(argv[3]); // Set kmin

  if (CURRENT_K < 2) {
   fprintf(stderr, "[Error]: kmin cannot be < 2\n");
   exit(-1);
  }

	config_map configs(conf_file);
	configs.add_options(confs);

	signal(SIGINT, int_handler);

	graph_index::ptr index = NUMA_graph_index<kcore_vertex>::create(index_file);
	graph_engine::ptr graph = graph_engine::create(graph_file, index, configs);
	printf("K-core starting\n");
	// printf("prof_file: %s\n", graph_conf.get_prof_file().c_str());
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());

  // Set kmax
  vsize_t kmax;
  if (argc > 4) {
    kmax = atol(argv[4]);
  }
  else { // compute largest degree and set it
    printf("Computing kmax as max_degree ...\n");
    vertex_query::ptr mdq(new max_degree_query());
    graph->query_on_all(mdq);
    kmax = ((max_degree_query *) mdq.get())->get_max_degree();
  }
  printf("Setting kmax to %u ... \n", kmax);

  class activate_k_filter: public vertex_filter {
    vsize_t min;
    public:
    activate_k_filter (vsize_t min) {
      this->min = min;
    }
    bool keep(compute_vertex &v) {
      kcore_vertex &kcore_v = (kcore_vertex &) v;
      return kcore_v.get_degree() < min;
    }
  };

  for (; CURRENT_K <= kmax; CURRENT_K++) {

    std::shared_ptr<vertex_filter> filter
      = std::shared_ptr<vertex_filter>(new activate_k_filter(CURRENT_K));

    struct timeval start, end;
    gettimeofday(&start, NULL);
    graph->start(filter, vertex_program_creater::ptr());
    graph->wait4complete();
    gettimeofday(&end, NULL);

    if (all_greater_than_core) { // There's a chance we can hop forward
      printf("***All are greater than K = %u\n", CURRENT_K);
      vertex_query::ptr mdq(new min_degree_query());
      graph->query_on_all(mdq);
      vsize_t min_degree_remaining = ((min_degree_query *) mdq.get())->get_min_degree();

      if (min_degree_remaining == std::numeric_limits<vsize_t>::max()) {
        printf("No more active vertices left!\n");
        break;
      }

      printf("\n\nThe graphs minimum degree remaining is %u\n\n", min_degree_remaining);
      CURRENT_K = min_degree_remaining;

      // TODO: Remove this if and TEST
      if (CURRENT_K > kmax || CURRENT_K == PREVIOUS_K)
        break;
    }
    all_greater_than_core = true;

#if 1
    vertex_query::ptr cvq(new count_vertex_query());
    graph->query_on_all(cvq);
    size_t in_k_core = ((count_vertex_query *) cvq.get())->get_num();
    printf("\n******************************************\n"
        "%d-core shows %ld vertices > %d degree in %f seconds\n"
        "\n******************************************\n",
        CURRENT_K, in_k_core, CURRENT_K, time_diff(start, end));
#endif
    PREVIOUS_K = CURRENT_K;

  }

	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	//if (graph_conf.get_print_io_stat())
		//print_io_thread_stat();
}
<commit_msg>[Bug]: K-core/coreness fully functional and tested for accuracy<commit_after>/**
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Disa Mhembere (disa@jhu.edu)
 *
 * This file is part of FlashGraph.
 *
 * 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 CURRENT_KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <signal.h>
#include <google/profiler.h>

#include <vector>
#include <algorithm>

#include "thread.h"
#include "io_interface.h"
#include "container.h"
#include "concurrency.h"

#include "vertex_index.h"
#include "graph_engine.h"
#include "graph_config.h"

vsize_t CURRENT_K; // Min degree necessary to be part of the k-core graph
vsize_t PREVIOUS_K;
bool all_greater_than_core = true;

class kcore_vertex: public compute_directed_vertex
{
  bool deleted;
  vsize_t core;
  vsize_t degree;

public:
	kcore_vertex() {
	}

  kcore_vertex(vertex_id_t id, const vertex_index &index1):
    compute_directed_vertex(id, index1) {
	const directed_vertex_index &index = (const directed_vertex_index &) index1;
    this->degree = index.get_num_in_edges(id) + index.get_num_out_edges(id);
    this->core = degree == 0 ? 0 :
                degree == 1 ? 1 : -1; // Everyone between kmin < core > kmax will get this core
    this->deleted = degree == 0 ? true : false; // If your degree you're already deleted
  }

  bool is_deleted() const {
    return deleted;
  }

  void _delete() {
    this->deleted = true;
  }

  void set_core(vsize_t core) {
    this->core = core;
  }

  const vsize_t get_core() const {
    return this->core;
  }

  vsize_t get_degree() {
    return degree;
  }

  void run(vertex_program &prog);

	void run(vertex_program &prog, const page_vertex &vertex);

	void run_on_message(vertex_program &prog, const vertex_message &msg);
};

// If I am to be deleted, multicast this message to all my neighbors
// and activate them
class deleted_message: public vertex_message
{
  public:
  deleted_message(): vertex_message(sizeof(deleted_message), true) {
  }
};

void multicast_delete_msg(vertex_program &prog,
      const page_vertex &vertex, edge_type E)
{
  int num_dests = vertex.get_num_edges(E);
  edge_seq_iterator it = vertex.get_neigh_seq_it(E, 0, num_dests);

  // Doesn't matter who sent it, just --degree on reception
  deleted_message msg;
  prog.multicast_msg(it, msg);
}

void kcore_vertex::run(vertex_program &prog) {
  if ( degree > CURRENT_K ) {
    return;
  }

  if (!is_deleted()) {
    vertex_id_t id = get_id();
    request_vertices(&id, 1); // put my edgelist in page cache

    if (all_greater_than_core) {
      all_greater_than_core = false;
    }
  }
}

void kcore_vertex::run(vertex_program &prog, const page_vertex &vertex) {
  if (is_deleted()) {
    return; // Nothing to be done here
  }

  if ( get_degree() < CURRENT_K ) {
    set_core(CURRENT_K - 1); // This is true because you must make it past CURRENT_K-1 to be here
    _delete();

    // Send two multicast messages - [IN_EDGE, OUT_EDGE]
    multicast_delete_msg(prog, vertex, IN_EDGE);
    multicast_delete_msg(prog, vertex, OUT_EDGE);
  }
}

void kcore_vertex::run_on_message(vertex_program &prog, const vertex_message &msg) {
  if (is_deleted()) {
    return; // nothing to be done here
  }
  // else
  degree--;
}

class count_vertex_query: public vertex_query
{
	size_t num;
public:
	count_vertex_query() {
		num = 0;
	}

	virtual void run(graph_engine &graph, compute_vertex &v) {
		kcore_vertex &kcore_v = (kcore_vertex &) v;
		if (!kcore_v.is_deleted())
			num++;
	}

	virtual void merge(graph_engine &graph, vertex_query::ptr q) {
		count_vertex_query *cvq = (count_vertex_query *) q.get();
		num += cvq->num;
	}

	virtual ptr clone() {
		return vertex_query::ptr(new count_vertex_query());
	}

	size_t get_num() const {
		return num;
	}
};

// Max degree corresponds to the highest core
class max_degree_query: public vertex_query
{
  vsize_t max_degree;
public:
  max_degree_query() {
    max_degree = 0;
  }

  virtual void run(graph_engine &graph, compute_vertex &v) {
    if (graph.get_vertex_edges(v.get_id()) > max_degree) {
      max_degree = graph.get_vertex_edges(v.get_id());
    }
  }

  virtual void merge(graph_engine &graph, vertex_query::ptr q) {
    max_degree_query *mdq = (max_degree_query *) q.get();
    if (max_degree < mdq->max_degree) {
      max_degree = mdq->max_degree;
    }
  }

  virtual ptr clone() {
    return vertex_query::ptr(new max_degree_query());
  }

  vsize_t get_max_degree() const {
    return max_degree;
  }
};

// Figure out the lowest REMAINING degree in the graph
class min_degree_query: public vertex_query
{
  vsize_t min_degree;
public:
  min_degree_query() {
    min_degree = std::numeric_limits<vsize_t>::max();
  }

  virtual void run(graph_engine &graph, compute_vertex &v) {
    kcore_vertex kcore_v = (kcore_vertex&) v;
    if (!kcore_v.is_deleted()) {
      if (kcore_v.get_degree() < min_degree) {
        min_degree = kcore_v.get_degree();
      }
    }
  }

  virtual void merge(graph_engine &graph, vertex_query::ptr q) {
    min_degree_query *mdq = (min_degree_query *) q.get();
    if (min_degree > mdq->min_degree) {
      min_degree = mdq->min_degree;
    }
  }

  virtual ptr clone() {
    return vertex_query::ptr(new min_degree_query());
  }

  vsize_t get_min_degree() const {
    return min_degree;
  }
};

void int_handler(int sig_num)
{
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	exit(0);
}

void print_usage()
{
	fprintf(stderr,
			"k-core [options] conf_file graph_file index_file kmin [kmax] (=Max Degree)\n");
	fprintf(stderr, "-c confs: add more configurations to the system\n");
	graph_conf.print_help();
	params.print_help();
}

// Helpers
void print_func(vertex_id_t i) {
  std::cout << " " << i;
}
void print_active(std::vector<vertex_id_t> v) {
  std::cout << "[";
    for_each (v.begin(), v.end(), print_func);
  std::cout <<  " ]\n";
}
// End Helpers

int main(int argc, char *argv[])
{
	int opt;
	std::string confs;
	int num_opts = 0;
	while ((opt = getopt(argc, argv, "c:")) != -1) {
		num_opts++;
		switch (opt) {
			case 'c':
				confs = optarg;
				num_opts++;
				break;
			default:
				print_usage();
		}
	}
	argv += 1 + num_opts;
	argc -= 1 + num_opts;

	if (argc < 4) {
		print_usage();
		exit(-1);
	}

	std::string conf_file = argv[0];
	std::string graph_file = argv[1];
	std::string index_file = argv[2];
	CURRENT_K = atol(argv[3]); // Set kmin

  if (CURRENT_K < 2) {
   fprintf(stderr, "[Error]: kmin cannot be < 2\n");
   exit(-1);
  }

	config_map configs(conf_file);
	configs.add_options(confs);

	signal(SIGINT, int_handler);

	graph_index::ptr index = NUMA_graph_index<kcore_vertex>::create(index_file);
	graph_engine::ptr graph = graph_engine::create(graph_file, index, configs);
	printf("K-core starting\n");
	// printf("prof_file: %s\n", graph_conf.get_prof_file().c_str());
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());

  // Set kmax
  vsize_t kmax;
  if (argc > 4) {
    kmax = atol(argv[4]);
  }
  else { // compute largest degree and set it
    printf("Computing kmax as max_degree ...\n");
    vertex_query::ptr mdq(new max_degree_query());
    graph->query_on_all(mdq);
    kmax = ((max_degree_query *) mdq.get())->get_max_degree();
  }
  printf("Setting kmax to %u ... \n", kmax);

  class activate_k_filter: public vertex_filter {
    vsize_t min;
    public:
    activate_k_filter (vsize_t min) {
      this->min = min;
    }
    bool keep(compute_vertex &v) {
      kcore_vertex &kcore_v = (kcore_vertex &) v;
      return kcore_v.get_degree() < min;
    }
  };

  for (; CURRENT_K <= kmax; CURRENT_K++) {

    std::shared_ptr<vertex_filter> filter
      = std::shared_ptr<vertex_filter>(new activate_k_filter(CURRENT_K));

    struct timeval start, end;
    gettimeofday(&start, NULL);
    graph->start(filter, vertex_program_creater::ptr());
    graph->wait4complete();
    gettimeofday(&end, NULL);

    if (all_greater_than_core) { // There's a chance we can hop forward
      printf("***All are greater than K = %u\n", CURRENT_K);
      vertex_query::ptr mdq(new min_degree_query());
      graph->query_on_all(mdq);
      vsize_t min_degree_remaining = ((min_degree_query *) mdq.get())->get_min_degree();

      if (min_degree_remaining == std::numeric_limits<vsize_t>::max()) {
        printf("No more active vertices left!\n");
        break;
      }

      printf("\n\nThe graphs minimum degree remaining is %u\n\n", min_degree_remaining);
      // Effectively jumps us to the CURRENT_K + 1th core
      CURRENT_K = min_degree_remaining; // NOTE: Careful - messing with the loop variable :/

      if (CURRENT_K > kmax)
        printf("\nTerminating computation at kmax\n");
        break;
    }
    all_greater_than_core = true;

#if 1
    vertex_query::ptr cvq(new count_vertex_query());
    graph->query_on_all(cvq);
    size_t in_k_core = ((count_vertex_query *) cvq.get())->get_num();
    printf("\n******************************************\n"
        "%d-core shows %ld vertices > %d degree in %f seconds\n"
        "\n******************************************\n",
        CURRENT_K, in_k_core, CURRENT_K, time_diff(start, end));
#endif
    PREVIOUS_K = CURRENT_K;

  }

  // Print out
  graph_index::const_iterator it = index->begin();
  graph_index::const_iterator end_it = index->end();
  printf("Cores by vertex:\n");
  for (; it != end_it; ++it) {
    const kcore_vertex &v = (const kcore_vertex &) *it;
    printf("%u, ", v.get_core());
  }
  printf("\n");

	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	//if (graph_conf.get_print_io_stat())
		//print_io_thread_stat();
}
<|endoftext|>


<commit_before>#if _WIN32
#pragma warning(disable : 4996 4267)
#endif

#include "./placement_labeller_model.h"
#include "./labelling_coordinator.h"

const int ROW_COUNT = 9;

PlacementLabellerModel::PlacementLabellerModel(
    std::shared_ptr<LabellingCoordinator> coordinator)
  : coordinator(coordinator)
{
}

QHash<int, QByteArray> PlacementLabellerModel::roleNames() const
{
  QHash<int, QByteArray> roles;
  roles[NameRole] = "name";
  roles[WeightRole] = "weight";

  return roles;
}

int PlacementLabellerModel::rowCount(const QModelIndex &parent) const
{
  Q_UNUSED(parent);
  return ROW_COUNT;
}

int PlacementLabellerModel::columnCount(const QModelIndex &parent) const
{
  Q_UNUSED(parent);
  return 2;
}

QVariant PlacementLabellerModel::data(const QModelIndex &index, int role) const
{
  if (index.row() < 0 || index.row() >= ROW_COUNT)
    return QVariant();

  switch (role)
  {
  case NameRole:
    return QVariant::fromValue(getWeightNameForRowIndex(index.row()));
  case WeightRole:
    return QVariant::fromValue(getWeightValueForRowIndex(index.row()));
  }
  return QVariant();
}

Qt::ItemFlags PlacementLabellerModel::flags(const QModelIndex &index) const
{
  if (!index.isValid())
    return Qt::ItemIsEnabled;

  return QAbstractItemModel::flags(index) | Qt::ItemFlag::ItemIsEditable |
         Qt::ItemIsUserCheckable;
}

bool PlacementLabellerModel::getIsVisible() const
{
  return isVisible;
}

void PlacementLabellerModel::changeWeight(int row, QVariant newValue)
{
  bool converted = false;
  auto value = newValue.toFloat(&converted);
  if (converted)
  {
    switch (row)
    {
    case 0:
      weights.labelShadowConstraint = value;
      break;
    case 1:
      weights.distanceToOldPosition = value;
      break;
    case 2:
      weights.distanceToAnchor = value;
      break;
    case 3:
      weights.favorHorizontalOrVerticalLines = value;
      break;
    case 4:
      weights.connectorShadowConstraint = value;
      break;
    case 5:
      weights.anchorConstraint = value;
      break;
    case 6:
      weights.integralCosts = value;
      break;
    case 7:
      integralCostsWeights.saliency = value;
      break;
    case 8:
      integralCostsWeights.occlusion = value;
      break;
    }
  }

  coordinator->setCostFunctionWeights(weights);
}

void PlacementLabellerModel::toggleVisibility()
{
  isVisible = !isVisible;
  emit isVisibleChanged();
}

void PlacementLabellerModel::simulateHardConstraints()
{
  beginResetModel();

  weights.connectorShadowConstraint = std::numeric_limits<float>::max();
  weights.labelShadowConstraint = std::numeric_limits<float>::max();
  coordinator->setCostFunctionWeights(weights);

  endResetModel();
}

QString PlacementLabellerModel::getWeightNameForRowIndex(int rowIndex) const
{
  switch (rowIndex)
  {
  case 0:
    return "Label shadow";
  case 1:
    return "Distance to old position";
  case 2:
    return "Distance to anchor";
  case 3:
    return "Connector orientation";
  case 4:
    return "Connector shadow";
  case 5:
    return "Anchor constraint";
  case 6:
    return "Integral costs:";
  case 7:
    return "- Saliency";
  case 8:
    return "- Occlusion";
  }

  return "Unknown";
}

float PlacementLabellerModel::getWeightValueForRowIndex(int rowIndex) const
{
  switch (rowIndex)
  {
  case 0:
    return weights.labelShadowConstraint;
  case 1:
    return weights.distanceToOldPosition;
  case 2:
    return weights.distanceToAnchor;
  case 3:
    return weights.favorHorizontalOrVerticalLines;
  case 4:
    return weights.connectorShadowConstraint;
  case 5:
    return weights.anchorConstraint;
  case 6:
    return weights.integralCosts;
  case 7:
    return integralCostsWeights.saliency;
  case 8:
    return integralCostsWeights.occlusion;
  }

  return 0.0f;
}

<commit_msg>Minor: fix linting error.<commit_after>#if _WIN32
#pragma warning(disable : 4996 4267)
#endif

#include "./placement_labeller_model.h"
#include <limits>
#include "./labelling_coordinator.h"

const int ROW_COUNT = 9;

PlacementLabellerModel::PlacementLabellerModel(
    std::shared_ptr<LabellingCoordinator> coordinator)
  : coordinator(coordinator)
{
}

QHash<int, QByteArray> PlacementLabellerModel::roleNames() const
{
  QHash<int, QByteArray> roles;
  roles[NameRole] = "name";
  roles[WeightRole] = "weight";

  return roles;
}

int PlacementLabellerModel::rowCount(const QModelIndex &parent) const
{
  Q_UNUSED(parent);
  return ROW_COUNT;
}

int PlacementLabellerModel::columnCount(const QModelIndex &parent) const
{
  Q_UNUSED(parent);
  return 2;
}

QVariant PlacementLabellerModel::data(const QModelIndex &index, int role) const
{
  if (index.row() < 0 || index.row() >= ROW_COUNT)
    return QVariant();

  switch (role)
  {
  case NameRole:
    return QVariant::fromValue(getWeightNameForRowIndex(index.row()));
  case WeightRole:
    return QVariant::fromValue(getWeightValueForRowIndex(index.row()));
  }
  return QVariant();
}

Qt::ItemFlags PlacementLabellerModel::flags(const QModelIndex &index) const
{
  if (!index.isValid())
    return Qt::ItemIsEnabled;

  return QAbstractItemModel::flags(index) | Qt::ItemFlag::ItemIsEditable |
         Qt::ItemIsUserCheckable;
}

bool PlacementLabellerModel::getIsVisible() const
{
  return isVisible;
}

void PlacementLabellerModel::changeWeight(int row, QVariant newValue)
{
  bool converted = false;
  auto value = newValue.toFloat(&converted);
  if (converted)
  {
    switch (row)
    {
    case 0:
      weights.labelShadowConstraint = value;
      break;
    case 1:
      weights.distanceToOldPosition = value;
      break;
    case 2:
      weights.distanceToAnchor = value;
      break;
    case 3:
      weights.favorHorizontalOrVerticalLines = value;
      break;
    case 4:
      weights.connectorShadowConstraint = value;
      break;
    case 5:
      weights.anchorConstraint = value;
      break;
    case 6:
      weights.integralCosts = value;
      break;
    case 7:
      integralCostsWeights.saliency = value;
      break;
    case 8:
      integralCostsWeights.occlusion = value;
      break;
    }
  }

  coordinator->setCostFunctionWeights(weights);
}

void PlacementLabellerModel::toggleVisibility()
{
  isVisible = !isVisible;
  emit isVisibleChanged();
}

void PlacementLabellerModel::simulateHardConstraints()
{
  beginResetModel();

  weights.connectorShadowConstraint = std::numeric_limits<float>::max();
  weights.labelShadowConstraint = std::numeric_limits<float>::max();
  coordinator->setCostFunctionWeights(weights);

  endResetModel();
}

QString PlacementLabellerModel::getWeightNameForRowIndex(int rowIndex) const
{
  switch (rowIndex)
  {
  case 0:
    return "Label shadow";
  case 1:
    return "Distance to old position";
  case 2:
    return "Distance to anchor";
  case 3:
    return "Connector orientation";
  case 4:
    return "Connector shadow";
  case 5:
    return "Anchor constraint";
  case 6:
    return "Integral costs:";
  case 7:
    return "- Saliency";
  case 8:
    return "- Occlusion";
  }

  return "Unknown";
}

float PlacementLabellerModel::getWeightValueForRowIndex(int rowIndex) const
{
  switch (rowIndex)
  {
  case 0:
    return weights.labelShadowConstraint;
  case 1:
    return weights.distanceToOldPosition;
  case 2:
    return weights.distanceToAnchor;
  case 3:
    return weights.favorHorizontalOrVerticalLines;
  case 4:
    return weights.connectorShadowConstraint;
  case 5:
    return weights.anchorConstraint;
  case 6:
    return weights.integralCosts;
  case 7:
    return integralCostsWeights.saliency;
  case 8:
    return integralCostsWeights.occlusion;
  }

  return 0.0f;
}

<|endoftext|>


<commit_before>#include "icore.h"

/*!
    \namespace Core
    \brief The Core namespace contains all classes that make up the Core plugin
    which constitute the basic functionality of Qt Creator.
*/

/*!
    \namespace Core::Internal
    \internal
*/

/*!
    \class Core::ICore
    \brief The ICore class allows access to the different part that make up
    the basic functionality of Qt Creator.

    You should never create a subclass of this interface. The one and only
    instance is created by the Core plugin. You can access this instance
    from your plugin via the plugin manager, e.g.
    \code
        ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
    \endcode

    \mainclass
*/

/*!
    \fn QStringList ICore::showNewItemDialog(const QString &title,
                                      const QList<IWizard *> &wizards,
                                      const QString &defaultLocation = QString())
    \brief Opens a dialog where the user can choose from a set of \a wizards that
    create new files/classes/projects.

    The \a title argument is shown as the dialogs title. The path where the
    files will be created (if the user doesn't change it) is set
    in \a defaultLocation. It defaults to the path of the file manager's
    current file.

    \sa Core::FileManager
*/

/*!
    \fn void ICore::showOptionsDialog(const QString &group = QString(),
                               const QString &page = QString())
    \brief Opens the application options/preferences dialog with preselected
    \a page in a specified \a group.

    The arguments refer to the string IDs of the corresponding IOptionsPage.
*/

/*!
    \fn ActionManager *ICore::actionManager() const
    \brief Returns the application's action manager.

    The action manager is responsible for registration of menus and
    menu items and keyboard shortcuts.
*/

/*!
    \fn FileManager *ICore::fileManager() const
    \brief Returns the application's file manager.

    The file manager keeps track of files for changes outside the application.
*/

/*!
    \fn UniqueIDManager *ICore::uniqueIDManager() const
    \brief Returns the application's id manager.

    The unique ID manager transforms strings in unique integers and the other way round.
*/

/*!
    \fn MessageManager *ICore::messageManager() const
    \brief Returns the application's message manager.

    The message manager is the interface to the "General" output pane for
    general application debug messages.
*/

/*!
    \fn ExtensionSystem::PluginManager *ICore::pluginManager() const
    \brief Returns the application's plugin manager.

    The plugin manager handles the plugin life cycles and manages
    the common object pool.
*/

/*!
    \fn EditorManager *ICore::editorManager() const
    \brief Returns the application's editor manager.

    The editor manager handles all editor related tasks like opening
    documents, the stack of currently open documents and the currently
    active document.
*/

/*!
    \fn ProgressManager *ICore::progressManager() const
    \brief Returns the application's progress manager.

    Use the progress manager to register a concurrent task to
    show a progress bar the way Qt Creator does it.
*/

/*!
    \fn ScriptManager *ICore::scriptManager() const
    \internal
*/

/*!
    \fn VariableManager *ICore::variableManager() const
    \brief Returns the application's variable manager.

    The variable manager is used to register application wide string variables
    like \c MY_PROJECT_DIR such that strings like \c{somecommand ${MY_PROJECT_DIR}/sub}
    can be resolved/expanded from anywhere in the application.
*/

/*!
    \fn VCSManager *ICore::vcsManager() const
    \brief Returns the application's vcs manager.

    The vcs manager can be used to e.g. retrieve information about
    the version control system used for a directory on hard disk.
    The actual functionality for a specific version control system
    must be implemented in a IVersionControl object and registered in
    the plugin manager's object pool.
*/

/*!
    \fn ModeManager *ICore::modeManager() const
    \brief Returns the application's mode manager.

    The mode manager handles everything related to the instances of IMode
    that were added to the plugin manager's object pool as well as their
    buttons and the tool bar with the round buttons in the lower left
    corner of Qt Creator.
*/

/*!
    \fn MimeDatabase *ICore::mimeDatabase() const
    \brief Returns the application's mime database.

    Use the mime database to manage mime types.
*/

/*!
    \fn QSettings *ICore::settings() const
    \brief Returns the application's main settings object.

    You can use it to retrieve or set application wide settings
    (in contrast to session or project specific settings).
*/

/*!
    \fn QPrinter *ICore::printer() const
    \brief Returns the application's printer object.

    Always use this printer object for printing, so the different parts of the
    application re-use it's settings.
*/

/*!
    \fn QString ICore::resourcePath() const
    \brief Returns the absolute path that is used for resources like
    project templates and the debugger macros.

    This abstraction is needed to avoid platform-specific code all over
    the place, since e.g. on Mac the resources are part of the application bundle.
*/

/*!
    \fn QMainWindow *ICore::mainWindow() const
    \brief Returns the main application window.

    For use as dialog parent etc.
*/

/*!
    \fn IContext *ICore::currentContextObject() const
    \brief Returns the context object of the current main context.

    \sa ICore::addAdditionalContext()
    \sa ICore::addContextObject()
*/

/*!
    \fn void ICore::addAdditionalContext(int context)
    \brief Register additional context to be currently active.

    Appends the additional \a context to the list of currently active
    contexts. You need to call ICore::updateContext to make that change
    take effect.

    \sa ICore::removeAdditionalContext()
    \sa ICore::hasContext()
    \sa ICore::updateContext()
*/

/*!
    \fn void ICore::removeAdditionalContext(int context)
    \brief Removes the given \a context from the list of currently active contexts.

    You need to call ICore::updateContext to make that change
    take effect.

    \sa ICore::addAdditionalContext()
    \sa ICore::hasContext()
    \sa ICore::updateContext()
*/

/*!
    \fn bool ICore::hasContext(int context) const
    \brief Returns if the given \a context is currently one of the active contexts.

    \sa ICore::addAdditionalContext()
    \sa ICore::addContextObject()
*/

/*!
    \fn void ICore::addContextObject(IContext *context)
    \brief Registers an additional \a context object.

    After registration this context object gets automatically the
    current context object whenever it's widget gets focus.

    \sa ICore::removeContextObject()
    \sa ICore::addAdditionalContext()
    \sa ICore::currentContextObject()
*/

/*!
    \fn void ICore::removeContextObject(IContext *context)
    \brief Unregisters a \a context object from the list of know contexts.

    \sa ICore::addContextObject()
    \sa ICore::addAdditionalContext()
    \sa ICore::currentContextObject()
}
*/

/*!
    \fn void ICore::updateContext()
    \brief Update the list of active contexts after adding or removing additional ones.

    \sa ICore::addAdditionalContext()
    \sa ICore::removeAdditionalContext()
*/

/*!
    \fn void ICore::openFiles(const QStringList &fileNames)
    \brief Open all files from a list of \a fileNames like it would be
    done if they were given to Qt Creator on the command line, or
    they were opened via \gui{File|Open}.
*/

/*!
    \fn ICore::ICore()
    \internal
*/

/*!
    \fn ICore::~ICore()
    \internal
*/

/*!
    \fn void ICore::coreOpened()
    \brief Emitted after all plugins have been loaded and the main window shown.
*/

/*!
    \fn void ICore::saveSettingsRequested()
    \brief Emitted to signal that the user has requested that the global settings
    should be saved to disk.

    At the moment that happens when the application is closed, and on \gui{Save All}.
*/

/*!
    \fn void ICore::optionsDialogRequested()
    \brief Signal that allows plugins to perform actions just before the \gui{Tools|Options}
    dialog is shown.
*/

/*!
    \fn void ICore::coreAboutToClose()
    \brief Plugins can do some pre-end-of-life actions when they get this signal.

    The application is guaranteed to shut down after this signal is emitted.
    It's there as an addition to the usual plugin lifecycle methods, namely
    IPlugin::shutdown(), just for convenience.
*/

/*!
    \fn void ICore::contextAboutToChange(Core::IContext *context)
    \brief Sent just before a new \a context becomes the current context
    (meaning that it's widget got focus).
*/

/*!
    \fn void ICore::contextChanged(Core::IContext *context)
    \brief Sent just after a new \a context became the current context
    (meaning that it's widget got focus).
*/
<commit_msg>Fixes:    - License header<commit_after>/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/

#include "icore.h"

/*!
    \namespace Core
    \brief The Core namespace contains all classes that make up the Core plugin
    which constitute the basic functionality of Qt Creator.
*/

/*!
    \namespace Core::Internal
    \internal
*/

/*!
    \class Core::ICore
    \brief The ICore class allows access to the different part that make up
    the basic functionality of Qt Creator.

    You should never create a subclass of this interface. The one and only
    instance is created by the Core plugin. You can access this instance
    from your plugin via the plugin manager, e.g.
    \code
        ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
    \endcode

    \mainclass
*/

/*!
    \fn QStringList ICore::showNewItemDialog(const QString &title,
                                      const QList<IWizard *> &wizards,
                                      const QString &defaultLocation = QString())
    \brief Opens a dialog where the user can choose from a set of \a wizards that
    create new files/classes/projects.

    The \a title argument is shown as the dialogs title. The path where the
    files will be created (if the user doesn't change it) is set
    in \a defaultLocation. It defaults to the path of the file manager's
    current file.

    \sa Core::FileManager
*/

/*!
    \fn void ICore::showOptionsDialog(const QString &group = QString(),
                               const QString &page = QString())
    \brief Opens the application options/preferences dialog with preselected
    \a page in a specified \a group.

    The arguments refer to the string IDs of the corresponding IOptionsPage.
*/

/*!
    \fn ActionManager *ICore::actionManager() const
    \brief Returns the application's action manager.

    The action manager is responsible for registration of menus and
    menu items and keyboard shortcuts.
*/

/*!
    \fn FileManager *ICore::fileManager() const
    \brief Returns the application's file manager.

    The file manager keeps track of files for changes outside the application.
*/

/*!
    \fn UniqueIDManager *ICore::uniqueIDManager() const
    \brief Returns the application's id manager.

    The unique ID manager transforms strings in unique integers and the other way round.
*/

/*!
    \fn MessageManager *ICore::messageManager() const
    \brief Returns the application's message manager.

    The message manager is the interface to the "General" output pane for
    general application debug messages.
*/

/*!
    \fn ExtensionSystem::PluginManager *ICore::pluginManager() const
    \brief Returns the application's plugin manager.

    The plugin manager handles the plugin life cycles and manages
    the common object pool.
*/

/*!
    \fn EditorManager *ICore::editorManager() const
    \brief Returns the application's editor manager.

    The editor manager handles all editor related tasks like opening
    documents, the stack of currently open documents and the currently
    active document.
*/

/*!
    \fn ProgressManager *ICore::progressManager() const
    \brief Returns the application's progress manager.

    Use the progress manager to register a concurrent task to
    show a progress bar the way Qt Creator does it.
*/

/*!
    \fn ScriptManager *ICore::scriptManager() const
    \internal
*/

/*!
    \fn VariableManager *ICore::variableManager() const
    \brief Returns the application's variable manager.

    The variable manager is used to register application wide string variables
    like \c MY_PROJECT_DIR such that strings like \c{somecommand ${MY_PROJECT_DIR}/sub}
    can be resolved/expanded from anywhere in the application.
*/

/*!
    \fn VCSManager *ICore::vcsManager() const
    \brief Returns the application's vcs manager.

    The vcs manager can be used to e.g. retrieve information about
    the version control system used for a directory on hard disk.
    The actual functionality for a specific version control system
    must be implemented in a IVersionControl object and registered in
    the plugin manager's object pool.
*/

/*!
    \fn ModeManager *ICore::modeManager() const
    \brief Returns the application's mode manager.

    The mode manager handles everything related to the instances of IMode
    that were added to the plugin manager's object pool as well as their
    buttons and the tool bar with the round buttons in the lower left
    corner of Qt Creator.
*/

/*!
    \fn MimeDatabase *ICore::mimeDatabase() const
    \brief Returns the application's mime database.

    Use the mime database to manage mime types.
*/

/*!
    \fn QSettings *ICore::settings() const
    \brief Returns the application's main settings object.

    You can use it to retrieve or set application wide settings
    (in contrast to session or project specific settings).
*/

/*!
    \fn QPrinter *ICore::printer() const
    \brief Returns the application's printer object.

    Always use this printer object for printing, so the different parts of the
    application re-use it's settings.
*/

/*!
    \fn QString ICore::resourcePath() const
    \brief Returns the absolute path that is used for resources like
    project templates and the debugger macros.

    This abstraction is needed to avoid platform-specific code all over
    the place, since e.g. on Mac the resources are part of the application bundle.
*/

/*!
    \fn QMainWindow *ICore::mainWindow() const
    \brief Returns the main application window.

    For use as dialog parent etc.
*/

/*!
    \fn IContext *ICore::currentContextObject() const
    \brief Returns the context object of the current main context.

    \sa ICore::addAdditionalContext()
    \sa ICore::addContextObject()
*/

/*!
    \fn void ICore::addAdditionalContext(int context)
    \brief Register additional context to be currently active.

    Appends the additional \a context to the list of currently active
    contexts. You need to call ICore::updateContext to make that change
    take effect.

    \sa ICore::removeAdditionalContext()
    \sa ICore::hasContext()
    \sa ICore::updateContext()
*/

/*!
    \fn void ICore::removeAdditionalContext(int context)
    \brief Removes the given \a context from the list of currently active contexts.

    You need to call ICore::updateContext to make that change
    take effect.

    \sa ICore::addAdditionalContext()
    \sa ICore::hasContext()
    \sa ICore::updateContext()
*/

/*!
    \fn bool ICore::hasContext(int context) const
    \brief Returns if the given \a context is currently one of the active contexts.

    \sa ICore::addAdditionalContext()
    \sa ICore::addContextObject()
*/

/*!
    \fn void ICore::addContextObject(IContext *context)
    \brief Registers an additional \a context object.

    After registration this context object gets automatically the
    current context object whenever it's widget gets focus.

    \sa ICore::removeContextObject()
    \sa ICore::addAdditionalContext()
    \sa ICore::currentContextObject()
*/

/*!
    \fn void ICore::removeContextObject(IContext *context)
    \brief Unregisters a \a context object from the list of know contexts.

    \sa ICore::addContextObject()
    \sa ICore::addAdditionalContext()
    \sa ICore::currentContextObject()
}
*/

/*!
    \fn void ICore::updateContext()
    \brief Update the list of active contexts after adding or removing additional ones.

    \sa ICore::addAdditionalContext()
    \sa ICore::removeAdditionalContext()
*/

/*!
    \fn void ICore::openFiles(const QStringList &fileNames)
    \brief Open all files from a list of \a fileNames like it would be
    done if they were given to Qt Creator on the command line, or
    they were opened via \gui{File|Open}.
*/

/*!
    \fn ICore::ICore()
    \internal
*/

/*!
    \fn ICore::~ICore()
    \internal
*/

/*!
    \fn void ICore::coreOpened()
    \brief Emitted after all plugins have been loaded and the main window shown.
*/

/*!
    \fn void ICore::saveSettingsRequested()
    \brief Emitted to signal that the user has requested that the global settings
    should be saved to disk.

    At the moment that happens when the application is closed, and on \gui{Save All}.
*/

/*!
    \fn void ICore::optionsDialogRequested()
    \brief Signal that allows plugins to perform actions just before the \gui{Tools|Options}
    dialog is shown.
*/

/*!
    \fn void ICore::coreAboutToClose()
    \brief Plugins can do some pre-end-of-life actions when they get this signal.

    The application is guaranteed to shut down after this signal is emitted.
    It's there as an addition to the usual plugin lifecycle methods, namely
    IPlugin::shutdown(), just for convenience.
*/

/*!
    \fn void ICore::contextAboutToChange(Core::IContext *context)
    \brief Sent just before a new \a context becomes the current context
    (meaning that it's widget got focus).
*/

/*!
    \fn void ICore::contextChanged(Core::IContext *context)
    \brief Sent just after a new \a context became the current context
    (meaning that it's widget got focus).
*/
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: contentenumeration.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 15:09:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX
#define SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_UCB_XCOMMANDENVIRONMENT_HPP_
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XPERSIST_HPP_
#include <com/sun/star/io/XPersist.hpp>
#endif
/** === end UNO includes === **/

#ifndef _THREAD_HXX_
#include <osl/thread.hxx>
#endif
#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif
#ifndef _UCBHELPER_CONTENT_HXX
#include <ucbhelper/content.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _DATETIME_HXX
#include <tools/datetime.hxx>
#endif
#ifndef _SV_IMAGE_HXX
#include <vcl/image.hxx>
#endif

class IUrlFilter;
//........................................................................
namespace svt
{
//........................................................................

    //====================================================================
    //= SortingData_Impl
    //====================================================================
    struct SortingData_Impl
    {
    private:
        ::rtl::OUString maFilename;     // only filename in upper case - for compare purposes
        ::rtl::OUString maTitle;        //  -> be carefull when changing maTitle to update maFilename only when new
        ::rtl::OUString maLowerTitle;

    public:
        ::rtl::OUString maType;
        ::rtl::OUString maTargetURL;
        ::rtl::OUString maImageURL;
        ::rtl::OUString maDisplayText;
        DateTime        maModDate;
        Image           maImage;
        sal_Int64       maSize;
        sal_Bool        mbIsFolder;
        sal_Bool        mbIsVolume;
        sal_Bool        mbIsRemote;
        sal_Bool        mbIsRemoveable;
        sal_Bool        mbIsFloppy;
        sal_Bool        mbIsCompactDisc;

        inline                          SortingData_Impl();
        inline const ::rtl::OUString&   GetTitle() const;
        inline const ::rtl::OUString&   GetLowerTitle() const;
        inline const ::rtl::OUString&   GetFileName() const;
        inline void                     SetNewTitle( const ::rtl::OUString& rNewTitle );        // new maTitle is set -> maFilename is set to same!
        inline void                     ChangeTitle( const ::rtl::OUString& rChangedTitle );    // maTitle is changed, maFilename is unchanged!

    private:
        inline void                     SetTitles( const ::rtl::OUString& rNewTitle );
    };

    inline SortingData_Impl::SortingData_Impl() :
        maSize          ( 0 ),
        mbIsFolder      ( sal_False ),
        mbIsVolume      ( sal_False ),
        mbIsRemote      ( sal_False ),
        mbIsRemoveable  ( sal_False ),
        mbIsFloppy      ( sal_False ),
        mbIsCompactDisc ( sal_False )
    {
    }

    inline const ::rtl::OUString& SortingData_Impl::GetTitle() const
    {
        return maTitle;
    }

    inline const ::rtl::OUString& SortingData_Impl::GetLowerTitle() const
    {
        return maLowerTitle;
    }

    inline const ::rtl::OUString& SortingData_Impl::GetFileName() const
    {
        return maFilename;
    }

    inline void SortingData_Impl::SetNewTitle( const ::rtl::OUString& rNewTitle )
    {
        SetTitles( rNewTitle );
        maFilename = rNewTitle.toAsciiUpperCase();
    }

    inline void SortingData_Impl::ChangeTitle( const ::rtl::OUString& rChangedTitle )
    {
        SetTitles( rChangedTitle );
    }

    inline void SortingData_Impl::SetTitles( const ::rtl::OUString& rNewTitle )
    {
        maTitle = rNewTitle;
        maLowerTitle = rNewTitle.toAsciiLowerCase();
    }

    //====================================================================
    //= IContentTitleTranslation
    //====================================================================
    class IContentTitleTranslation
    {
    public:
        virtual sal_Bool    GetTranslation( const ::rtl::OUString& _rOriginalName, ::rtl::OUString& _rTranslatedName ) const = 0;
    };

    //====================================================================
    //= EnumerationResult
    //====================================================================
    enum EnumerationResult
    {
        SUCCESS,    /// the enumration was successfull
        ERROR,      /// the enumration was unsuccessfull
        RUNNING     /// the enumeration is still running, and the maximum wait time has passed
    };

    //====================================================================
    //= FolderDescriptor
    //====================================================================
    struct FolderDescriptor
    {
        /** a content object describing the folder. Can be <NULL/>, in this case <member>sURL</member>
            is relevant.
        */
        ::ucb::Content  aContent;
        /** the URL of a folder. Will be ignored if <member>aContent</member> is not <NULL/>.
        */
        String          sURL;

        FolderDescriptor() { }

        FolderDescriptor( const ::ucb::Content& _rContent )
            :aContent( _rContent )
        {
        }

        FolderDescriptor( const String& _rURL )
            :sURL( _rURL )
        {
        }
    };

    //====================================================================
    //= IEnumerationResultHandler
    //====================================================================
    class IEnumerationResultHandler
    {
    public:
        virtual void        enumerationDone( EnumerationResult _eResult ) = 0;
    };

    //====================================================================
    //= FileViewContentEnumerator
    //====================================================================
    class FileViewContentEnumerator
            :public  ::rtl::IReference
            ,private ::osl::Thread
    {
    public:
        typedef ::std::vector< SortingData_Impl* >  ContentData;

    private:
        ContentData&                    m_rContent;
        ::osl::Mutex&                   m_rContentMutex;

        oslInterlockedCount             m_refCount;
        mutable ::osl::Mutex            m_aMutex;

        FolderDescriptor                m_aFolder;
        ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >
                                        m_xCommandEnv;
        const IUrlFilter*               m_pFilter;
        const IContentTitleTranslation* m_pTranslator;
        IEnumerationResultHandler*      m_pResultHandler;
        bool                            m_bCancelled;

        mutable ::com::sun::star::uno::Reference< ::com::sun::star::io::XPersist >
                                        m_xDocInfo;

    public:
        /** constructs an enumerator instance

            @param _rContentToFill
                the structure which is to be filled with the found content
            @param _rContentMutex
                the mutex which protects the access to <arg>_rContentToFill</arg>
            @param _pTranslator
                an instance which should be used to translate content titles. May be <NULL/>
        */
        FileViewContentEnumerator(
            const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >& _rxCommandEnv,
            ContentData& _rContentToFill,
            ::osl::Mutex& _rContentMutex,
            const IContentTitleTranslation* _pTranslator
        );

        /** enumerates the content of a given folder

            @param _rFolder
                the folder whose content is to be enumerated
            @param _pFilter
                a filter to apply to the found contents
            @param _pResultHandler
                an instance which should handle the results of the enumeration
        */
        void    enumerateFolderContent(
                    const FolderDescriptor& _rFolder,
                    const IUrlFilter* _pFilter,
                    IEnumerationResultHandler* _pResultHandler
                );

        /** enumerates the content of a given folder synchronously
        */
        EnumerationResult   enumerateFolderContentSync(
                    const FolderDescriptor& _rFolder,
                    const IUrlFilter* _pFilter
                );

        /** cancels the running operation.

            Note that "cancel" may mean that the operation is running, but its result
            is simply disregarded later on.
        */
        void    cancel();

        // IReference overridables
        virtual oslInterlockedCount SAL_CALL acquire();
        virtual oslInterlockedCount SAL_CALL release();

        using Thread::operator new;
        using Thread::operator delete;

    protected:
        ~FileViewContentEnumerator();

    private:
        EnumerationResult enumerateFolderContent();

        // Thread overridables
        virtual void SAL_CALL run();
        virtual void SAL_CALL onTerminated();

    private:
        sal_Bool implGetDocTitle( const ::rtl::OUString& _rTargetURL, ::rtl::OUString& _rRet ) const;
    };

//........................................................................
} // namespace svt
//........................................................................

#endif // SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX

<commit_msg>INTEGRATION: CWS bgdlremove (1.4.168); FILE MERGED 2007/05/18 11:32:06 kso 1.4.168.1: #i77419# - cleanup of ucbhelper namespaces.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: contentenumeration.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: ihi $ $Date: 2007-06-05 18:24:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX
#define SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_UCB_XCOMMANDENVIRONMENT_HPP_
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XPERSIST_HPP_
#include <com/sun/star/io/XPersist.hpp>
#endif
/** === end UNO includes === **/

#ifndef _THREAD_HXX_
#include <osl/thread.hxx>
#endif
#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif
#ifndef _UCBHELPER_CONTENT_HXX
#include <ucbhelper/content.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _DATETIME_HXX
#include <tools/datetime.hxx>
#endif
#ifndef _SV_IMAGE_HXX
#include <vcl/image.hxx>
#endif

class IUrlFilter;
//........................................................................
namespace svt
{
//........................................................................

    //====================================================================
    //= SortingData_Impl
    //====================================================================
    struct SortingData_Impl
    {
    private:
        ::rtl::OUString maFilename;     // only filename in upper case - for compare purposes
        ::rtl::OUString maTitle;        //  -> be carefull when changing maTitle to update maFilename only when new
        ::rtl::OUString maLowerTitle;

    public:
        ::rtl::OUString maType;
        ::rtl::OUString maTargetURL;
        ::rtl::OUString maImageURL;
        ::rtl::OUString maDisplayText;
        DateTime        maModDate;
        Image           maImage;
        sal_Int64       maSize;
        sal_Bool        mbIsFolder;
        sal_Bool        mbIsVolume;
        sal_Bool        mbIsRemote;
        sal_Bool        mbIsRemoveable;
        sal_Bool        mbIsFloppy;
        sal_Bool        mbIsCompactDisc;

        inline                          SortingData_Impl();
        inline const ::rtl::OUString&   GetTitle() const;
        inline const ::rtl::OUString&   GetLowerTitle() const;
        inline const ::rtl::OUString&   GetFileName() const;
        inline void                     SetNewTitle( const ::rtl::OUString& rNewTitle );        // new maTitle is set -> maFilename is set to same!
        inline void                     ChangeTitle( const ::rtl::OUString& rChangedTitle );    // maTitle is changed, maFilename is unchanged!

    private:
        inline void                     SetTitles( const ::rtl::OUString& rNewTitle );
    };

    inline SortingData_Impl::SortingData_Impl() :
        maSize          ( 0 ),
        mbIsFolder      ( sal_False ),
        mbIsVolume      ( sal_False ),
        mbIsRemote      ( sal_False ),
        mbIsRemoveable  ( sal_False ),
        mbIsFloppy      ( sal_False ),
        mbIsCompactDisc ( sal_False )
    {
    }

    inline const ::rtl::OUString& SortingData_Impl::GetTitle() const
    {
        return maTitle;
    }

    inline const ::rtl::OUString& SortingData_Impl::GetLowerTitle() const
    {
        return maLowerTitle;
    }

    inline const ::rtl::OUString& SortingData_Impl::GetFileName() const
    {
        return maFilename;
    }

    inline void SortingData_Impl::SetNewTitle( const ::rtl::OUString& rNewTitle )
    {
        SetTitles( rNewTitle );
        maFilename = rNewTitle.toAsciiUpperCase();
    }

    inline void SortingData_Impl::ChangeTitle( const ::rtl::OUString& rChangedTitle )
    {
        SetTitles( rChangedTitle );
    }

    inline void SortingData_Impl::SetTitles( const ::rtl::OUString& rNewTitle )
    {
        maTitle = rNewTitle;
        maLowerTitle = rNewTitle.toAsciiLowerCase();
    }

    //====================================================================
    //= IContentTitleTranslation
    //====================================================================
    class IContentTitleTranslation
    {
    public:
        virtual sal_Bool    GetTranslation( const ::rtl::OUString& _rOriginalName, ::rtl::OUString& _rTranslatedName ) const = 0;
    };

    //====================================================================
    //= EnumerationResult
    //====================================================================
    enum EnumerationResult
    {
        SUCCESS,    /// the enumration was successfull
        ERROR,      /// the enumration was unsuccessfull
        RUNNING     /// the enumeration is still running, and the maximum wait time has passed
    };

    //====================================================================
    //= FolderDescriptor
    //====================================================================
    struct FolderDescriptor
    {
        /** a content object describing the folder. Can be <NULL/>, in this case <member>sURL</member>
            is relevant.
        */
        ::ucbhelper::Content  aContent;
        /** the URL of a folder. Will be ignored if <member>aContent</member> is not <NULL/>.
        */
        String          sURL;

        FolderDescriptor() { }

        FolderDescriptor( const ::ucbhelper::Content& _rContent )
            :aContent( _rContent )
        {
        }

        FolderDescriptor( const String& _rURL )
            :sURL( _rURL )
        {
        }
    };

    //====================================================================
    //= IEnumerationResultHandler
    //====================================================================
    class IEnumerationResultHandler
    {
    public:
        virtual void        enumerationDone( EnumerationResult _eResult ) = 0;
    };

    //====================================================================
    //= FileViewContentEnumerator
    //====================================================================
    class FileViewContentEnumerator
            :public  ::rtl::IReference
            ,private ::osl::Thread
    {
    public:
        typedef ::std::vector< SortingData_Impl* >  ContentData;

    private:
        ContentData&                    m_rContent;
        ::osl::Mutex&                   m_rContentMutex;

        oslInterlockedCount             m_refCount;
        mutable ::osl::Mutex            m_aMutex;

        FolderDescriptor                m_aFolder;
        ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >
                                        m_xCommandEnv;
        const IUrlFilter*               m_pFilter;
        const IContentTitleTranslation* m_pTranslator;
        IEnumerationResultHandler*      m_pResultHandler;
        bool                            m_bCancelled;

        mutable ::com::sun::star::uno::Reference< ::com::sun::star::io::XPersist >
                                        m_xDocInfo;

    public:
        /** constructs an enumerator instance

            @param _rContentToFill
                the structure which is to be filled with the found content
            @param _rContentMutex
                the mutex which protects the access to <arg>_rContentToFill</arg>
            @param _pTranslator
                an instance which should be used to translate content titles. May be <NULL/>
        */
        FileViewContentEnumerator(
            const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >& _rxCommandEnv,
            ContentData& _rContentToFill,
            ::osl::Mutex& _rContentMutex,
            const IContentTitleTranslation* _pTranslator
        );

        /** enumerates the content of a given folder

            @param _rFolder
                the folder whose content is to be enumerated
            @param _pFilter
                a filter to apply to the found contents
            @param _pResultHandler
                an instance which should handle the results of the enumeration
        */
        void    enumerateFolderContent(
                    const FolderDescriptor& _rFolder,
                    const IUrlFilter* _pFilter,
                    IEnumerationResultHandler* _pResultHandler
                );

        /** enumerates the content of a given folder synchronously
        */
        EnumerationResult   enumerateFolderContentSync(
                    const FolderDescriptor& _rFolder,
                    const IUrlFilter* _pFilter
                );

        /** cancels the running operation.

            Note that "cancel" may mean that the operation is running, but its result
            is simply disregarded later on.
        */
        void    cancel();

        // IReference overridables
        virtual oslInterlockedCount SAL_CALL acquire();
        virtual oslInterlockedCount SAL_CALL release();

        using Thread::operator new;
        using Thread::operator delete;

    protected:
        ~FileViewContentEnumerator();

    private:
        EnumerationResult enumerateFolderContent();

        // Thread overridables
        virtual void SAL_CALL run();
        virtual void SAL_CALL onTerminated();

    private:
        sal_Bool implGetDocTitle( const ::rtl::OUString& _rTargetURL, ::rtl::OUString& _rRet ) const;
    };

//........................................................................
} // namespace svt
//........................................................................

#endif // SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX

<|endoftext|>


<commit_before>#include <map>
#include <string>
#include <set>
#include <memory>
#include <utility>
#include <iostream>
#include <iomanip>
#include <uv.h>

#include "../log.h"
#include "../message.h"
#include "../helper/common.h"
#include "polling_iterator.h"
#include "directory_record.h"

using std::string;
using std::set;
using std::endl;
using std::hex;
using std::dec;
using std::ostream;
using std::move;
using std::shared_ptr;

struct FSReq {
  uv_fs_t req;

  ~FSReq() {
    uv_fs_req_cleanup(&req);
  }
};

ostream &operator<<(ostream &out, const uv_timespec_t &ts)
{
  return out
     << ts.tv_sec << "s "
     << ts.tv_nsec << "ns";
}

ostream &operator<<(ostream &out, const uv_stat_t &stat)
{
  out
    << "[ino=" << stat.st_ino
    << " size=" << stat.st_size
    << " mode=" << hex << stat.st_mode << dec << " (";
  if (stat.st_mode & S_IFDIR) out << " DIR";
  if (stat.st_mode & S_IFREG) out << " REG";
  if ((stat.st_mode & S_IFLNK) == S_IFLNK) out << " LNK";
  out
    << " ) atim=" << stat.st_atim
    << " mtim=" << stat.st_mtim
    << " birthtim=" << stat.st_birthtim
    << "]";
  return out;
}

ostream &operator<<(ostream &out, const FSReq &r)
{
  if (r.req.result < 0) {
    return out << "[" << uv_strerror(static_cast<int>(r.req.result)) << "]";
  }

  return out << r.req.statbuf;
}

inline bool ts_not_equal(const uv_timespec_t &left, const uv_timespec_t &right)
{
  return left.tv_sec != right.tv_sec || left.tv_nsec != right.tv_nsec;
}

inline EntryKind kind_from_stat(const uv_stat_t &st)
{
  if (st.st_mode & S_IFDIR) return KIND_DIRECTORY;
  if (st.st_mode & S_IFREG) return KIND_FILE;
  return KIND_UNKNOWN;
}

DirectoryRecord::DirectoryRecord(string &&name) :
  parent{nullptr},
  name{move(name)},
  populated{false}
{
  //
}

string DirectoryRecord::path() const
{
  return parent == nullptr ? name : path_join(parent->path(), name);
}

void DirectoryRecord::scan(BoundPollingIterator *it)
{
  FSReq scan_req;
  set<Entry> scanned_entries;

  string dir = path();
  int scan_err = uv_fs_scandir(nullptr, &scan_req.req, dir.c_str(), 0, nullptr);
  if (scan_err < 0) {
    LOGGER << "Unable to scan directory " << dir << ": " << uv_strerror(scan_err) << "." << endl;
    return;
  }

  uv_dirent_t dirent;
  int next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  while (next_err == 0) {
    string entry_name(dirent.name);

    EntryKind entry_kind = KIND_UNKNOWN;
    if (dirent.type == UV_DIRENT_FILE) entry_kind = KIND_FILE;
    if (dirent.type == UV_DIRENT_DIR) entry_kind = KIND_DIRECTORY;

    LOGGER
      << "scandir: "
      << entry_name
      << " kind: "
      << entry_kind
      << "." << endl;

    it->push_entry(string(entry_name), entry_kind);
    if (populated) scanned_entries.emplace(move(entry_name), entry_kind);

    next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  }

  if (next_err != UV_EOF) {
    LOGGER << "Unable to list entries in directory " << dir << ": " << uv_strerror(next_err) << "." << endl;
  } else {
    // Report entries that were present the last time we scanned this directory, but aren't included in this
    // scan.
    auto previous = entries.begin();
    while (previous != entries.end()) {
      const string &previous_entry_name = previous->first;
      const string previous_entry_path(path_join(dir, previous_entry_name));
      EntryKind previous_entry_kind = kind_from_stat(previous->second);
      Entry previous_entry(previous_entry_name, previous_entry_kind);
      Entry unknown_entry(previous_entry_name, KIND_UNKNOWN);

      if (scanned_entries.count(previous_entry) == 0 && scanned_entries.count(unknown_entry) == 0) {
        entry_deleted(it, previous_entry_path, previous_entry_kind);
        auto former = previous;
        ++previous;
        entries.erase(former);

        subdirectories.erase(previous_entry_name);
      } else {
        ++previous;
      }
    }
  }
}

void DirectoryRecord::entry(
  BoundPollingIterator *it,
  const string &entry_name,
  const string &entry_path,
  EntryKind scan_kind
) {
  FSReq lstat_req;
  EntryKind previous_kind = scan_kind;
  EntryKind current_kind = scan_kind;

  int lstat_err = uv_fs_lstat(nullptr, &lstat_req.req, entry_path.c_str(), nullptr);
  if (lstat_err != 0 && lstat_err != UV_ENOENT && lstat_err != UV_EACCES) {
    LOGGER << "Unable to stat " << entry_path << ": " << uv_strerror(lstat_err) << "." << endl;
  }

  auto previous = entries.find(entry_name);

  bool existed_before = previous != entries.end();
  bool exists_now = lstat_err == 0;

  if (existed_before) previous_kind = kind_from_stat(previous->second);
  if (exists_now) current_kind = kind_from_stat(lstat_req.req.statbuf);

  ostream &logline = LOGGER << entry_path << ":\n  ";
  if (existed_before) {
    logline << previous->second;
  } else {
    logline << "(missing)";
  }
  logline << "\n  ==>\n  "
    << lstat_req
    << endl;

  if (existed_before && exists_now) {
    // Modification or no change
    uv_stat_t &previous_stat = previous->second;
    uv_stat_t &current_stat = lstat_req.req.statbuf;

    // TODO consider modifications to mode or ownership bits?
    if (
      kinds_are_different(previous_kind, current_kind) ||
      previous_stat.st_ino != current_stat.st_ino
    ) {
      entry_deleted(it, entry_path, previous_kind);
      entry_created(it, entry_path, current_kind);
    } else if (
      previous_stat.st_mode != current_stat.st_mode ||
      previous_stat.st_size != current_stat.st_size ||
      ts_not_equal(previous_stat.st_mtim, current_stat.st_mtim) ||
      ts_not_equal(previous_stat.st_ctim, current_stat.st_ctim)
    ) {
      entry_modified(it, entry_path, current_kind);
    }

  } else if (existed_before && !exists_now) {
    // Deletion

    entry_deleted(it, entry_path, previous_kind);

  } else if (!existed_before && exists_now) {
    // Creation

    if (kinds_are_different(scan_kind, current_kind)) {
      // Entry was created as a file, deleted, then recreated as a directory between scan() and entry()
      // (or vice versa)
      entry_created(it, entry_path, scan_kind);
      entry_deleted(it, entry_path, scan_kind);
    }
    entry_created(it, entry_path, current_kind);

  } else if (!existed_before && !exists_now) {
    // Entry was deleted between scan() and entry().
    // Emit a deletion and creation event pair. Note that the kinds will likely both be KIND_UNKNOWN.

    entry_created(it, entry_path, previous_kind);
    entry_deleted(it, entry_path, current_kind);

  }

  // Update entries with the latest stat information
  if (existed_before) entries.erase(previous);
  if (exists_now) entries.emplace(entry_name, lstat_req.req.statbuf);

  // Update subdirectories if this is or was a subdirectory
  auto dir = subdirectories.find(entry_name);
  if (current_kind != KIND_DIRECTORY && current_kind != KIND_UNKNOWN && dir != subdirectories.end()) {
    subdirectories.erase(dir);
  }
  if (current_kind == KIND_DIRECTORY) {
    if (dir == subdirectories.end()) {
      shared_ptr<DirectoryRecord> subdir(new DirectoryRecord(this, entry_name));
      subdirectories.emplace(entry_name, subdir);
      it->push_directory(subdir);
    } else {
      it->push_directory(dir->second);
    }
  }
}

bool DirectoryRecord::all_populated()
{
  if (!populated) return false;

  for (auto &pair : subdirectories) {
    if (!pair.second->all_populated()) {
      return false;
    }
  }

  return true;
}

DirectoryRecord::DirectoryRecord(DirectoryRecord *parent, const string &name) :
  parent{parent},
  name(move(name)),
  populated{false}
{
  //
}

void DirectoryRecord::entry_deleted(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().deleted(string(entry_path), kind);
}

void DirectoryRecord::entry_created(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().created(string(entry_path), kind);
}

void DirectoryRecord::entry_modified(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().modified(string(entry_path), kind);
}
<commit_msg>Crank down the polling thread logging a tad<commit_after>#include <map>
#include <string>
#include <set>
#include <memory>
#include <utility>
#include <iostream>
#include <iomanip>
#include <uv.h>

#include "../log.h"
#include "../message.h"
#include "../helper/common.h"
#include "polling_iterator.h"
#include "directory_record.h"

using std::string;
using std::set;
using std::endl;
using std::hex;
using std::dec;
using std::ostream;
using std::move;
using std::shared_ptr;

struct FSReq {
  uv_fs_t req;

  ~FSReq() {
    uv_fs_req_cleanup(&req);
  }
};

ostream &operator<<(ostream &out, const uv_timespec_t &ts)
{
  return out
     << ts.tv_sec << "s "
     << ts.tv_nsec << "ns";
}

ostream &operator<<(ostream &out, const uv_stat_t &stat)
{
  out
    << "[ino=" << stat.st_ino
    << " size=" << stat.st_size
    << " mode=" << hex << stat.st_mode << dec << " (";
  if (stat.st_mode & S_IFDIR) out << " DIR";
  if (stat.st_mode & S_IFREG) out << " REG";
  if ((stat.st_mode & S_IFLNK) == S_IFLNK) out << " LNK";
  out
    << " ) atim=" << stat.st_atim
    << " mtim=" << stat.st_mtim
    << " birthtim=" << stat.st_birthtim
    << "]";
  return out;
}

ostream &operator<<(ostream &out, const FSReq &r)
{
  if (r.req.result < 0) {
    return out << "[" << uv_strerror(static_cast<int>(r.req.result)) << "]";
  }

  return out << r.req.statbuf;
}

inline bool ts_not_equal(const uv_timespec_t &left, const uv_timespec_t &right)
{
  return left.tv_sec != right.tv_sec || left.tv_nsec != right.tv_nsec;
}

inline EntryKind kind_from_stat(const uv_stat_t &st)
{
  if (st.st_mode & S_IFDIR) return KIND_DIRECTORY;
  if (st.st_mode & S_IFREG) return KIND_FILE;
  return KIND_UNKNOWN;
}

DirectoryRecord::DirectoryRecord(string &&name) :
  parent{nullptr},
  name{move(name)},
  populated{false}
{
  //
}

string DirectoryRecord::path() const
{
  return parent == nullptr ? name : path_join(parent->path(), name);
}

void DirectoryRecord::scan(BoundPollingIterator *it)
{
  FSReq scan_req;
  set<Entry> scanned_entries;

  string dir = path();
  int scan_err = uv_fs_scandir(nullptr, &scan_req.req, dir.c_str(), 0, nullptr);
  if (scan_err < 0) {
    LOGGER << "Unable to scan directory " << dir << ": " << uv_strerror(scan_err) << "." << endl;
    return;
  }

  uv_dirent_t dirent;
  int next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  while (next_err == 0) {
    string entry_name(dirent.name);

    EntryKind entry_kind = KIND_UNKNOWN;
    if (dirent.type == UV_DIRENT_FILE) entry_kind = KIND_FILE;
    if (dirent.type == UV_DIRENT_DIR) entry_kind = KIND_DIRECTORY;

    it->push_entry(string(entry_name), entry_kind);
    if (populated) scanned_entries.emplace(move(entry_name), entry_kind);

    next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  }

  if (next_err != UV_EOF) {
    LOGGER << "Unable to list entries in directory " << dir << ": " << uv_strerror(next_err) << "." << endl;
  } else {
    // Report entries that were present the last time we scanned this directory, but aren't included in this
    // scan.
    auto previous = entries.begin();
    while (previous != entries.end()) {
      const string &previous_entry_name = previous->first;
      const string previous_entry_path(path_join(dir, previous_entry_name));
      EntryKind previous_entry_kind = kind_from_stat(previous->second);
      Entry previous_entry(previous_entry_name, previous_entry_kind);
      Entry unknown_entry(previous_entry_name, KIND_UNKNOWN);

      if (scanned_entries.count(previous_entry) == 0 && scanned_entries.count(unknown_entry) == 0) {
        entry_deleted(it, previous_entry_path, previous_entry_kind);
        auto former = previous;
        ++previous;
        entries.erase(former);

        subdirectories.erase(previous_entry_name);
      } else {
        ++previous;
      }
    }
  }
}

void DirectoryRecord::entry(
  BoundPollingIterator *it,
  const string &entry_name,
  const string &entry_path,
  EntryKind scan_kind
) {
  FSReq lstat_req;
  EntryKind previous_kind = scan_kind;
  EntryKind current_kind = scan_kind;

  int lstat_err = uv_fs_lstat(nullptr, &lstat_req.req, entry_path.c_str(), nullptr);
  if (lstat_err != 0 && lstat_err != UV_ENOENT && lstat_err != UV_EACCES) {
    LOGGER << "Unable to stat " << entry_path << ": " << uv_strerror(lstat_err) << "." << endl;
  }

  auto previous = entries.find(entry_name);

  bool existed_before = previous != entries.end();
  bool exists_now = lstat_err == 0;

  if (existed_before) previous_kind = kind_from_stat(previous->second);
  if (exists_now) current_kind = kind_from_stat(lstat_req.req.statbuf);

  if (existed_before && exists_now) {
    // Modification or no change
    uv_stat_t &previous_stat = previous->second;
    uv_stat_t &current_stat = lstat_req.req.statbuf;

    // TODO consider modifications to mode or ownership bits?
    if (
      kinds_are_different(previous_kind, current_kind) ||
      previous_stat.st_ino != current_stat.st_ino
    ) {
      entry_deleted(it, entry_path, previous_kind);
      entry_created(it, entry_path, current_kind);
    } else if (
      previous_stat.st_mode != current_stat.st_mode ||
      previous_stat.st_size != current_stat.st_size ||
      ts_not_equal(previous_stat.st_mtim, current_stat.st_mtim) ||
      ts_not_equal(previous_stat.st_ctim, current_stat.st_ctim)
    ) {
      entry_modified(it, entry_path, current_kind);
    }

  } else if (existed_before && !exists_now) {
    // Deletion

    entry_deleted(it, entry_path, previous_kind);

  } else if (!existed_before && exists_now) {
    // Creation

    if (kinds_are_different(scan_kind, current_kind)) {
      // Entry was created as a file, deleted, then recreated as a directory between scan() and entry()
      // (or vice versa)
      entry_created(it, entry_path, scan_kind);
      entry_deleted(it, entry_path, scan_kind);
    }
    entry_created(it, entry_path, current_kind);

  } else if (!existed_before && !exists_now) {
    // Entry was deleted between scan() and entry().
    // Emit a deletion and creation event pair. Note that the kinds will likely both be KIND_UNKNOWN.

    entry_created(it, entry_path, previous_kind);
    entry_deleted(it, entry_path, current_kind);

  }

  // Update entries with the latest stat information
  if (existed_before) entries.erase(previous);
  if (exists_now) entries.emplace(entry_name, lstat_req.req.statbuf);

  // Update subdirectories if this is or was a subdirectory
  auto dir = subdirectories.find(entry_name);
  if (current_kind != KIND_DIRECTORY && current_kind != KIND_UNKNOWN && dir != subdirectories.end()) {
    subdirectories.erase(dir);
  }
  if (current_kind == KIND_DIRECTORY) {
    if (dir == subdirectories.end()) {
      shared_ptr<DirectoryRecord> subdir(new DirectoryRecord(this, entry_name));
      subdirectories.emplace(entry_name, subdir);
      it->push_directory(subdir);
    } else {
      it->push_directory(dir->second);
    }
  }
}

bool DirectoryRecord::all_populated()
{
  if (!populated) return false;

  for (auto &pair : subdirectories) {
    if (!pair.second->all_populated()) {
      return false;
    }
  }

  return true;
}

DirectoryRecord::DirectoryRecord(DirectoryRecord *parent, const string &name) :
  parent{parent},
  name(move(name)),
  populated{false}
{
  //
}

void DirectoryRecord::entry_deleted(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().deleted(string(entry_path), kind);
}

void DirectoryRecord::entry_created(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().created(string(entry_path), kind);
}

void DirectoryRecord::entry_modified(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().modified(string(entry_path), kind);
}
<|endoftext|>


<commit_before><commit_msg>CppunitTest_sw_docbookexport: -Werror,-Wunused-private-field<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTypes.h"

#if defined(SK_BUILD_FOR_WIN)

// Workaround for:
// http://connect.microsoft.com/VisualStudio/feedback/details/621653/
// http://crbug.com/225822
// In VS2010 both intsafe.h and stdint.h define the following without guards.
// SkTypes brought in windows.h and stdint.h and the following defines are
// not used by this file. However, they may be re-introduced by wincodec.h.
#undef INT8_MIN
#undef INT16_MIN
#undef INT32_MIN
#undef INT64_MIN
#undef INT8_MAX
#undef UINT8_MAX
#undef INT16_MAX
#undef UINT16_MAX
#undef INT32_MAX
#undef UINT32_MAX
#undef INT64_MAX
#undef UINT64_MAX

#include "SkAutoCoInitialize.h"
#include "SkAutoMalloc.h"
#include "SkBitmap.h"
#include "SkImageEncoderPriv.h"
#include "SkIStream.h"
#include "SkImageEncoder.h"
#include "SkStream.h"
#include "SkTScopedComPtr.h"
#include "SkTemplates.h"
#include "SkUnPreMultiply.h"
#include <wincodec.h>

//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
//Undo this #define if it has been done so that we link against the symbols
//we intended to link against on all SDKs.
#if defined(CLSID_WICImagingFactory)
#undef CLSID_WICImagingFactory
#endif

bool SkEncodeImageWithWIC(SkWStream* stream, const SkPixmap& pixmap,
                          SkEncodedImageFormat format, int quality) {
    GUID type;
    switch (format) {
        case SkEncodedImageFormat::kJPEG:
            type = GUID_ContainerFormatJpeg;
            break;
        case SkEncodedImageFormat::kPNG:
            type = GUID_ContainerFormatPng;
            break;
        default:
            return false;
    }
    SkBitmap bitmapOrig;
    if (!bitmapOrig.installPixels(pixmap)) {
        return false;
    }
    bitmapOrig.setImmutable();

    // First convert to BGRA if necessary.
    SkBitmap bitmap;
    if (!bitmap.tryAllocPixels(bitmapOrig.info().makeColorType(kBGRA_8888_SkColorType)) ||
        !bitmapOrig.readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), 0, 0))
    {
        return false;
    }

    // WIC expects unpremultiplied pixels.  Unpremultiply if necessary.
    if (kPremul_SkAlphaType == bitmap.alphaType()) {
        uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels());
        for (int y = 0; y < bitmap.height(); ++y) {
            for (int x = 0; x < bitmap.width(); ++x) {
                uint8_t* bytes = pixels + y * bitmap.rowBytes() + x * bitmap.bytesPerPixel();
                SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
                SkColor* dst = reinterpret_cast<SkColor*>(bytes);
                *dst = SkUnPreMultiply::PMColorToColor(*src);
            }
        }
    }

    // Finally, if we are performing a jpeg encode, we must convert to BGR.
    void* pixels = bitmap.getPixels();
    size_t rowBytes = bitmap.rowBytes();
    SkAutoMalloc pixelStorage;
    WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
    if (SkEncodedImageFormat::kJPEG == format) {
        formatDesired = GUID_WICPixelFormat24bppBGR;
        rowBytes = SkAlign4(bitmap.width() * 3);
        pixelStorage.reset(rowBytes * bitmap.height());
        for (int y = 0; y < bitmap.height(); y++) {
            uint8_t* dstRow = SkTAddOffset<uint8_t>(pixelStorage.get(), y * rowBytes);
            for (int x = 0; x < bitmap.width(); x++) {
                uint32_t bgra = *bitmap.getAddr32(x, y);
                dstRow[0] = (uint8_t) (bgra >>  0);
                dstRow[1] = (uint8_t) (bgra >>  8);
                dstRow[2] = (uint8_t) (bgra >> 16);
                dstRow += 3;
            }
        }

        pixels = pixelStorage.get();
    }

    //Initialize COM.
    SkAutoCoInitialize scopedCo;
    if (!scopedCo.succeeded()) {
        return false;
    }

    HRESULT hr = S_OK;

    //Create Windows Imaging Component ImagingFactory.
    SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
    if (SUCCEEDED(hr)) {
        hr = CoCreateInstance(
            CLSID_WICImagingFactory
            , nullptr
            , CLSCTX_INPROC_SERVER
            , IID_PPV_ARGS(&piImagingFactory)
        );
    }

    //Convert the SkWStream to an IStream.
    SkTScopedComPtr<IStream> piStream;
    if (SUCCEEDED(hr)) {
        hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
    }

    //Create an encode of the appropriate type.
    SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
    if (SUCCEEDED(hr)) {
        hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder);
    }

    if (SUCCEEDED(hr)) {
        hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
    }

    //Create a the frame.
    SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
    SkTScopedComPtr<IPropertyBag2> piPropertybag;
    if (SUCCEEDED(hr)) {
        hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
    }

    if (SUCCEEDED(hr)) {
        PROPBAG2 name;
        memset(&name, 0, sizeof(name));
        name.dwType = PROPBAG2_TYPE_DATA;
        name.vt = VT_R4;
        name.pstrName = const_cast<LPOLESTR>(L"ImageQuality");

        VARIANT value;
        VariantInit(&value);
        value.vt = VT_R4;
        value.fltVal = (FLOAT)(quality / 100.0);

        //Ignore result code.
        //  This returns E_FAIL if the named property is not in the bag.
        //TODO(bungeman) enumerate the properties,
        //  write and set hr iff property exists.
        piPropertybag->Write(1, &name, &value);
    }
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
    }

    //Set the size of the frame.
    const UINT width = bitmap.width();
    const UINT height = bitmap.height();
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->SetSize(width, height);
    }

    //Set the pixel format of the frame.  If native encoded format cannot match BGRA,
    //it will choose the closest pixel format that it supports.
    WICPixelFormatGUID formatGUID = formatDesired;
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
    }
    if (SUCCEEDED(hr)) {
        //Be sure the image format is the one requested.
        hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
    }

    //Write the pixels into the frame.
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->WritePixels(height,
                                              (UINT) rowBytes,
                                              (UINT) rowBytes * height,
                                              reinterpret_cast<BYTE*>(pixels));
    }

    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->Commit();
    }

    if (SUCCEEDED(hr)) {
        hr = piEncoder->Commit();
    }

    return SUCCEEDED(hr);
}

#endif // defined(SK_BUILD_FOR_WIN)
<commit_msg>try to remove workaround for VS 2010<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTypes.h"

#if defined(SK_BUILD_FOR_WIN)

#include "SkAutoCoInitialize.h"
#include "SkAutoMalloc.h"
#include "SkBitmap.h"
#include "SkImageEncoderPriv.h"
#include "SkIStream.h"
#include "SkImageEncoder.h"
#include "SkStream.h"
#include "SkTScopedComPtr.h"
#include "SkTemplates.h"
#include "SkUnPreMultiply.h"
#include <wincodec.h>

//All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
//In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
//but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
//Undo this #define if it has been done so that we link against the symbols
//we intended to link against on all SDKs.
#if defined(CLSID_WICImagingFactory)
#undef CLSID_WICImagingFactory
#endif

bool SkEncodeImageWithWIC(SkWStream* stream, const SkPixmap& pixmap,
                          SkEncodedImageFormat format, int quality) {
    GUID type;
    switch (format) {
        case SkEncodedImageFormat::kJPEG:
            type = GUID_ContainerFormatJpeg;
            break;
        case SkEncodedImageFormat::kPNG:
            type = GUID_ContainerFormatPng;
            break;
        default:
            return false;
    }
    SkBitmap bitmapOrig;
    if (!bitmapOrig.installPixels(pixmap)) {
        return false;
    }
    bitmapOrig.setImmutable();

    // First convert to BGRA if necessary.
    SkBitmap bitmap;
    if (!bitmap.tryAllocPixels(bitmapOrig.info().makeColorType(kBGRA_8888_SkColorType)) ||
        !bitmapOrig.readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), 0, 0))
    {
        return false;
    }

    // WIC expects unpremultiplied pixels.  Unpremultiply if necessary.
    if (kPremul_SkAlphaType == bitmap.alphaType()) {
        uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels());
        for (int y = 0; y < bitmap.height(); ++y) {
            for (int x = 0; x < bitmap.width(); ++x) {
                uint8_t* bytes = pixels + y * bitmap.rowBytes() + x * bitmap.bytesPerPixel();
                SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
                SkColor* dst = reinterpret_cast<SkColor*>(bytes);
                *dst = SkUnPreMultiply::PMColorToColor(*src);
            }
        }
    }

    // Finally, if we are performing a jpeg encode, we must convert to BGR.
    void* pixels = bitmap.getPixels();
    size_t rowBytes = bitmap.rowBytes();
    SkAutoMalloc pixelStorage;
    WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
    if (SkEncodedImageFormat::kJPEG == format) {
        formatDesired = GUID_WICPixelFormat24bppBGR;
        rowBytes = SkAlign4(bitmap.width() * 3);
        pixelStorage.reset(rowBytes * bitmap.height());
        for (int y = 0; y < bitmap.height(); y++) {
            uint8_t* dstRow = SkTAddOffset<uint8_t>(pixelStorage.get(), y * rowBytes);
            for (int x = 0; x < bitmap.width(); x++) {
                uint32_t bgra = *bitmap.getAddr32(x, y);
                dstRow[0] = (uint8_t) (bgra >>  0);
                dstRow[1] = (uint8_t) (bgra >>  8);
                dstRow[2] = (uint8_t) (bgra >> 16);
                dstRow += 3;
            }
        }

        pixels = pixelStorage.get();
    }

    //Initialize COM.
    SkAutoCoInitialize scopedCo;
    if (!scopedCo.succeeded()) {
        return false;
    }

    HRESULT hr = S_OK;

    //Create Windows Imaging Component ImagingFactory.
    SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
    if (SUCCEEDED(hr)) {
        hr = CoCreateInstance(
            CLSID_WICImagingFactory
            , nullptr
            , CLSCTX_INPROC_SERVER
            , IID_PPV_ARGS(&piImagingFactory)
        );
    }

    //Convert the SkWStream to an IStream.
    SkTScopedComPtr<IStream> piStream;
    if (SUCCEEDED(hr)) {
        hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
    }

    //Create an encode of the appropriate type.
    SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
    if (SUCCEEDED(hr)) {
        hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder);
    }

    if (SUCCEEDED(hr)) {
        hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
    }

    //Create a the frame.
    SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
    SkTScopedComPtr<IPropertyBag2> piPropertybag;
    if (SUCCEEDED(hr)) {
        hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
    }

    if (SUCCEEDED(hr)) {
        PROPBAG2 name;
        memset(&name, 0, sizeof(name));
        name.dwType = PROPBAG2_TYPE_DATA;
        name.vt = VT_R4;
        name.pstrName = const_cast<LPOLESTR>(L"ImageQuality");

        VARIANT value;
        VariantInit(&value);
        value.vt = VT_R4;
        value.fltVal = (FLOAT)(quality / 100.0);

        //Ignore result code.
        //  This returns E_FAIL if the named property is not in the bag.
        //TODO(bungeman) enumerate the properties,
        //  write and set hr iff property exists.
        piPropertybag->Write(1, &name, &value);
    }
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
    }

    //Set the size of the frame.
    const UINT width = bitmap.width();
    const UINT height = bitmap.height();
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->SetSize(width, height);
    }

    //Set the pixel format of the frame.  If native encoded format cannot match BGRA,
    //it will choose the closest pixel format that it supports.
    WICPixelFormatGUID formatGUID = formatDesired;
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
    }
    if (SUCCEEDED(hr)) {
        //Be sure the image format is the one requested.
        hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
    }

    //Write the pixels into the frame.
    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->WritePixels(height,
                                              (UINT) rowBytes,
                                              (UINT) rowBytes * height,
                                              reinterpret_cast<BYTE*>(pixels));
    }

    if (SUCCEEDED(hr)) {
        hr = piBitmapFrameEncode->Commit();
    }

    if (SUCCEEDED(hr)) {
        hr = piEncoder->Commit();
    }

    return SUCCEEDED(hr);
}

#endif // defined(SK_BUILD_FOR_WIN)
<|endoftext|>


<commit_before><commit_msg>ooxml export: w14:numForm element<commit_after><|endoftext|>