<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Michael Hackstein
////////////////////////////////////////////////////////////////////////////////

#include "PathEnumerator.h"
#include "VocBase/Traverser.h"

using DepthFirstEnumerator = arangodb::traverser::DepthFirstEnumerator;
using BreadthFirstEnumerator = arangodb::traverser::BreadthFirstEnumerator;
using Traverser = arangodb::traverser::Traverser;
using TraverserOptions = arangodb::traverser::TraverserOptions;

bool DepthFirstEnumerator::next() {
  if (_isFirst) {
    _isFirst = false;
    if (_opts->minDepth == 0) {
      return true;
    }
  }
  if (_enumeratedPath.vertices.empty()) {
    // We are done;
    return false;
  }

  size_t cursorId = 0;

  while (true) {
    if (_enumeratedPath.edges.size() < _opts->maxDepth) {
      // We are not done with this path, so
      // we reserve the cursor for next depth
      auto cursor = _opts->nextCursor(_enumeratedPath.vertices.back(),
                                      _enumeratedPath.edges.size());
      if (cursor != nullptr) {
        _edgeCursors.emplace(cursor);
      }
    } else {
      // This path is at the end. cut the last step
      _enumeratedPath.vertices.pop_back();
      _enumeratedPath.edges.pop_back();
    }

    while (!_edgeCursors.empty()) {
      TRI_ASSERT(_edgeCursors.size() == _enumeratedPath.edges.size() + 1);
      auto& cursor = _edgeCursors.top();
      if (cursor->next(_enumeratedPath.edges, cursorId)) {
        ++_traverser->_readDocuments;
        if (_opts->uniqueEdges == TraverserOptions::UniquenessLevel::GLOBAL) {
          if (_returnedEdges.find(_enumeratedPath.edges.back()) ==
              _returnedEdges.end()) {
            // Edge not yet visited. Mark and continue.
            _returnedEdges.emplace(_enumeratedPath.edges.back());
          } else {
            _traverser->_filteredPaths++;
            _enumeratedPath.edges.pop_back();
            continue;
          }
        }
        if (!_traverser->edgeMatchesConditions(_enumeratedPath.edges.back(),
                                               _enumeratedPath.vertices.back(),
                                               _enumeratedPath.edges.size() - 1,
                                               cursorId)) {
            // This edge does not pass the filtering
            _enumeratedPath.edges.pop_back();
            continue;
        }

        if (_opts->uniqueEdges == TraverserOptions::UniquenessLevel::PATH) {
          auto& e = _enumeratedPath.edges.back();
          bool foundOnce = false;
          for (auto const& it : _enumeratedPath.edges) {
            if (foundOnce) {
              foundOnce = false; // if we leave with foundOnce == false we found the edge earlier
              break;
            }
            if (it == e) {
              foundOnce = true;
            }
          }
          if (!foundOnce) {
            // We found it and it was not the last element (expected)
            // This edge is allready on the path
            _enumeratedPath.edges.pop_back();
            continue;
          }
        }

        // We have to check if edge and vertex is valid
        if (_traverser->getVertex(_enumeratedPath.edges.back(),
                                  _enumeratedPath.vertices)) {
          // case both are valid.
          if (_opts->uniqueVertices == TraverserOptions::UniquenessLevel::PATH) {
            auto& e = _enumeratedPath.vertices.back();
            bool foundOnce = false;
            for (auto const& it : _enumeratedPath.vertices) {
              if (foundOnce) {
                foundOnce = false;  // if we leave with foundOnce == false we
                                    // found the edge earlier
                break;
              }
              if (it == e) {
                foundOnce = true;
              }
            }
            if (!foundOnce) {
              // We found it and it was not the last element (expected)
              // This vertex is allready on the path
              _enumeratedPath.vertices.pop_back();
              _enumeratedPath.edges.pop_back();
              continue;
            }
          }
          if (_enumeratedPath.edges.size() < _opts->minDepth) {
            // Do not return, but leave this loop. Continue with the outer.
            break;
          }

          return true;
        }
        // Vertex Invalid. Revoke edge
        _enumeratedPath.edges.pop_back();
        continue;
      } else {
        // cursor is empty.
        _edgeCursors.pop();
        _enumeratedPath.edges.pop_back();
        _enumeratedPath.vertices.pop_back();
      }
    }
    if (_edgeCursors.empty()) {
      // If we get here all cursors are exhausted.
      _enumeratedPath.edges.clear();
      _enumeratedPath.vertices.clear();
      return false;
    }
  }
}

arangodb::aql::AqlValue DepthFirstEnumerator::lastVertexToAqlValue() {
  return _traverser->fetchVertexData(_enumeratedPath.vertices.back());
}

arangodb::aql::AqlValue DepthFirstEnumerator::lastEdgeToAqlValue() {
  if (_enumeratedPath.edges.empty()) {
    return arangodb::aql::AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
  }
  return _traverser->fetchEdgeData(_enumeratedPath.edges.back());
}

arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypack::Builder& result) {
  result.clear();
  result.openObject();
  result.add(VPackValue("edges"));
  result.openArray();
  for (auto const& it : _enumeratedPath.edges) {
    _traverser->addEdgeToVelocyPack(it, result);
  }
  result.close();
  result.add(VPackValue("vertices"));
  result.openArray();
  for (auto const& it : _enumeratedPath.vertices) {
    _traverser->addVertexToVelocyPack(it, result);
  }
  result.close();
  result.close();
  return arangodb::aql::AqlValue(result.slice());
}

BreadthFirstEnumerator::BreadthFirstEnumerator(Traverser* traverser,
                                               VPackSlice startVertex,
                                               TraverserOptions const* opts)
    : PathEnumerator(traverser, startVertex, opts),
      _schreierIndex(1),
      _lastReturned(0),
      _currentDepth(0),
      _toSearchPos(0) {
  _schreier.reserve(32);
  auto step = std::make_unique<PathStep>(startVertex);
  _schreier.emplace_back(step.get());
  step.release();

  _toSearch.emplace_back(NextStep(0));
}

bool BreadthFirstEnumerator::next() {
  if (_isFirst) {
    _isFirst = false;
    if (_opts->minDepth == 0) {
      computeEnumeratedPath(_lastReturned++);
      return true;
    }
    _lastReturned++;
  }

  if (_lastReturned < _schreierIndex) {
    // We still have something on our stack.
    // Paths have been read but not returned.
    computeEnumeratedPath(_lastReturned++);
    return true;
  }

  if (_opts->maxDepth == 0) {
    // Short circuit.
    // We cannot find any path of length 0 or less
    return false;
  }
  // Avoid large call stacks.
  // Loop will be left if we are either finished
  // with searching.
  // Or we found vertices in the next depth for
  // a vertex.
  while (true) {
    if (_toSearchPos >= _toSearch.size()) {
      // This depth is done. GoTo next
      if (_nextDepth.empty()) {
        // That's it. we are done.
        _enumeratedPath.edges.clear();
        _enumeratedPath.vertices.clear();
        return false;
      }
      // Save copies:
      // We clear current
      // we swap current and next.
      // So now current is filled
      // and next is empty.
      _toSearch.clear();
      _toSearchPos = 0;
      _toSearch.swap(_nextDepth);
      _currentDepth++;
      TRI_ASSERT(_toSearchPos < _toSearch.size());
      TRI_ASSERT(_nextDepth.empty());
      TRI_ASSERT(_currentDepth < _opts->maxDepth);
    }
    // This access is always safe.
    // If not it should have bailed out before.
    TRI_ASSERT(_toSearchPos < _toSearch.size());

    _tmpEdges.clear();
    auto const nextIdx = _toSearch[_toSearchPos++].sourceIdx;
    auto const& nextVertex = _schreier[nextIdx]->vertex;

    std::unique_ptr<arangodb::traverser::EdgeCursor> cursor(_opts->nextCursor(nextVertex, _currentDepth));
    if (cursor != nullptr) {
      size_t cursorIdx;
      bool shouldReturnPath = _currentDepth + 1 >= _opts->minDepth;
      bool didInsert = false;
      while (cursor->readAll(_tmpEdges, cursorIdx)) {
        if (!_tmpEdges.empty()) {
          _traverser->_readDocuments += _tmpEdges.size();
          VPackSlice v;
          for (auto const& e : _tmpEdges) {
            if (_opts->uniqueEdges ==
                TraverserOptions::UniquenessLevel::GLOBAL) {
              if (_returnedEdges.find(e) == _returnedEdges.end()) {
                // Edge not yet visited. Mark and continue.
                _returnedEdges.emplace(e);
              } else {
                _traverser->_filteredPaths++;
                continue;
              }
            }

            if (!_traverser->edgeMatchesConditions(e, nextVertex,
                                                   _currentDepth,
                                                   cursorIdx)) {
              continue;
            }
            if (_traverser->getSingleVertex(e, nextVertex, _currentDepth, v)) {
              auto step = std::make_unique<PathStep>(nextIdx, e, v);
              _schreier.emplace_back(step.get());
              step.release();
              if (_currentDepth < _opts->maxDepth - 1) {
                _nextDepth.emplace_back(NextStep(_schreierIndex));
              }
              _schreierIndex++;
              didInsert = true;
            }
          }
          _tmpEdges.clear();
        }
      }
      if (!shouldReturnPath) {
        _lastReturned = _schreierIndex;
        didInsert = false;
      }
      if (didInsert) {
        // We exit the loop here.
        // _schreierIndex is moved forward
        break;
      }
    }
    // Nothing found for this vertex.
    // _toSearchPos is increased so
    // we are not stuck in an endless loop
  }

  // _lastReturned points to the last used
  // entry. We compute the path to it
  // and increase the schreierIndex to point
  // to the next free position.
  computeEnumeratedPath(_lastReturned++);
  return true;
}

// TODO Optimize this. Remove enumeratedPath
// All can be read from schreier vector directly
arangodb::aql::AqlValue BreadthFirstEnumerator::lastVertexToAqlValue() {
  return _traverser->fetchVertexData(
      _enumeratedPath.vertices.back());
}

arangodb::aql::AqlValue BreadthFirstEnumerator::lastEdgeToAqlValue() {
  if (_enumeratedPath.edges.empty()) {
    return arangodb::aql::AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
  }
  return _traverser->fetchEdgeData(_enumeratedPath.edges.back());
}

arangodb::aql::AqlValue BreadthFirstEnumerator::pathToAqlValue(
    arangodb::velocypack::Builder& result) {
  result.clear();
  result.openObject();
  result.add(VPackValue("edges"));
  result.openArray();
  for (auto const& it : _enumeratedPath.edges) {
    _traverser->addEdgeToVelocyPack(it, result);
  }
  result.close();
  result.add(VPackValue("vertices"));
  result.openArray();
  for (auto const& it : _enumeratedPath.vertices) {
    _traverser->addVertexToVelocyPack(it, result);
  }
  result.close();
  result.close();
  return arangodb::aql::AqlValue(result.slice());
}

void BreadthFirstEnumerator::computeEnumeratedPath(size_t index) {
  TRI_ASSERT(index < _schreier.size());

  size_t depth = getDepth(index);
  _enumeratedPath.edges.clear();
  _enumeratedPath.vertices.clear();
  _enumeratedPath.edges.resize(depth);
  _enumeratedPath.vertices.resize(depth + 1);

  // Computed path. Insert it into the path enumerator.
  PathStep* current = nullptr;
  while (index != 0) {
    TRI_ASSERT(depth > 0);
    current = _schreier[index];
    _enumeratedPath.vertices[depth] = current->vertex;
    _enumeratedPath.edges[depth - 1] = current->edge;

    index = current->sourceIdx;
    --depth;
  }

  current = _schreier[0];
  _enumeratedPath.vertices[0] = current->vertex;
}

<commit_msg>Fixed undefined behaviour on Mac. An empty vector was popped.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Michael Hackstein
////////////////////////////////////////////////////////////////////////////////

#include "PathEnumerator.h"
#include "VocBase/Traverser.h"

using DepthFirstEnumerator = arangodb::traverser::DepthFirstEnumerator;
using BreadthFirstEnumerator = arangodb::traverser::BreadthFirstEnumerator;
using Traverser = arangodb::traverser::Traverser;
using TraverserOptions = arangodb::traverser::TraverserOptions;

bool DepthFirstEnumerator::next() {
  if (_isFirst) {
    _isFirst = false;
    if (_opts->minDepth == 0) {
      return true;
    }
  }
  if (_enumeratedPath.vertices.empty()) {
    // We are done;
    return false;
  }

  size_t cursorId = 0;

  while (true) {
    if (_enumeratedPath.edges.size() < _opts->maxDepth) {
      // We are not done with this path, so
      // we reserve the cursor for next depth
      auto cursor = _opts->nextCursor(_enumeratedPath.vertices.back(),
                                      _enumeratedPath.edges.size());
      if (cursor != nullptr) {
        _edgeCursors.emplace(cursor);
      }
    } else {
      TRI_ASSERT(!_enumeratedPath.edges.empty());
      // This path is at the end. cut the last step
      _enumeratedPath.vertices.pop_back();
      _enumeratedPath.edges.pop_back();
    }

    while (!_edgeCursors.empty()) {
      TRI_ASSERT(_edgeCursors.size() == _enumeratedPath.edges.size() + 1);
      auto& cursor = _edgeCursors.top();
      if (cursor->next(_enumeratedPath.edges, cursorId)) {
        ++_traverser->_readDocuments;
        if (_opts->uniqueEdges == TraverserOptions::UniquenessLevel::GLOBAL) {
          if (_returnedEdges.find(_enumeratedPath.edges.back()) ==
              _returnedEdges.end()) {
            // Edge not yet visited. Mark and continue.
            _returnedEdges.emplace(_enumeratedPath.edges.back());
          } else {
            _traverser->_filteredPaths++;
            TRI_ASSERT(!_enumeratedPath.edges.empty());
            _enumeratedPath.edges.pop_back();
            continue;
          }
        }
        if (!_traverser->edgeMatchesConditions(_enumeratedPath.edges.back(),
                                               _enumeratedPath.vertices.back(),
                                               _enumeratedPath.edges.size() - 1,
                                               cursorId)) {
            // This edge does not pass the filtering
            TRI_ASSERT(!_enumeratedPath.edges.empty());
            _enumeratedPath.edges.pop_back();
            continue;
        }

        if (_opts->uniqueEdges == TraverserOptions::UniquenessLevel::PATH) {
          auto& e = _enumeratedPath.edges.back();
          bool foundOnce = false;
          for (auto const& it : _enumeratedPath.edges) {
            if (foundOnce) {
              foundOnce = false; // if we leave with foundOnce == false we found the edge earlier
              break;
            }
            if (it == e) {
              foundOnce = true;
            }
          }
          if (!foundOnce) {
            // We found it and it was not the last element (expected)
            // This edge is allready on the path
            TRI_ASSERT(!_enumeratedPath.edges.empty());
            _enumeratedPath.edges.pop_back();
            continue;
          }
        }

        // We have to check if edge and vertex is valid
        if (_traverser->getVertex(_enumeratedPath.edges.back(),
                                  _enumeratedPath.vertices)) {
          // case both are valid.
          if (_opts->uniqueVertices == TraverserOptions::UniquenessLevel::PATH) {
            auto& e = _enumeratedPath.vertices.back();
            bool foundOnce = false;
            for (auto const& it : _enumeratedPath.vertices) {
              if (foundOnce) {
                foundOnce = false;  // if we leave with foundOnce == false we
                                    // found the edge earlier
                break;
              }
              if (it == e) {
                foundOnce = true;
              }
            }
            if (!foundOnce) {
              // We found it and it was not the last element (expected)
              // This vertex is allready on the path
              TRI_ASSERT(!_enumeratedPath.edges.empty());
              _enumeratedPath.vertices.pop_back();
              _enumeratedPath.edges.pop_back();
              continue;
            }
          }
          if (_enumeratedPath.edges.size() < _opts->minDepth) {
            // Do not return, but leave this loop. Continue with the outer.
            break;
          }

          return true;
        }
        // Vertex Invalid. Revoke edge
        TRI_ASSERT(!_enumeratedPath.edges.empty());
        _enumeratedPath.edges.pop_back();
        continue;
      } else {
        // cursor is empty.
        _edgeCursors.pop();
        if (!_enumeratedPath.edges.empty()) {
          _enumeratedPath.edges.pop_back();
          _enumeratedPath.vertices.pop_back();
        }
      }
    }
    if (_edgeCursors.empty()) {
      // If we get here all cursors are exhausted.
      _enumeratedPath.edges.clear();
      _enumeratedPath.vertices.clear();
      return false;
    }
  }
}

arangodb::aql::AqlValue DepthFirstEnumerator::lastVertexToAqlValue() {
  return _traverser->fetchVertexData(_enumeratedPath.vertices.back());
}

arangodb::aql::AqlValue DepthFirstEnumerator::lastEdgeToAqlValue() {
  if (_enumeratedPath.edges.empty()) {
    return arangodb::aql::AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
  }
  return _traverser->fetchEdgeData(_enumeratedPath.edges.back());
}

arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypack::Builder& result) {
  result.clear();
  result.openObject();
  result.add(VPackValue("edges"));
  result.openArray();
  for (auto const& it : _enumeratedPath.edges) {
    _traverser->addEdgeToVelocyPack(it, result);
  }
  result.close();
  result.add(VPackValue("vertices"));
  result.openArray();
  for (auto const& it : _enumeratedPath.vertices) {
    _traverser->addVertexToVelocyPack(it, result);
  }
  result.close();
  result.close();
  return arangodb::aql::AqlValue(result.slice());
}

BreadthFirstEnumerator::BreadthFirstEnumerator(Traverser* traverser,
                                               VPackSlice startVertex,
                                               TraverserOptions const* opts)
    : PathEnumerator(traverser, startVertex, opts),
      _schreierIndex(1),
      _lastReturned(0),
      _currentDepth(0),
      _toSearchPos(0) {
  _schreier.reserve(32);
  auto step = std::make_unique<PathStep>(startVertex);
  _schreier.emplace_back(step.get());
  step.release();

  _toSearch.emplace_back(NextStep(0));
}

bool BreadthFirstEnumerator::next() {
  if (_isFirst) {
    _isFirst = false;
    if (_opts->minDepth == 0) {
      computeEnumeratedPath(_lastReturned++);
      return true;
    }
    _lastReturned++;
  }

  if (_lastReturned < _schreierIndex) {
    // We still have something on our stack.
    // Paths have been read but not returned.
    computeEnumeratedPath(_lastReturned++);
    return true;
  }

  if (_opts->maxDepth == 0) {
    // Short circuit.
    // We cannot find any path of length 0 or less
    return false;
  }
  // Avoid large call stacks.
  // Loop will be left if we are either finished
  // with searching.
  // Or we found vertices in the next depth for
  // a vertex.
  while (true) {
    if (_toSearchPos >= _toSearch.size()) {
      // This depth is done. GoTo next
      if (_nextDepth.empty()) {
        // That's it. we are done.
        _enumeratedPath.edges.clear();
        _enumeratedPath.vertices.clear();
        return false;
      }
      // Save copies:
      // We clear current
      // we swap current and next.
      // So now current is filled
      // and next is empty.
      _toSearch.clear();
      _toSearchPos = 0;
      _toSearch.swap(_nextDepth);
      _currentDepth++;
      TRI_ASSERT(_toSearchPos < _toSearch.size());
      TRI_ASSERT(_nextDepth.empty());
      TRI_ASSERT(_currentDepth < _opts->maxDepth);
    }
    // This access is always safe.
    // If not it should have bailed out before.
    TRI_ASSERT(_toSearchPos < _toSearch.size());

    _tmpEdges.clear();
    auto const nextIdx = _toSearch[_toSearchPos++].sourceIdx;
    auto const& nextVertex = _schreier[nextIdx]->vertex;

    std::unique_ptr<arangodb::traverser::EdgeCursor> cursor(_opts->nextCursor(nextVertex, _currentDepth));
    if (cursor != nullptr) {
      size_t cursorIdx;
      bool shouldReturnPath = _currentDepth + 1 >= _opts->minDepth;
      bool didInsert = false;
      while (cursor->readAll(_tmpEdges, cursorIdx)) {
        if (!_tmpEdges.empty()) {
          _traverser->_readDocuments += _tmpEdges.size();
          VPackSlice v;
          for (auto const& e : _tmpEdges) {
            if (_opts->uniqueEdges ==
                TraverserOptions::UniquenessLevel::GLOBAL) {
              if (_returnedEdges.find(e) == _returnedEdges.end()) {
                // Edge not yet visited. Mark and continue.
                _returnedEdges.emplace(e);
              } else {
                _traverser->_filteredPaths++;
                continue;
              }
            }

            if (!_traverser->edgeMatchesConditions(e, nextVertex,
                                                   _currentDepth,
                                                   cursorIdx)) {
              continue;
            }
            if (_traverser->getSingleVertex(e, nextVertex, _currentDepth, v)) {
              auto step = std::make_unique<PathStep>(nextIdx, e, v);
              _schreier.emplace_back(step.get());
              step.release();
              if (_currentDepth < _opts->maxDepth - 1) {
                _nextDepth.emplace_back(NextStep(_schreierIndex));
              }
              _schreierIndex++;
              didInsert = true;
            }
          }
          _tmpEdges.clear();
        }
      }
      if (!shouldReturnPath) {
        _lastReturned = _schreierIndex;
        didInsert = false;
      }
      if (didInsert) {
        // We exit the loop here.
        // _schreierIndex is moved forward
        break;
      }
    }
    // Nothing found for this vertex.
    // _toSearchPos is increased so
    // we are not stuck in an endless loop
  }

  // _lastReturned points to the last used
  // entry. We compute the path to it
  // and increase the schreierIndex to point
  // to the next free position.
  computeEnumeratedPath(_lastReturned++);
  return true;
}

// TODO Optimize this. Remove enumeratedPath
// All can be read from schreier vector directly
arangodb::aql::AqlValue BreadthFirstEnumerator::lastVertexToAqlValue() {
  return _traverser->fetchVertexData(
      _enumeratedPath.vertices.back());
}

arangodb::aql::AqlValue BreadthFirstEnumerator::lastEdgeToAqlValue() {
  if (_enumeratedPath.edges.empty()) {
    return arangodb::aql::AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
  }
  return _traverser->fetchEdgeData(_enumeratedPath.edges.back());
}

arangodb::aql::AqlValue BreadthFirstEnumerator::pathToAqlValue(
    arangodb::velocypack::Builder& result) {
  result.clear();
  result.openObject();
  result.add(VPackValue("edges"));
  result.openArray();
  for (auto const& it : _enumeratedPath.edges) {
    _traverser->addEdgeToVelocyPack(it, result);
  }
  result.close();
  result.add(VPackValue("vertices"));
  result.openArray();
  for (auto const& it : _enumeratedPath.vertices) {
    _traverser->addVertexToVelocyPack(it, result);
  }
  result.close();
  result.close();
  return arangodb::aql::AqlValue(result.slice());
}

void BreadthFirstEnumerator::computeEnumeratedPath(size_t index) {
  TRI_ASSERT(index < _schreier.size());

  size_t depth = getDepth(index);
  _enumeratedPath.edges.clear();
  _enumeratedPath.vertices.clear();
  _enumeratedPath.edges.resize(depth);
  _enumeratedPath.vertices.resize(depth + 1);

  // Computed path. Insert it into the path enumerator.
  PathStep* current = nullptr;
  while (index != 0) {
    TRI_ASSERT(depth > 0);
    current = _schreier[index];
    _enumeratedPath.vertices[depth] = current->vertex;
    _enumeratedPath.edges[depth - 1] = current->edge;

    index = current->sourceIdx;
    --depth;
  }

  current = _schreier[0];
  _enumeratedPath.vertices[0] = current->vertex;
}

<|endoftext|>


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

#include "ppapi/tests/test_graphics_3d.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ppapi/c/dev/ppb_testing_dev.h"
#include "ppapi/c/ppb_opengles2.h"
#include "ppapi/cpp/graphics_3d.h"
#include "ppapi/cpp/module.h"
#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"

const int32_t kInvalidContext = 0;

REGISTER_TEST_CASE(Graphics3D);

bool TestGraphics3D::Init() {
  opengl_es2_ = static_cast<const PPB_OpenGLES2*>(
      pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_INTERFACE));
  glInitializePPAPI(pp::Module::Get()->get_browser_interface());
  return opengl_es2_ && CheckTestingInterface();
}

void TestGraphics3D::RunTests(const std::string& filter) {
  RUN_TEST(FramePPAPI, filter);
  RUN_TEST(FrameGL, filter);
  RUN_TEST(ExtensionsGL, filter);
}

std::string TestGraphics3D::TestFramePPAPI() {
  const int width = 16;
  const int height = 16;
  const int32_t attribs[] = {
      PP_GRAPHICS3DATTRIB_WIDTH, width,
      PP_GRAPHICS3DATTRIB_HEIGHT, height,
      PP_GRAPHICS3DATTRIB_NONE
  };
  pp::Graphics3D context(instance_, attribs);
  ASSERT_FALSE(context.is_null());

  const uint8_t red_color[4] = {255, 0, 0, 255};

  // Access OpenGLES API through the PPAPI interface.
  // Clear color buffer to opaque red.
  opengl_es2_->ClearColor(context.pp_resource(), 1.0f, 0.0f, 0.0f, 1.0f);
  opengl_es2_->Clear(context.pp_resource(), GL_COLOR_BUFFER_BIT);
  // Check if the color buffer has opaque red.
  std::string error = CheckPixelPPAPI(&context, width/2, height/2, red_color);
  if (!error.empty())
    return error;

  int32_t rv = SwapBuffersSync(&context);
  ASSERT_EQ(rv, PP_OK);

  PASS();
}

std::string TestGraphics3D::TestFrameGL() {
  const int width = 16;
  const int height = 16;
  const int32_t attribs[] = {
      PP_GRAPHICS3DATTRIB_WIDTH, width,
      PP_GRAPHICS3DATTRIB_HEIGHT, height,
      PP_GRAPHICS3DATTRIB_NONE
  };
  pp::Graphics3D context(instance_, attribs);
  ASSERT_FALSE(context.is_null());

  const uint8_t red_color[4] = {255, 0, 0, 255};
  // Perform same operations as TestFramePPAPI, but use OpenGLES API directly.
  // This is how most developers will use OpenGLES.
  glSetCurrentContextPPAPI(context.pp_resource());
  glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);
  std::string error = CheckPixelGL(width/2, height/2, red_color);
  glSetCurrentContextPPAPI(kInvalidContext);
  if (!error.empty())
    return error;

  int32_t rv = SwapBuffersSync(&context);
  ASSERT_EQ(rv, PP_OK);

  PASS();
}

std::string TestGraphics3D::TestExtensionsGL() {
  const int width = 16;
  const int height = 16;
  const int32_t attribs[] = {
      PP_GRAPHICS3DATTRIB_WIDTH, width,
      PP_GRAPHICS3DATTRIB_HEIGHT, height,
      PP_GRAPHICS3DATTRIB_NONE
  };
  pp::Graphics3D context(instance_, attribs);
  ASSERT_FALSE(context.is_null());

  glSetCurrentContextPPAPI(context.pp_resource());
  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);

  // Ask about a couple of extensions via glGetString.  If an extension is
  // available, try a couple of trivial calls.  This test is not intended
  // to be exhaustive; check the source can compile, link, and run without
  // crashing.
  ASSERT_NE(glGetString(GL_VERSION), NULL);
  const char* ext = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
  if (strstr(ext, "GL_EXT_occlusion_query_boolean")) {
    GLuint a_query;
    GLboolean is_a_query;
    glGenQueriesEXT(1, &a_query);
    ASSERT_NE(a_query, 0);
    glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, a_query);
    is_a_query = glIsQueryEXT(a_query);
    ASSERT_EQ(is_a_query, GL_TRUE);
    glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
    glDeleteQueriesEXT(1, &a_query);
  }
  if (strstr(ext, "GL_ANGLE_instanced_arrays")) {
    glDrawArraysInstancedANGLE(GL_TRIANGLE_STRIP, 0, 0, 0);
  }
  glSetCurrentContextPPAPI(kInvalidContext);

  int32_t rv = SwapBuffersSync(&context);
  ASSERT_EQ(rv, PP_OK);

  PASS();
}

int32_t TestGraphics3D::SwapBuffersSync(pp::Graphics3D* context) {
  TestCompletionCallback callback(instance_->pp_instance(), true);
  int32_t rv = context->SwapBuffers(callback);
  if (rv != PP_OK_COMPLETIONPENDING)
    return rv;

  return callback.WaitForResult();
}

std::string TestGraphics3D::CheckPixelPPAPI(
    pp::Graphics3D* context,
    int x, int y, const uint8_t expected_color[4]) {
  GLubyte pixel_color[4];
  opengl_es2_->ReadPixels(context->pp_resource(),
      x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);

  ASSERT_EQ(pixel_color[0], expected_color[0]);
  ASSERT_EQ(pixel_color[1], expected_color[1]);
  ASSERT_EQ(pixel_color[2], expected_color[2]);
  ASSERT_EQ(pixel_color[3], expected_color[3]);
  PASS();
}

std::string TestGraphics3D::CheckPixelGL(
    int x, int y, const uint8_t expected_color[4]) {
  GLubyte pixel_color[4];
  glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);

  ASSERT_EQ(pixel_color[0], expected_color[0]);
  ASSERT_EQ(pixel_color[1], expected_color[1]);
  ASSERT_EQ(pixel_color[2], expected_color[2]);
  ASSERT_EQ(pixel_color[3], expected_color[3]);
  PASS();
}

<commit_msg>Also run 3D tests on background thread.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/tests/test_graphics_3d.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ppapi/c/dev/ppb_testing_dev.h"
#include "ppapi/c/ppb_opengles2.h"
#include "ppapi/cpp/graphics_3d.h"
#include "ppapi/cpp/module.h"
#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
#include "ppapi/tests/test_case.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"

const int32_t kInvalidContext = 0;

REGISTER_TEST_CASE(Graphics3D);

bool TestGraphics3D::Init() {
  opengl_es2_ = static_cast<const PPB_OpenGLES2*>(
      pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_INTERFACE));
  glInitializePPAPI(pp::Module::Get()->get_browser_interface());
  return opengl_es2_ && CheckTestingInterface();
}

void TestGraphics3D::RunTests(const std::string& filter) {
  RUN_CALLBACK_TEST(TestGraphics3D, FramePPAPI, filter);
  RUN_CALLBACK_TEST(TestGraphics3D, FrameGL, filter);
  RUN_CALLBACK_TEST(TestGraphics3D, ExtensionsGL, filter);
}

std::string TestGraphics3D::TestFramePPAPI() {
  const int width = 16;
  const int height = 16;
  const int32_t attribs[] = {
      PP_GRAPHICS3DATTRIB_WIDTH, width,
      PP_GRAPHICS3DATTRIB_HEIGHT, height,
      PP_GRAPHICS3DATTRIB_NONE
  };
  pp::Graphics3D context(instance_, attribs);
  ASSERT_FALSE(context.is_null());

  const uint8_t red_color[4] = {255, 0, 0, 255};

  // Access OpenGLES API through the PPAPI interface.
  // Clear color buffer to opaque red.
  opengl_es2_->ClearColor(context.pp_resource(), 1.0f, 0.0f, 0.0f, 1.0f);
  opengl_es2_->Clear(context.pp_resource(), GL_COLOR_BUFFER_BIT);
  // Check if the color buffer has opaque red.
  std::string error = CheckPixelPPAPI(&context, width/2, height/2, red_color);
  if (!error.empty())
    return error;

  int32_t rv = SwapBuffersSync(&context);
  ASSERT_EQ(rv, PP_OK);

  PASS();
}

std::string TestGraphics3D::TestFrameGL() {
  const int width = 16;
  const int height = 16;
  const int32_t attribs[] = {
      PP_GRAPHICS3DATTRIB_WIDTH, width,
      PP_GRAPHICS3DATTRIB_HEIGHT, height,
      PP_GRAPHICS3DATTRIB_NONE
  };
  pp::Graphics3D context(instance_, attribs);
  ASSERT_FALSE(context.is_null());

  const uint8_t red_color[4] = {255, 0, 0, 255};
  // Perform same operations as TestFramePPAPI, but use OpenGLES API directly.
  // This is how most developers will use OpenGLES.
  glSetCurrentContextPPAPI(context.pp_resource());
  glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);
  std::string error = CheckPixelGL(width/2, height/2, red_color);
  glSetCurrentContextPPAPI(kInvalidContext);
  if (!error.empty())
    return error;

  int32_t rv = SwapBuffersSync(&context);
  ASSERT_EQ(rv, PP_OK);

  PASS();
}

std::string TestGraphics3D::TestExtensionsGL() {
  const int width = 16;
  const int height = 16;
  const int32_t attribs[] = {
      PP_GRAPHICS3DATTRIB_WIDTH, width,
      PP_GRAPHICS3DATTRIB_HEIGHT, height,
      PP_GRAPHICS3DATTRIB_NONE
  };
  pp::Graphics3D context(instance_, attribs);
  ASSERT_FALSE(context.is_null());

  glSetCurrentContextPPAPI(context.pp_resource());
  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);

  // Ask about a couple of extensions via glGetString.  If an extension is
  // available, try a couple of trivial calls.  This test is not intended
  // to be exhaustive; check the source can compile, link, and run without
  // crashing.
  ASSERT_NE(glGetString(GL_VERSION), NULL);
  const char* ext = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
  if (strstr(ext, "GL_EXT_occlusion_query_boolean")) {
    GLuint a_query;
    GLboolean is_a_query;
    glGenQueriesEXT(1, &a_query);
    ASSERT_NE(a_query, 0);
    glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, a_query);
    is_a_query = glIsQueryEXT(a_query);
    ASSERT_EQ(is_a_query, GL_TRUE);
    glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
    glDeleteQueriesEXT(1, &a_query);
  }
  if (strstr(ext, "GL_ANGLE_instanced_arrays")) {
    glDrawArraysInstancedANGLE(GL_TRIANGLE_STRIP, 0, 0, 0);
  }
  glSetCurrentContextPPAPI(kInvalidContext);

  int32_t rv = SwapBuffersSync(&context);
  ASSERT_EQ(rv, PP_OK);

  PASS();
}

int32_t TestGraphics3D::SwapBuffersSync(pp::Graphics3D* context) {
  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  int32_t rv = context->SwapBuffers(callback);
  if (rv != PP_OK_COMPLETIONPENDING)
    return rv;

  return callback.WaitForResult();
}

std::string TestGraphics3D::CheckPixelPPAPI(
    pp::Graphics3D* context,
    int x, int y, const uint8_t expected_color[4]) {
  GLubyte pixel_color[4];
  opengl_es2_->ReadPixels(context->pp_resource(),
      x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);

  ASSERT_EQ(pixel_color[0], expected_color[0]);
  ASSERT_EQ(pixel_color[1], expected_color[1]);
  ASSERT_EQ(pixel_color[2], expected_color[2]);
  ASSERT_EQ(pixel_color[3], expected_color[3]);
  PASS();
}

std::string TestGraphics3D::CheckPixelGL(
    int x, int y, const uint8_t expected_color[4]) {
  GLubyte pixel_color[4];
  glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);

  ASSERT_EQ(pixel_color[0], expected_color[0]);
  ASSERT_EQ(pixel_color[1], expected_color[1]);
  ASSERT_EQ(pixel_color[2], expected_color[2]);
  ASSERT_EQ(pixel_color[3], expected_color[3]);
  PASS();
}

<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2016 Michael Fink
//
/// \file CanonControlLuaBindings.hpp Lua bindings for the CanonControl library
//
#pragma once

// includes
#include "Lua.hpp"
#include "Instance.hpp"
#include "RecursiveMutex.hpp"
#include "Event.hpp"
#include "Asio.hpp"
#include "ShutterReleaseSettings.hpp"
#include "RemoteReleaseControl.hpp"

// forward references
class SourceDevice;
class SourceInfo;
class DeviceProperty;
class ImageProperty;
class Viewfinder;
class BulbReleaseControl;

/// \brief Lua bindings for CanonControl library
/// \details Provides bindings for all classes and functions in the CanonControl
/// library. As soon as the object is destroyed, the bindings are deregistered. All
/// callback handlers registered are reset and won't be called anymore.
class CanonControlLuaBindings : public std::enable_shared_from_this<CanonControlLuaBindings>
{
public:
   /// function type to output debug strings
   typedef std::function<void(const CString&)> T_fnOutputDebugString;

   /// ctor; inits bindings
   CanonControlLuaBindings(Lua::State& state, boost::asio::io_service::strand& strand);

   /// dtor; cleans up bindings
   virtual ~CanonControlLuaBindings() throw();

   /// sets output debug string handler
   void SetOutputDebugStringHandler(T_fnOutputDebugString fnOutputDebugString)
   {
      m_fnOutputDebugString = fnOutputDebugString;
   }

   /// inits bindings to CanonControl; since the this parameter is needed in
   /// the bindings, call this immediately after the ctor
   void InitBindings();

   /// cancels all handlers of async operations
   void CancelHandlers();

   /// stops internal timer
   void StopTimer();

private:
   /// returns Lua state object
   Lua::State& GetState() throw() { return m_state; }

   /// inits constants used in various calls
   void InitConstants();

   /// inits constants for SourceDevice table
   void InitSourceDeviceConstants(Lua::Table& constants);

   /// inits constants for ImageProperty table
   void InitImagePropertyConstants(Lua::Table& constants);

   /// inits constants for ShootingMode table
   void InitShootingModeConstants(Lua::Table& constants);

   /// inits constants for ShutterReleaseSettings table
   void InitShutterReleaseSettingsConstants(Lua::Table& constants);

   /// inits constants for RemoteReleaseControl
   void InitRemoteReleaseControlConstants(Lua::Table& constants);

   /// inits constants for Viewfinder
   void InitViewfinderConstants(Lua::Table& constants);

   /// restarts timer for event handling
   void RestartEventTimer();

   /// cleans up all bindings
   void CleanupBindings();

   /// handler for timer used for event handling
   void OnTimerEventHandling(const boost::system::error_code& error);

   // Sys functions

   /// local instance = Sys:getInstance()
   std::vector<Lua::Value> SysGetInstance(Lua::State& state);

   // Instance functions

   /// local version = Instance:getVersion()
   std::vector<Lua::Value> InstanceGetVersion();

   /// local sourceInfoArray = instance:enumerateDevices()
   std::vector<Lua::Value> InstanceEnumerateDevices(Lua::State& state);

   /// instance:asyncWaitForCamera(callbackFunction)
   std::vector<Lua::Value> InstanceAsyncWaitForCamera(Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// method called when a camera has been connected
   void AsyncWaitForCamera_OnCameraConnected();

   // SourceInfo functions

   /// adds a source info table to given table
   /// { name = "camera name", function open() ... end }
   void AddSourceInfo(Lua::State& state, Lua::Table& table, size_t uiIndex, std::shared_ptr<SourceInfo> spSourceInfo);

   /// local sourceDevice = sourceInfo:open()
   std::vector<Lua::Value> SourceInfoOpen(std::shared_ptr<SourceInfo> spSourceInfo,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   // SourceDevice functions

   /// initializes SourceDevice table
   void InitSourceDeviceTable(std::shared_ptr<SourceDevice> spSourceDevice, Lua::Table& sourceDevice);

   /// local isCapable = sourceDevice:getDeviceCapability(Constants.SourceDevice.capXxx)
   std::vector<Lua::Value> SourceDeviceGetDeviceCapability(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// local arrayDeviceProps = sourceDevice:enumDeviceProperties()
   std::vector<Lua::Value> SourceDeviceEnumDeviceProperties(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state);

   /// local deviceProperty = sourceDevice:getDeviceProperty()
   std::vector<Lua::Value> SourceDeviceGetDeviceProperty(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// adds a device property values to given table
   /// { id = "property id", name = "name", asString = "value", isReadOnly = true/false end }
   void AddDeviceProperty(Lua::Table& table, const DeviceProperty& deviceProperty, std::shared_ptr<SourceDevice> spSourceDevice);

   /// enters release control and returns RemoteReleaseControl table
   std::vector<Lua::Value> SourceDeviceEnterReleaseControl(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state);

   // RemoteReleaseControl functions

   /// initializes RemoteReleaseControl table
   void InitRemoteReleaseControlTable(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::Table& remoteReleaseControl);

   /// local capability = remoteReleaseControl:getCapability()
   std::vector<Lua::Value> RemoteReleaseControlGetCapability(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// local releaseSettings = remoteReleaseControl:getReleaseSettings()
   std::vector<Lua::Value> RemoteReleaseControlGetReleaseSettings(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// initializes ReleaseSettings table
   void InitReleaseSettingsTable(Lua::State& state, const ShutterReleaseSettings& releaseSettings,
      Lua::Table& tableReleaseSettings);

   /// sets new release settings
   std::vector<Lua::Value> RemoteReleaseControlSetReleaseSettings(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// callback that is called when image has been transferred
   void SetReleaseSettings_OnFinishedTransfer(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      const ShutterReleaseSettings& releaseSettings);

   void RemoteReleaseControl_PropertyEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      std::shared_ptr<int> spHandlerId,
      RemoteReleaseControl::T_enPropertyEvent,
      unsigned int eventData);

   /// local handlerId = remoteReleaseControl:addPropertyEventHandler(callbackFunction)
   std::vector<Lua::Value> RemoteReleaseControlAddPropertyEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:removePropertyEventHandler(handlerId)
   std::vector<Lua::Value> RemoteReleaseControlRemovePropertyEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   void RemoteReleaseControl_StateEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      std::shared_ptr<int> spHandlerId,
      RemoteReleaseControl::T_enStateEvent,
      unsigned int eventData);

   /// local handlerId = remoteReleaseControl:addStateEventHandler(callbackFunction)
   std::vector<Lua::Value> RemoteReleaseControlAddStateEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:removeStateEventHandler(handlerId)
   std::vector<Lua::Value> RemoteReleaseControlRemoveStateEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   void RemoteReleaseControl_DownloadEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      std::shared_ptr<int> spHandlerId,
      RemoteReleaseControl::T_enDownloadEvent,
      unsigned int eventData);

   /// local handlerId = remoteReleaseControl:addDownloadEventHandler(callbackFunction)
   std::vector<Lua::Value> RemoteReleaseControlAddDownloadEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:removeDownloadEventHandler(handlerId)
   std::vector<Lua::Value> RemoteReleaseControlRemoveDownloadEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// local imagePropertiesList = remoteReleaseControl:enumImageProperties()
   std::vector<Lua::Value> RemoteReleaseControlEnumImageProperties(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::State& state);

   /// local imageProperty = remoteReleaseControl:getImageProperty()
   std::vector<Lua::Value> RemoteReleaseControlGetImageProperty(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// local imageProperty = remoteReleaseControl:getImagePropertyByType(imagePropertyType)
   std::vector<Lua::Value> RemoteReleaseControlGetImagePropertyByType(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// local imageProperty = remoteReleaseControl:getShootingModeImageProperty(shootingMode)
   std::vector<Lua::Value> RemoteReleaseControlGetShootingModeImageProperty(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// adds ImageProperty table
   void AddImageProperty(Lua::Table& table, const ImageProperty& imageProperty,
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   /// local viewfinder = remoteReleaseControl:startViewfinder()
   std::vector<Lua::Value> RemoteReleaseControlStartViewfinder(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::State& state);

   /// local numShots = remoteReleaseControl:numAvailableShots()
   std::vector<Lua::Value> RemoteReleaseControlNumAvailableShots(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   /// remoteReleaseControl:sendCommand()
   std::vector<Lua::Value> RemoteReleaseControlSendCommand(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:release()
   std::vector<Lua::Value> RemoteReleaseControlRelease(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   /// local bulbReleaseControl = remoteReleaseControl:startBulb()
   std::vector<Lua::Value> RemoteReleaseControlStartBulb(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::State& state);

   /// local remoteReleaseControl:close()
   std::vector<Lua::Value> RemoteReleaseControlClose(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   // Viewfinder functions

   /// initializes viewfinder table
   void InitViewfinderTable(std::shared_ptr<Viewfinder> spViewfinder, Lua::Table& viewfinder);

   /// viewfinder:setOutputType(outputType)
   std::vector<Lua::Value> ViewfinderSetOutputType(std::shared_ptr<Viewfinder> spViewfinder,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// viewfinder:setAvailImageHandler(callbackFunction)
   std::vector<Lua::Value> ViewfinderSetAvailImageHandler(std::shared_ptr<Viewfinder> spViewfinder,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// called when a new viewfinder image is available
   void SetAvailImageHandler_OnAvailImageHandler(std::shared_ptr<Viewfinder> spViewfinder,
      const std::vector<BYTE>& vecImage);

   /// called to close viewfinder
   std::vector<Lua::Value> ViewfinderClose(std::shared_ptr<Viewfinder> spViewfinder,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   // BulbReleaseControl functions

   /// initizalizes BulbReleaseControl table
   void InitBulbReleaseControlTable(std::shared_ptr<BulbReleaseControl> spBulbReleaseControl, Lua::Table& bulbReleaseControl);

   /// local elapsedTime = bulbReleaseControl:elapsedTime()
   std::vector<Lua::Value> BulbReleaseControlElapsedTime(std::shared_ptr<BulbReleaseControl> spBulbReleaseControl);

   /// bulbReleaseControl:stop()
   std::vector<Lua::Value> BulbReleaseControlStop(std::shared_ptr<BulbReleaseControl> spBulbReleaseControl);

private:
   /// Lua state
   Lua::State& m_state;

   /// CanonControl instance
   std::unique_ptr<Instance> m_upInstance;

   /// release settings stored for the script
   ShutterReleaseSettings m_releaseSettings;

   /// once Lua has connected to remote release control, a pointer is stored here
   std::shared_ptr<RemoteReleaseControl> m_spRemoteRelaseControl;

   /// set of all registered property handler ids
   std::set<int> m_setAllPropertyHandlerIds;

   /// set of all registered state handler ids
   std::set<int> m_setAllStateHandlerIds;

   /// set of all registered download handler ids
   std::set<int> m_setAllDownloadHandlerIds;

   /// once Lua script started viewfinder, a pointer is stored here
   std::shared_ptr<Viewfinder> m_spViewfinder;

   /// strand to execute all Lua calls on
   boost::asio::io_service::strand& m_strand;

   /// output debug string handler
   T_fnOutputDebugString m_fnOutputDebugString;

   /// mutex to protect AsyncWaitForCamera() handler to call Lua script multiple times
   RecursiveMutex m_mtxAsyncWaitForCamera_InScript;

   /// timer for event handling
   boost::asio::deadline_timer m_timerEventHandling;

   /// event that is set when the event handling timer has stopped
   Event m_evtTimerStopped;
};
<commit_msg>added doxygen comments<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2016 Michael Fink
//
/// \file CanonControlLuaBindings.hpp Lua bindings for the CanonControl library
//
#pragma once

// includes
#include "Lua.hpp"
#include "Instance.hpp"
#include "RecursiveMutex.hpp"
#include "Event.hpp"
#include "Asio.hpp"
#include "ShutterReleaseSettings.hpp"
#include "RemoteReleaseControl.hpp"

// forward references
class SourceDevice;
class SourceInfo;
class DeviceProperty;
class ImageProperty;
class Viewfinder;
class BulbReleaseControl;

/// \brief Lua bindings for CanonControl library
/// \details Provides bindings for all classes and functions in the CanonControl
/// library. As soon as the object is destroyed, the bindings are deregistered. All
/// callback handlers registered are reset and won't be called anymore.
class CanonControlLuaBindings : public std::enable_shared_from_this<CanonControlLuaBindings>
{
public:
   /// function type to output debug strings
   typedef std::function<void(const CString&)> T_fnOutputDebugString;

   /// ctor; inits bindings
   CanonControlLuaBindings(Lua::State& state, boost::asio::io_service::strand& strand);

   /// dtor; cleans up bindings
   virtual ~CanonControlLuaBindings() throw();

   /// sets output debug string handler
   void SetOutputDebugStringHandler(T_fnOutputDebugString fnOutputDebugString)
   {
      m_fnOutputDebugString = fnOutputDebugString;
   }

   /// inits bindings to CanonControl; since the this parameter is needed in
   /// the bindings, call this immediately after the ctor
   void InitBindings();

   /// cancels all handlers of async operations
   void CancelHandlers();

   /// stops internal timer
   void StopTimer();

private:
   /// returns Lua state object
   Lua::State& GetState() throw() { return m_state; }

   /// inits constants used in various calls
   void InitConstants();

   /// inits constants for SourceDevice table
   void InitSourceDeviceConstants(Lua::Table& constants);

   /// inits constants for ImageProperty table
   void InitImagePropertyConstants(Lua::Table& constants);

   /// inits constants for ShootingMode table
   void InitShootingModeConstants(Lua::Table& constants);

   /// inits constants for ShutterReleaseSettings table
   void InitShutterReleaseSettingsConstants(Lua::Table& constants);

   /// inits constants for RemoteReleaseControl
   void InitRemoteReleaseControlConstants(Lua::Table& constants);

   /// inits constants for Viewfinder
   void InitViewfinderConstants(Lua::Table& constants);

   /// restarts timer for event handling
   void RestartEventTimer();

   /// cleans up all bindings
   void CleanupBindings();

   /// handler for timer used for event handling
   void OnTimerEventHandling(const boost::system::error_code& error);

   // Sys functions

   /// local instance = Sys:getInstance()
   std::vector<Lua::Value> SysGetInstance(Lua::State& state);

   // Instance functions

   /// local version = Instance:getVersion()
   std::vector<Lua::Value> InstanceGetVersion();

   /// local sourceInfoArray = instance:enumerateDevices()
   std::vector<Lua::Value> InstanceEnumerateDevices(Lua::State& state);

   /// instance:asyncWaitForCamera(callbackFunction)
   std::vector<Lua::Value> InstanceAsyncWaitForCamera(Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// method called when a camera has been connected
   void AsyncWaitForCamera_OnCameraConnected();

   // SourceInfo functions

   /// adds a source info table to given table
   /// { name = "camera name", function open() ... end }
   void AddSourceInfo(Lua::State& state, Lua::Table& table, size_t uiIndex, std::shared_ptr<SourceInfo> spSourceInfo);

   /// local sourceDevice = sourceInfo:open()
   std::vector<Lua::Value> SourceInfoOpen(std::shared_ptr<SourceInfo> spSourceInfo,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   // SourceDevice functions

   /// initializes SourceDevice table
   void InitSourceDeviceTable(std::shared_ptr<SourceDevice> spSourceDevice, Lua::Table& sourceDevice);

   /// local isCapable = sourceDevice:getDeviceCapability(Constants.SourceDevice.capXxx)
   std::vector<Lua::Value> SourceDeviceGetDeviceCapability(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// local arrayDeviceProps = sourceDevice:enumDeviceProperties()
   std::vector<Lua::Value> SourceDeviceEnumDeviceProperties(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state);

   /// local deviceProperty = sourceDevice:getDeviceProperty()
   std::vector<Lua::Value> SourceDeviceGetDeviceProperty(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// adds a device property values to given table
   /// { id = "property id", name = "name", asString = "value", isReadOnly = true/false end }
   void AddDeviceProperty(Lua::Table& table, const DeviceProperty& deviceProperty, std::shared_ptr<SourceDevice> spSourceDevice);

   /// enters release control and returns RemoteReleaseControl table
   std::vector<Lua::Value> SourceDeviceEnterReleaseControl(std::shared_ptr<SourceDevice> spSourceDevice,
      Lua::State& state);

   // RemoteReleaseControl functions

   /// initializes RemoteReleaseControl table
   void InitRemoteReleaseControlTable(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::Table& remoteReleaseControl);

   /// local capability = remoteReleaseControl:getCapability()
   std::vector<Lua::Value> RemoteReleaseControlGetCapability(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// local releaseSettings = remoteReleaseControl:getReleaseSettings()
   std::vector<Lua::Value> RemoteReleaseControlGetReleaseSettings(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// initializes ReleaseSettings table
   void InitReleaseSettingsTable(Lua::State& state, const ShutterReleaseSettings& releaseSettings,
      Lua::Table& tableReleaseSettings);

   /// sets new release settings
   std::vector<Lua::Value> RemoteReleaseControlSetReleaseSettings(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// callback that is called when image has been transferred
   void SetReleaseSettings_OnFinishedTransfer(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      const ShutterReleaseSettings& releaseSettings);

   /// event handler for property change events
   void RemoteReleaseControl_PropertyEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      std::shared_ptr<int> spHandlerId,
      RemoteReleaseControl::T_enPropertyEvent,
      unsigned int eventData);

   /// local handlerId = remoteReleaseControl:addPropertyEventHandler(callbackFunction)
   std::vector<Lua::Value> RemoteReleaseControlAddPropertyEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:removePropertyEventHandler(handlerId)
   std::vector<Lua::Value> RemoteReleaseControlRemovePropertyEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// event handler for state events
   void RemoteReleaseControl_StateEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      std::shared_ptr<int> spHandlerId,
      RemoteReleaseControl::T_enStateEvent,
      unsigned int eventData);

   /// local handlerId = remoteReleaseControl:addStateEventHandler(callbackFunction)
   std::vector<Lua::Value> RemoteReleaseControlAddStateEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:removeStateEventHandler(handlerId)
   std::vector<Lua::Value> RemoteReleaseControlRemoveStateEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// event handler for download events
   void RemoteReleaseControl_DownloadEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      std::shared_ptr<int> spHandlerId,
      RemoteReleaseControl::T_enDownloadEvent,
      unsigned int eventData);

   /// local handlerId = remoteReleaseControl:addDownloadEventHandler(callbackFunction)
   std::vector<Lua::Value> RemoteReleaseControlAddDownloadEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:removeDownloadEventHandler(handlerId)
   std::vector<Lua::Value> RemoteReleaseControlRemoveDownloadEventHandler(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// local imagePropertiesList = remoteReleaseControl:enumImageProperties()
   std::vector<Lua::Value> RemoteReleaseControlEnumImageProperties(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::State& state);

   /// local imageProperty = remoteReleaseControl:getImageProperty()
   std::vector<Lua::Value> RemoteReleaseControlGetImageProperty(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// local imageProperty = remoteReleaseControl:getImagePropertyByType(imagePropertyType)
   std::vector<Lua::Value> RemoteReleaseControlGetImagePropertyByType(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// local imageProperty = remoteReleaseControl:getShootingModeImageProperty(shootingMode)
   std::vector<Lua::Value> RemoteReleaseControlGetShootingModeImageProperty(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state,
      const std::vector<Lua::Value>& vecParams);

   /// adds ImageProperty table
   void AddImageProperty(Lua::Table& table, const ImageProperty& imageProperty,
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   /// local viewfinder = remoteReleaseControl:startViewfinder()
   std::vector<Lua::Value> RemoteReleaseControlStartViewfinder(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::State& state);

   /// local numShots = remoteReleaseControl:numAvailableShots()
   std::vector<Lua::Value> RemoteReleaseControlNumAvailableShots(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   /// remoteReleaseControl:sendCommand()
   std::vector<Lua::Value> RemoteReleaseControlSendCommand(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// remoteReleaseControl:release()
   std::vector<Lua::Value> RemoteReleaseControlRelease(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   /// local bulbReleaseControl = remoteReleaseControl:startBulb()
   std::vector<Lua::Value> RemoteReleaseControlStartBulb(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, Lua::State& state);

   /// local remoteReleaseControl:close()
   std::vector<Lua::Value> RemoteReleaseControlClose(
      std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl);

   // Viewfinder functions

   /// initializes viewfinder table
   void InitViewfinderTable(std::shared_ptr<Viewfinder> spViewfinder, Lua::Table& viewfinder);

   /// viewfinder:setOutputType(outputType)
   std::vector<Lua::Value> ViewfinderSetOutputType(std::shared_ptr<Viewfinder> spViewfinder,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// viewfinder:setAvailImageHandler(callbackFunction)
   std::vector<Lua::Value> ViewfinderSetAvailImageHandler(std::shared_ptr<Viewfinder> spViewfinder,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   /// called when a new viewfinder image is available
   void SetAvailImageHandler_OnAvailImageHandler(std::shared_ptr<Viewfinder> spViewfinder,
      const std::vector<BYTE>& vecImage);

   /// called to close viewfinder
   std::vector<Lua::Value> ViewfinderClose(std::shared_ptr<Viewfinder> spViewfinder,
      Lua::State& state, const std::vector<Lua::Value>& vecParams);

   // BulbReleaseControl functions

   /// initizalizes BulbReleaseControl table
   void InitBulbReleaseControlTable(std::shared_ptr<BulbReleaseControl> spBulbReleaseControl, Lua::Table& bulbReleaseControl);

   /// local elapsedTime = bulbReleaseControl:elapsedTime()
   std::vector<Lua::Value> BulbReleaseControlElapsedTime(std::shared_ptr<BulbReleaseControl> spBulbReleaseControl);

   /// bulbReleaseControl:stop()
   std::vector<Lua::Value> BulbReleaseControlStop(std::shared_ptr<BulbReleaseControl> spBulbReleaseControl);

private:
   /// Lua state
   Lua::State& m_state;

   /// CanonControl instance
   std::unique_ptr<Instance> m_upInstance;

   /// release settings stored for the script
   ShutterReleaseSettings m_releaseSettings;

   /// once Lua has connected to remote release control, a pointer is stored here
   std::shared_ptr<RemoteReleaseControl> m_spRemoteRelaseControl;

   /// set of all registered property handler ids
   std::set<int> m_setAllPropertyHandlerIds;

   /// set of all registered state handler ids
   std::set<int> m_setAllStateHandlerIds;

   /// set of all registered download handler ids
   std::set<int> m_setAllDownloadHandlerIds;

   /// once Lua script started viewfinder, a pointer is stored here
   std::shared_ptr<Viewfinder> m_spViewfinder;

   /// strand to execute all Lua calls on
   boost::asio::io_service::strand& m_strand;

   /// output debug string handler
   T_fnOutputDebugString m_fnOutputDebugString;

   /// mutex to protect AsyncWaitForCamera() handler to call Lua script multiple times
   RecursiveMutex m_mtxAsyncWaitForCamera_InScript;

   /// timer for event handling
   boost::asio::deadline_timer m_timerEventHandling;

   /// event that is set when the event handling timer has stopped
   Event m_evtTimerStopped;
};
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) Yorik van Havre          (yorik@uncreated.net) 2015     *
 *   Copyright (c) 2016 WandererFan    (wandererfan@gmail.com)             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
#endif

#include <iomanip>

#include <App/Application.h>
#include <App/Property.h>
#include <App/PropertyStandard.h>
#include <App/PropertyUnits.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/FileInfo.h>
#include <Base/Parameter.h>

#include "DrawViewSpreadsheet.h"

#include <Mod/Spreadsheet/App/Cell.h>
#include <Mod/Spreadsheet/App/Sheet.h>

using namespace TechDraw;
using namespace std;

//===========================================================================
// DrawViewSpreadsheet
//===========================================================================

PROPERTY_SOURCE(TechDraw::DrawViewSpreadsheet, TechDraw::DrawViewSymbol)

DrawViewSpreadsheet::DrawViewSpreadsheet(void)
{
    static const char *vgroup = "Spreadsheet";

    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Labels");
    std::string fontName = hGrp->GetASCII("LabelFont", "osifont");

    ADD_PROPERTY_TYPE(Source ,(0),vgroup,App::Prop_None,"Spreadsheet to view");
    Source.setScope(App::LinkScope::Global);
    ADD_PROPERTY_TYPE(CellStart ,("A1"),vgroup,App::Prop_None,"The top left cell of the range to display");
    ADD_PROPERTY_TYPE(CellEnd ,("B2"),vgroup,App::Prop_None,"The bottom right cell of the range to display");
    ADD_PROPERTY_TYPE(Font ,((fontName.c_str())),vgroup,App::Prop_None,"The name of the font to use");
    ADD_PROPERTY_TYPE(TextColor,(0.0f,0.0f,0.0f),vgroup,App::Prop_None,"The default color of the text and lines");
    ADD_PROPERTY_TYPE(TextSize,(12.0),vgroup,App::Prop_None,"The size of the text");
    ADD_PROPERTY_TYPE(LineWidth,(0.35),vgroup,App::Prop_None,"The thickness of the cell lines");

    EditableTexts.setStatus(App::Property::Hidden,true);

}

DrawViewSpreadsheet::~DrawViewSpreadsheet()
{
}

short DrawViewSpreadsheet::mustExecute() const
{
    short result = 0;
    if (!isRestoring()) {
        result  =  (Source.isTouched()  ||
                    CellStart.isTouched() ||
                    CellEnd.isTouched() ||
                    Font.isTouched() ||
                    TextSize.isTouched() ||
                    TextColor.isTouched() ||
                    LineWidth.isTouched() );
    }
    if (result) {
        return result;
    }
    return TechDraw::DrawView::mustExecute();
}

void DrawViewSpreadsheet::onChanged(const App::Property* prop)
{
    TechDraw::DrawView::onChanged(prop);
}

App::DocumentObjectExecReturn *DrawViewSpreadsheet::execute(void)
{
    App::DocumentObject* link = Source.getValue();
    std::string scellstart = CellStart.getValue();
    std::string scellend = CellEnd.getValue();
    if (!link)
        return new App::DocumentObjectExecReturn("No spreadsheet linked");
    if (!link->getTypeId().isDerivedFrom(Spreadsheet::Sheet::getClassTypeId()))
        return new App::DocumentObjectExecReturn("The linked object is not a spreadsheet");
    if ( (scellstart.empty()) || (scellend.empty()) )
        return new App::DocumentObjectExecReturn("Empty cell value");

    Symbol.setValue(getSheetImage());

    return TechDraw::DrawView::execute();
}

std::vector<std::string> DrawViewSpreadsheet::getAvailColumns(void)
{
    // build a list of available columns: A, B, C, ... AA, AB, ... ZY, ZZ.
    std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    std::vector<std::string> availcolumns;
    for (int i=0; i<26; ++i) {              //A:Z
        std::stringstream s;
        s << alphabet[i];
        availcolumns.push_back(s.str());
    }
    for (int i=0; i<26; ++i) {             //AA:ZZ
        for (int j=0; j<26; ++j) {
            std::stringstream s;
            s << alphabet[i] << alphabet[j];
            availcolumns.push_back(s.str());
        }
    }
    return availcolumns;
}

std::string DrawViewSpreadsheet::getSVGHead(void)
{
    std::string head = std::string("<svg\n") +
                       std::string("	xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n") +
                       std::string("	xmlns:freecad=\"http://www.freecadweb.org/wiki/index.php?title=Svg_Namespace\">\n");
    return head;
}

std::string DrawViewSpreadsheet::getSVGTail(void)
{
    std::string tail = "\n</svg>";
    return tail;
}

std::string DrawViewSpreadsheet::getSheetImage(void)
{
    std::stringstream result;

    App::DocumentObject* link = Source.getValue();
    link->recomputeFeature();   //make sure s/s is up to date

    std::string scellstart = CellStart.getValue();
    std::string scellend = CellEnd.getValue();

    std::vector<std::string> availcolumns = getAvailColumns();

    // build rows range and columns range
    std::vector<std::string> columns;
    std::vector<int> rows;
    //break startcell into row & column parts
    //Note: could do this with regex ([A-Z]*)([0-9]*)
    std::string startCol;
    int startRow = -1;
    for (unsigned int i=0; i<scellstart.length(); ++i) {
        if (isdigit(scellstart[i])) {
            startCol = scellstart.substr(0,i);
            startRow = std::atoi(scellstart.substr(i,scellstart.length()-1).c_str());
            break;    //first digit is enough
        }
    }

    //validate startCol in A:ZZ
    int iStart = colInList(availcolumns,startCol);
    if (iStart >= 0) {
        columns.push_back(startCol);
        rows.push_back(startRow);
    } else {
        Base::Console().Error("DVS - %s - start Column (%s) is invalid\n",getNameInDocument(),startCol.c_str());
        return result.str();
    }
    //startCol is valid

    //break endcell contents into row & col parts
    std::string endCol;
    int endRow = -1;
    for (unsigned int i=0; i<scellend.length(); ++i) {
        if (isdigit(scellend[i])) {
            endCol = scellend.substr(0,i);
            endRow = std::atoi(scellend.substr(i,scellend.length()-1).c_str());
            break;
        }
    }
    //validate endCol in A:ZZ
    int iEnd = colInList(availcolumns,endCol);
    if (iEnd < 0) {
        Base::Console().Error("DVS - %s - end Column (%s) is invalid\n",getNameInDocument(),endCol.c_str());
        return result.str();
    }
    //endCol is valid

    if ( (startCol > endCol) ||
         (startRow > endRow) ) {
        Base::Console().Error("DVS - %s - cell range is invalid\n",getNameInDocument());
        return result.str();
    }

    //fill the col/row name vectors
    if (startCol != endCol) {
        int i = iStart + 1;
        for ( ; i < iEnd; i++) {
            columns.push_back(availcolumns.at(i));
        }
        columns.push_back(endCol);
    }
    int i = startRow + 1;
    for (; i < endRow; i ++) {
        rows.push_back(i);
    }
    rows.push_back(endRow);

    // create the Svg code
    std::string ViewName = Label.getValue();

    result << getSVGHead();

    App::Color c = TextColor.getValue();
    result  << "<g id=\"" << ViewName << "\">" << endl;

    // fill the cells
    float rowoffset = 0.0;
    float coloffset = 0.0;
    float cellheight = 100;
    float cellwidth = 100;
    std::string celltext;
    Spreadsheet::Sheet* sheet = static_cast<Spreadsheet::Sheet*>(link);
    std::vector<std::string> skiplist;

    for (std::vector<std::string>::const_iterator col = columns.begin(); col != columns.end(); ++col) {
        // create a group for each column
        result << "  <g id=\"" << ViewName << "_col" << (*col) << "\">" << endl;
        for (std::vector<int>::const_iterator row = rows.begin(); row != rows.end(); ++row) {
            // get cell size
            std::stringstream srow;
            srow << (*row);
            App::CellAddress address((*col) + srow.str());
            cellwidth = sheet->getColumnWidth(address.col());
            cellheight = sheet->getRowHeight(address.row());
            celltext = "";
            Spreadsheet::Cell* cell = sheet->getCell(address);
            // get the text
            App::Property* prop = sheet->getPropertyByName(address.toString().c_str());
            std::stringstream field;
            if (prop != 0) {
                if (prop->isDerivedFrom((App::PropertyQuantity::getClassTypeId()))) {
                    field << cell->getFormattedQuantity();
                } else if (prop->isDerivedFrom((App::PropertyFloat::getClassTypeId())))
                    field << cell->getFormattedQuantity();
                else if (prop->isDerivedFrom((App::PropertyString::getClassTypeId())))
                    field << static_cast<App::PropertyString*>(prop)->getValue();
                else
                    assert(0);
                celltext = field.str();
            }
            // get colors, style, alignment and span
            int alignment = 0;
            std::string bcolor = "none";
            std::string fcolor = c.asCSSString();
            std::string textstyle = "";
            if (cell) {
                App::Color f,b;
                std::set<std::string> st;
                int colspan, rowspan;
                if (cell->getBackground(b)) {
                    bcolor = b.asCSSString();
                }
                if (cell->getForeground(f)) {
                    fcolor = f.asCSSString();
                }
                if (cell->getStyle(st)) {
                    for (std::set<std::string>::const_iterator i = st.begin(); i != st.end(); ++i) {
                         if ((*i) == "bold")
                            textstyle = textstyle + "font-weight: bold; ";
                        else if ((*i) == "italic")
                            textstyle = textstyle + "font-style: italic; ";
                        else if ((*i) == "underline")
                            textstyle = textstyle + "text-decoration: underline; ";
                    }
                }
                if (cell->getSpans(rowspan,colspan)) {
                    for (int i=0; i<colspan; ++i) {
                        for (int j=0; j<rowspan; ++j) {
                            App::CellAddress nextcell(address.row()+j,address.col()+i);
                            if (i > 0)
                                cellwidth = cellwidth + sheet->getColumnWidth(nextcell.col());
                            if (j > 0)
                                cellheight = cellheight + sheet->getRowHeight(nextcell.row());
                            if ( (i > 0) || (j > 0) )
                                skiplist.push_back(nextcell.toString());
                        }
                    }
                }
                cell->getAlignment(alignment);
            }
            // skip cell if found in skiplist
            if (std::find(skiplist.begin(), skiplist.end(), address.toString()) == skiplist.end()) {
                result << "    <rect x=\"" << coloffset << "\" y=\"" << rowoffset << "\" width=\"" << cellwidth
                       << "\" height=\"" << cellheight << "\" style=\"fill:" << bcolor << ";stroke-width:"
                       << LineWidth.getValue()/getScale() << ";stroke:" << c.asCSSString() << ";\" />" << endl;
                if (alignment & Spreadsheet::Cell::ALIGNMENT_LEFT)
                    result << "    <text style=\"" << textstyle << "\" x=\"" << coloffset + TextSize.getValue()/2 << "\" y=\"" << rowoffset + 0.75 * cellheight << "\" font-family=\"" ;
                if (alignment & Spreadsheet::Cell::ALIGNMENT_HCENTER)
                    result << "    <text text-anchor=\"middle\" style=\"" << textstyle << "\" x=\"" << coloffset + cellwidth/2 << "\" y=\"" << rowoffset + 0.75 * cellheight << "\" font-family=\"" ;
                if (alignment & Spreadsheet::Cell::ALIGNMENT_RIGHT)
                    result << "    <text text-anchor=\"end\" style=\"" << textstyle << "\" x=\"" << coloffset + (cellwidth - TextSize.getValue()/2) << "\" y=\"" << rowoffset + 0.75 * cellheight << "\" font-family=\"" ;
                if ((alignment & Spreadsheet::Cell::ALIGNMENT_LEFT) ||
                    (alignment & Spreadsheet::Cell::ALIGNMENT_HCENTER) ||
                    (alignment & Spreadsheet::Cell::ALIGNMENT_RIGHT)) {
                    result << Font.getValue() << "\"" << " font-size=\"" << TextSize.getValue() << "\""
                           << " fill=\"" << fcolor << "\">" << celltext << "</text>" << endl;
                }
            }
            rowoffset = rowoffset + cellheight;
        }
        result << "  </g>" << endl;
        rowoffset = 0.0;
        coloffset = coloffset + cellwidth;
    }

    // close the containing group
    result << "</g>" << endl;

    result << getSVGTail();

    return result.str();

}

int DrawViewSpreadsheet::colInList(const std::vector<std::string>& list,
                                                              const std::string& toFind)
{
    int result = -1;
    auto match = std::find(std::begin(list), std::end(list), toFind);
    if (match != std::end(list)) {
        result = match - std::begin(list);
    }
    return result;
}

// Python Drawing feature ---------------------------------------------------------

namespace App {
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewSpreadsheetPython, TechDraw::DrawViewSpreadsheet)
template<> const char* TechDraw::DrawViewSpreadsheetPython::getViewProviderName(void) const {
    return "TechDrawGui::ViewProviderSpreadsheet";
}
/// @endcond

// explicit template instantiation
template class TechDrawExport FeaturePythonT<TechDraw::DrawViewSpreadsheet>;
}
<commit_msg>[TD]Fix Integer display in s/s image<commit_after>/***************************************************************************
 *   Copyright (c) Yorik van Havre          (yorik@uncreated.net) 2015     *
 *   Copyright (c) 2016 WandererFan    (wandererfan@gmail.com)             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
#endif

#include <iomanip>

#include <App/Application.h>
#include <App/Property.h>
#include <App/PropertyStandard.h>
#include <App/PropertyUnits.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/FileInfo.h>
#include <Base/Parameter.h>

#include "DrawViewSpreadsheet.h"

#include <Mod/Spreadsheet/App/Cell.h>
#include <Mod/Spreadsheet/App/Sheet.h>

using namespace TechDraw;
using namespace std;

//===========================================================================
// DrawViewSpreadsheet
//===========================================================================

PROPERTY_SOURCE(TechDraw::DrawViewSpreadsheet, TechDraw::DrawViewSymbol)

DrawViewSpreadsheet::DrawViewSpreadsheet(void)
{
    static const char *vgroup = "Spreadsheet";

    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Labels");
    std::string fontName = hGrp->GetASCII("LabelFont", "osifont");

    ADD_PROPERTY_TYPE(Source ,(0),vgroup,App::Prop_None,"Spreadsheet to view");
    Source.setScope(App::LinkScope::Global);
    ADD_PROPERTY_TYPE(CellStart ,("A1"),vgroup,App::Prop_None,"The top left cell of the range to display");
    ADD_PROPERTY_TYPE(CellEnd ,("B2"),vgroup,App::Prop_None,"The bottom right cell of the range to display");
    ADD_PROPERTY_TYPE(Font ,((fontName.c_str())),vgroup,App::Prop_None,"The name of the font to use");
    ADD_PROPERTY_TYPE(TextColor,(0.0f,0.0f,0.0f),vgroup,App::Prop_None,"The default color of the text and lines");
    ADD_PROPERTY_TYPE(TextSize,(12.0),vgroup,App::Prop_None,"The size of the text");
    ADD_PROPERTY_TYPE(LineWidth,(0.35),vgroup,App::Prop_None,"The thickness of the cell lines");

    EditableTexts.setStatus(App::Property::Hidden,true);

}

DrawViewSpreadsheet::~DrawViewSpreadsheet()
{
}

short DrawViewSpreadsheet::mustExecute() const
{
    short result = 0;
    if (!isRestoring()) {
        result  =  (Source.isTouched()  ||
                    CellStart.isTouched() ||
                    CellEnd.isTouched() ||
                    Font.isTouched() ||
                    TextSize.isTouched() ||
                    TextColor.isTouched() ||
                    LineWidth.isTouched() );
    }
    if (result) {
        return result;
    }
    return TechDraw::DrawView::mustExecute();
}

void DrawViewSpreadsheet::onChanged(const App::Property* prop)
{
    TechDraw::DrawView::onChanged(prop);
}

App::DocumentObjectExecReturn *DrawViewSpreadsheet::execute(void)
{
    App::DocumentObject* link = Source.getValue();
    std::string scellstart = CellStart.getValue();
    std::string scellend = CellEnd.getValue();
    if (!link)
        return new App::DocumentObjectExecReturn("No spreadsheet linked");
    if (!link->getTypeId().isDerivedFrom(Spreadsheet::Sheet::getClassTypeId()))
        return new App::DocumentObjectExecReturn("The linked object is not a spreadsheet");
    if ( (scellstart.empty()) || (scellend.empty()) )
        return new App::DocumentObjectExecReturn("Empty cell value");

    Symbol.setValue(getSheetImage());

    return TechDraw::DrawView::execute();
}

std::vector<std::string> DrawViewSpreadsheet::getAvailColumns(void)
{
    // build a list of available columns: A, B, C, ... AA, AB, ... ZY, ZZ.
    std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    std::vector<std::string> availcolumns;
    for (int i=0; i<26; ++i) {              //A:Z
        std::stringstream s;
        s << alphabet[i];
        availcolumns.push_back(s.str());
    }
    for (int i=0; i<26; ++i) {             //AA:ZZ
        for (int j=0; j<26; ++j) {
            std::stringstream s;
            s << alphabet[i] << alphabet[j];
            availcolumns.push_back(s.str());
        }
    }
    return availcolumns;
}

std::string DrawViewSpreadsheet::getSVGHead(void)
{
    std::string head = std::string("<svg\n") +
                       std::string("	xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n") +
                       std::string("	xmlns:freecad=\"http://www.freecadweb.org/wiki/index.php?title=Svg_Namespace\">\n");
    return head;
}

std::string DrawViewSpreadsheet::getSVGTail(void)
{
    std::string tail = "\n</svg>";
    return tail;
}

std::string DrawViewSpreadsheet::getSheetImage(void)
{
    std::stringstream result;

    App::DocumentObject* link = Source.getValue();
    link->recomputeFeature();   //make sure s/s is up to date

    std::string scellstart = CellStart.getValue();
    std::string scellend = CellEnd.getValue();

    std::vector<std::string> availcolumns = getAvailColumns();

    // build rows range and columns range
    std::vector<std::string> columns;
    std::vector<int> rows;
    //break startcell into row & column parts
    //Note: could do this with regex ([A-Z]*)([0-9]*)
    std::string startCol;
    int startRow = -1;
    for (unsigned int i=0; i<scellstart.length(); ++i) {
        if (isdigit(scellstart[i])) {
            startCol = scellstart.substr(0,i);
            startRow = std::atoi(scellstart.substr(i,scellstart.length()-1).c_str());
            break;    //first digit is enough
        }
    }

    //validate startCol in A:ZZ
    int iStart = colInList(availcolumns,startCol);
    if (iStart >= 0) {
        columns.push_back(startCol);
        rows.push_back(startRow);
    } else {
        Base::Console().Error("DVS - %s - start Column (%s) is invalid\n",getNameInDocument(),startCol.c_str());
        return result.str();
    }
    //startCol is valid

    //break endcell contents into row & col parts
    std::string endCol;
    int endRow = -1;
    for (unsigned int i=0; i<scellend.length(); ++i) {
        if (isdigit(scellend[i])) {
            endCol = scellend.substr(0,i);
            endRow = std::atoi(scellend.substr(i,scellend.length()-1).c_str());
            break;
        }
    }
    //validate endCol in A:ZZ
    int iEnd = colInList(availcolumns,endCol);
    if (iEnd < 0) {
        Base::Console().Error("DVS - %s - end Column (%s) is invalid\n",getNameInDocument(),endCol.c_str());
        return result.str();
    }
    //endCol is valid

    if ( (startCol > endCol) ||
         (startRow > endRow) ) {
        Base::Console().Error("DVS - %s - cell range is invalid\n",getNameInDocument());
        return result.str();
    }

    //fill the col/row name vectors
    if (startCol != endCol) {
        int i = iStart + 1;
        for ( ; i < iEnd; i++) {
            columns.push_back(availcolumns.at(i));
        }
        columns.push_back(endCol);
    }
    int i = startRow + 1;
    for (; i < endRow; i ++) {
        rows.push_back(i);
    }
    rows.push_back(endRow);

    // create the Svg code
    std::string ViewName = Label.getValue();

    result << getSVGHead();

    App::Color c = TextColor.getValue();
    result  << "<g id=\"" << ViewName << "\">" << endl;

    // fill the cells
    float rowoffset = 0.0;
    float coloffset = 0.0;
    float cellheight = 100;
    float cellwidth = 100;
    std::string celltext;
    Spreadsheet::Sheet* sheet = static_cast<Spreadsheet::Sheet*>(link);
    std::vector<std::string> skiplist;

    for (std::vector<std::string>::const_iterator col = columns.begin(); col != columns.end(); ++col) {
        // create a group for each column
        result << "  <g id=\"" << ViewName << "_col" << (*col) << "\">" << endl;
        for (std::vector<int>::const_iterator row = rows.begin(); row != rows.end(); ++row) {
            // get cell size
            std::stringstream srow;
            srow << (*row);
            App::CellAddress address((*col) + srow.str());
            cellwidth = sheet->getColumnWidth(address.col());
            cellheight = sheet->getRowHeight(address.row());
            celltext = "";
            Spreadsheet::Cell* cell = sheet->getCell(address);
            // get the text
            App::Property* prop = sheet->getPropertyByName(address.toString().c_str());
            std::stringstream field;
            if (prop != 0) {
                if (prop->isDerivedFrom((App::PropertyQuantity::getClassTypeId()))) {
                    field << cell->getFormattedQuantity();
                } else if (prop->isDerivedFrom((App::PropertyFloat::getClassTypeId()))) {
                    field << cell->getFormattedQuantity();
                } else if (prop->isDerivedFrom((App::PropertyInteger::getClassTypeId()))) {
                    field << cell->getFormattedQuantity();
                } else if (prop->isDerivedFrom((App::PropertyString::getClassTypeId()))) {
                    field << static_cast<App::PropertyString*>(prop)->getValue();
                } else {
                    Base::Console().Error("DVSS: Unknown property type\n");
                    celltext = "???";
//                    assert(0);
                }
                celltext = field.str();
            }
            // get colors, style, alignment and span
            int alignment = 0;
            std::string bcolor = "none";
            std::string fcolor = c.asCSSString();
            std::string textstyle = "";
            if (cell) {
                App::Color f,b;
                std::set<std::string> st;
                int colspan, rowspan;
                if (cell->getBackground(b)) {
                    bcolor = b.asCSSString();
                }
                if (cell->getForeground(f)) {
                    fcolor = f.asCSSString();
                }
                if (cell->getStyle(st)) {
                    for (std::set<std::string>::const_iterator i = st.begin(); i != st.end(); ++i) {
                         if ((*i) == "bold")
                            textstyle = textstyle + "font-weight: bold; ";
                        else if ((*i) == "italic")
                            textstyle = textstyle + "font-style: italic; ";
                        else if ((*i) == "underline")
                            textstyle = textstyle + "text-decoration: underline; ";
                    }
                }
                if (cell->getSpans(rowspan,colspan)) {
                    for (int i=0; i<colspan; ++i) {
                        for (int j=0; j<rowspan; ++j) {
                            App::CellAddress nextcell(address.row()+j,address.col()+i);
                            if (i > 0)
                                cellwidth = cellwidth + sheet->getColumnWidth(nextcell.col());
                            if (j > 0)
                                cellheight = cellheight + sheet->getRowHeight(nextcell.row());
                            if ( (i > 0) || (j > 0) )
                                skiplist.push_back(nextcell.toString());
                        }
                    }
                }
                cell->getAlignment(alignment);
            }
            // skip cell if found in skiplist
            if (std::find(skiplist.begin(), skiplist.end(), address.toString()) == skiplist.end()) {
                result << "    <rect x=\"" << coloffset << "\" y=\"" << rowoffset << "\" width=\"" << cellwidth
                       << "\" height=\"" << cellheight << "\" style=\"fill:" << bcolor << ";stroke-width:"
                       << LineWidth.getValue()/getScale() << ";stroke:" << c.asCSSString() << ";\" />" << endl;
                if (alignment & Spreadsheet::Cell::ALIGNMENT_LEFT)
                    result << "    <text style=\"" << textstyle << "\" x=\"" << coloffset + TextSize.getValue()/2 << "\" y=\"" << rowoffset + 0.75 * cellheight << "\" font-family=\"" ;
                if (alignment & Spreadsheet::Cell::ALIGNMENT_HCENTER)
                    result << "    <text text-anchor=\"middle\" style=\"" << textstyle << "\" x=\"" << coloffset + cellwidth/2 << "\" y=\"" << rowoffset + 0.75 * cellheight << "\" font-family=\"" ;
                if (alignment & Spreadsheet::Cell::ALIGNMENT_RIGHT)
                    result << "    <text text-anchor=\"end\" style=\"" << textstyle << "\" x=\"" << coloffset + (cellwidth - TextSize.getValue()/2) << "\" y=\"" << rowoffset + 0.75 * cellheight << "\" font-family=\"" ;
                if ((alignment & Spreadsheet::Cell::ALIGNMENT_LEFT) ||
                    (alignment & Spreadsheet::Cell::ALIGNMENT_HCENTER) ||
                    (alignment & Spreadsheet::Cell::ALIGNMENT_RIGHT)) {
                    result << Font.getValue() << "\"" << " font-size=\"" << TextSize.getValue() << "\""
                           << " fill=\"" << fcolor << "\">" << celltext << "</text>" << endl;
                }
            }
            rowoffset = rowoffset + cellheight;
        }
        result << "  </g>" << endl;
        rowoffset = 0.0;
        coloffset = coloffset + cellwidth;
    }

    // close the containing group
    result << "</g>" << endl;

    result << getSVGTail();

    return result.str();

}

int DrawViewSpreadsheet::colInList(const std::vector<std::string>& list,
                                                              const std::string& toFind)
{
    int result = -1;
    auto match = std::find(std::begin(list), std::end(list), toFind);
    if (match != std::end(list)) {
        result = match - std::begin(list);
    }
    return result;
}

// Python Drawing feature ---------------------------------------------------------

namespace App {
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewSpreadsheetPython, TechDraw::DrawViewSpreadsheet)
template<> const char* TechDraw::DrawViewSpreadsheetPython::getViewProviderName(void) const {
    return "TechDrawGui::ViewProviderSpreadsheet";
}
/// @endcond

// explicit template instantiation
template class TechDrawExport FeaturePythonT<TechDraw::DrawViewSpreadsheet>;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/drag_util.h"

#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/window.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drag_utils.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/widget/widget.h"

namespace atom {

void DragFileItems(const std::vector<base::FilePath>& files,
                   const gfx::Image& icon,
                   gfx::NativeView view) {
  // Set up our OLE machinery
  ui::OSExchangeData data;

  drag_utils::CreateDragImageForFile(files[0], icon.AsImageSkia(), &data);

  std::vector<ui::FileInfo> file_infos;
  for (const base::FilePath& file : files) {
    file_infos.push_back(ui::FileInfo(file, base::FilePath()));
  }
  data.SetFilenames(file_infos);

  aura::Window* root_window = view->GetRootWindow();
  if (!root_window || !aura::client::GetDragDropClient(root_window))
    return;

  gfx::Point location = display::Screen::GetScreen()->GetCursorScreenPoint();
  // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below.
  aura::client::GetDragDropClient(root_window)->StartDragAndDrop(
      data,
      root_window,
      view,
      location,
      ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK,
      ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
}

}  // namespace atom
<commit_msg>CreateDragImageForFile -> SetDragImage<commit_after>// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/drag_util.h"

#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/window.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/button_drag_utils.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"

namespace atom {

void DragFileItems(const std::vector<base::FilePath>& files,
                   const gfx::Image& icon,
                   gfx::NativeView view) {
  // Set up our OLE machinery
  ui::OSExchangeData data;

  button_drag_utils::SetDragImage(GURL(),
      files[0].BaseName().LossyDisplayName(),
      icon.AsImageSkia(),
      nullptr,
      *views::Widget::GetTopLevelWidgetForNativeView(view),
      &data);

  std::vector<ui::FileInfo> file_infos;
  for (const base::FilePath& file : files) {
    file_infos.push_back(ui::FileInfo(file, base::FilePath()));
  }
  data.SetFilenames(file_infos);

  aura::Window* root_window = view->GetRootWindow();
  if (!root_window || !aura::client::GetDragDropClient(root_window))
    return;

  gfx::Point location = display::Screen::GetScreen()->GetCursorScreenPoint();
  // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below.
  aura::client::GetDragDropClient(root_window)->StartDragAndDrop(
      data,
      root_window,
      view,
      location,
      ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK,
      ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
}

}  // namespace atom
<|endoftext|>