<commit_before>/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

#undef NDEBUG
#include <chrono>
#include <map>
#include <memory>
#include <string>
#include <thread>

#include "core/Core.h"
#include "core/repository/AtomicRepoEntries.h"
#include "core/RepositoryFactory.h"
#include "FlowFileRecord.h"
#include "provenance/Provenance.h"
#include "properties/Configure.h"
#include "../unit/ProvenanceTestHelper.h"
#include "../TestBase.h"
#include "YamlConfiguration.h"
#include "CustomProcessors.h"
#include "TestControllerWithFlow.h"

const char* yamlConfig =
    R"(
Flow Controller:
    name: MiNiFi Flow
    id: 2438e3c8-015a-1000-79ca-83af40ec1990
Processors:
  - name: Generator
    id: 2438e3c8-015a-1000-79ca-83af40ec1991
    class: org.apache.nifi.processors.standard.TestFlowFileGenerator
    max concurrent tasks: 1
    scheduling strategy: TIMER_DRIVEN
    scheduling period: 100 ms
    penalization period: 300 ms
    yield period: 100 ms
    run duration nanos: 0
    auto-terminated relationships list:
    Properties:
      Batch Size: 3
  - name: TestProcessor
    id: 2438e3c8-015a-1000-79ca-83af40ec1992
    class: org.apache.nifi.processors.standard.TestProcessor
    max concurrent tasks: 1
    scheduling strategy: TIMER_DRIVEN
    scheduling period: 100 ms
    penalization period: 3 sec
    yield period: 1 sec
    run duration nanos: 0
    auto-terminated relationships list:
      - apple
      - banana
Connections:
  - name: Gen
    id: 2438e3c8-015a-1000-79ca-83af40ec1997
    source name: Generator
    source id: 2438e3c8-015a-1000-79ca-83af40ec1991
    source relationship name: success
    destination name: TestProcessor
    destination id: 2438e3c8-015a-1000-79ca-83af40ec1992
    max work queue size: 0
    max work queue data size: 1 MB
    flowfile expiration: 60 sec
Remote Processing Groups:

Controller Services:
  - name: defaultstatemanagerprovider
    id: 2438e3c8-015a-1000-79ca-83af40ec1995
    class: UnorderedMapPersistableKeyValueStoreService
    Properties:
      Auto Persistence Interval:
          - value: 0 sec
      File:
          - value: flowcontrollertests_state.txt
)";

template<typename Fn>
bool verifyWithBusyWait(std::chrono::milliseconds timeout, Fn&& fn) {
  auto start = std::chrono::steady_clock::now();
  while (std::chrono::steady_clock::now() - start < timeout) {
    if (fn()) {
      return true;
    }
  }
  return false;
}

TEST_CASE("Flow shutdown drains connections", "[TestFlow1]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, "100 ms");

  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));
  // prevent execution of the consumer processor
  sinkProc->yield(10000);

  std::map<std::string, std::shared_ptr<minifi::Connection>> connectionMap;

  root->getConnections(connectionMap);
  // adds the single connection to the map both by name and id
  REQUIRE(connectionMap.size() == 2);

  testController.startFlow();

  // wait for the generator to create some files
  std::this_thread::sleep_for(std::chrono::milliseconds{1000});

  for (auto& it : connectionMap) {
    REQUIRE(it.second->getQueueSize() > 10);
  }

  controller->stop();

  REQUIRE(sinkProc->trigger_count == 0);

  for (auto& it : connectionMap) {
    REQUIRE(it.second->isEmpty());
  }
}

TEST_CASE("Flow shutdown waits for a while", "[TestFlow2]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, "10 s");

  auto sourceProc = std::static_pointer_cast<minifi::processors::TestFlowFileGenerator>(root->findProcessorByName("Generator"));
  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));

  std::promise<void> execSinkPromise;
  std::future<void> execSinkFuture = execSinkPromise.get_future();
  sinkProc->onTriggerCb_ = [&] {
    execSinkFuture.wait();
  };

  testController.startFlow();

  // wait for the source processor to enqueue its flowFiles
  auto flowFilesEnqueued = [&] {return root->getTotalFlowFileCount() == 3;};
  REQUIRE(verifyWithBusyWait(std::chrono::milliseconds{200}, flowFilesEnqueued));

  REQUIRE(sourceProc->trigger_count.load() == 1);

  execSinkPromise.set_value();
  controller->stop();

  REQUIRE(sourceProc->trigger_count.load() == 1);
  REQUIRE(sinkProc->trigger_count.load() == 3);
}

TEST_CASE("Flow stopped after grace period", "[TestFlow3]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, "1000 ms");

  auto sourceProc = std::static_pointer_cast<minifi::processors::TestFlowFileGenerator>(root->findProcessorByName("Generator"));
  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));

  std::promise<void> execSinkPromise;
  std::future<void> execSinkFuture = execSinkPromise.get_future();
  sinkProc->onTriggerCb_ = [&]{
    execSinkFuture.wait();
    static std::atomic<bool> first_onTrigger{true};
    bool isFirst = true;
    // sleep only on the first trigger
    if (first_onTrigger.compare_exchange_strong(isFirst, false)) {
      std::this_thread::sleep_for(std::chrono::milliseconds{1500});
    }
  };

  testController.startFlow();

  // wait for the source processor to enqueue its flowFiles
  auto flowFilesEnqueued = [&] {return root->getTotalFlowFileCount() == 3;};
  REQUIRE(verifyWithBusyWait(std::chrono::milliseconds{200}, flowFilesEnqueued));

  REQUIRE(sourceProc->trigger_count.load() == 1);

  execSinkPromise.set_value();
  controller->stop();

  REQUIRE(sourceProc->trigger_count.load() == 1);
  REQUIRE(sinkProc->trigger_count.load() == 1);
}

TEST_CASE("Extend the waiting period during shutdown", "[TestFlow4]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  unsigned int timeout_ms = 1000;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, std::to_string(timeout_ms) + " ms");

  auto sourceProc = std::static_pointer_cast<minifi::processors::TestFlowFileGenerator>(root->findProcessorByName("Generator"));
  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));

  std::promise<void> execSinkPromise;
  std::future<void> execSinkFuture = execSinkPromise.get_future();
  sinkProc->onTriggerCb_ = [&]{
    execSinkFuture.wait();
    static std::atomic<bool> first_onTrigger{true};
    bool isFirst = true;
    // sleep only on the first trigger
    if (first_onTrigger.compare_exchange_strong(isFirst, false)) {
      std::this_thread::sleep_for(std::chrono::milliseconds{1500});
    }
  };

  testController.startFlow();

  // wait for the source processor to enqueue its flowFiles
  auto flowFilesEnqueued = [&] {return root->getTotalFlowFileCount() == 3;};
  REQUIRE(verifyWithBusyWait(std::chrono::milliseconds{200}, flowFilesEnqueued));

  REQUIRE(sourceProc->trigger_count.load() == 1);

  std::thread shutdownThread([&]{
    execSinkPromise.set_value();
    controller->stop();
  });

  auto shutdownInitiated = std::chrono::steady_clock::now();
  auto shutdownDuration = [&] {return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - shutdownInitiated);};

  std::this_thread::sleep_for(std::chrono::milliseconds{500});
  while (shutdownDuration() < std::chrono::milliseconds(5000) && controller->isRunning()) {
    timeout_ms += 500;
    testController.getLogger()->log_info("Controller still running after %u ms, extending the waiting period to %u ms, ff count: %u",
        static_cast<unsigned int>(shutdownDuration().count()), timeout_ms, static_cast<unsigned int>(root->getTotalFlowFileCount()));
    testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, std::to_string(timeout_ms) + " ms");
    std::this_thread::sleep_for(std::chrono::milliseconds{500});
  }

  REQUIRE(!controller->isRunning());
  REQUIRE(shutdownDuration().count() > 1500);

  shutdownThread.join();

  REQUIRE(sourceProc->trigger_count.load() == 1);
  REQUIRE(sinkProc->trigger_count.load() == 3);
}
<commit_msg>MINIFICPP-1438 Fix transient failures of FlowControllerTests<commit_after>/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

#undef NDEBUG
#include <chrono>
#include <map>
#include <memory>
#include <string>
#include <thread>

#include "core/Core.h"
#include "core/repository/AtomicRepoEntries.h"
#include "core/RepositoryFactory.h"
#include "FlowFileRecord.h"
#include "provenance/Provenance.h"
#include "properties/Configure.h"
#include "../unit/ProvenanceTestHelper.h"
#include "../TestBase.h"
#include "YamlConfiguration.h"
#include "CustomProcessors.h"
#include "TestControllerWithFlow.h"

const char* yamlConfig =
    R"(
Flow Controller:
    name: MiNiFi Flow
    id: 2438e3c8-015a-1000-79ca-83af40ec1990
Processors:
  - name: Generator
    id: 2438e3c8-015a-1000-79ca-83af40ec1991
    class: org.apache.nifi.processors.standard.TestFlowFileGenerator
    max concurrent tasks: 1
    scheduling strategy: TIMER_DRIVEN
    scheduling period: 100 ms
    penalization period: 300 ms
    yield period: 100 ms
    run duration nanos: 0
    auto-terminated relationships list:
    Properties:
      Batch Size: 3
  - name: TestProcessor
    id: 2438e3c8-015a-1000-79ca-83af40ec1992
    class: org.apache.nifi.processors.standard.TestProcessor
    max concurrent tasks: 1
    scheduling strategy: TIMER_DRIVEN
    scheduling period: 100 ms
    penalization period: 3 sec
    yield period: 1 sec
    run duration nanos: 0
    auto-terminated relationships list:
      - apple
      - banana
Connections:
  - name: Gen
    id: 2438e3c8-015a-1000-79ca-83af40ec1997
    source name: Generator
    source id: 2438e3c8-015a-1000-79ca-83af40ec1991
    source relationship name: success
    destination name: TestProcessor
    destination id: 2438e3c8-015a-1000-79ca-83af40ec1992
    max work queue size: 0
    max work queue data size: 1 MB
    flowfile expiration: 60 sec
Remote Processing Groups:

Controller Services:
  - name: defaultstatemanagerprovider
    id: 2438e3c8-015a-1000-79ca-83af40ec1995
    class: UnorderedMapPersistableKeyValueStoreService
    Properties:
      Auto Persistence Interval:
          - value: 0 sec
      File:
          - value: flowcontrollertests_state.txt
)";

template<typename Fn>
bool verifyWithBusyWait(std::chrono::milliseconds timeout, Fn&& fn) {
  auto start = std::chrono::steady_clock::now();
  while (std::chrono::steady_clock::now() - start < timeout) {
    if (fn()) {
      return true;
    }
  }
  return false;
}

TEST_CASE("Flow shutdown drains connections", "[TestFlow1]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, "100 ms");

  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));
  // prevent execution of the consumer processor
  sinkProc->yield(10000);

  std::map<std::string, std::shared_ptr<minifi::Connection>> connectionMap;

  root->getConnections(connectionMap);
  // adds the single connection to the map both by name and id
  REQUIRE(connectionMap.size() == 2);

  testController.startFlow();

  // wait for the generator to create some files
  std::this_thread::sleep_for(std::chrono::milliseconds{1000});

  for (auto& it : connectionMap) {
    REQUIRE(it.second->getQueueSize() > 10);
  }

  controller->stop();

  REQUIRE(sinkProc->trigger_count == 0);

  for (auto& it : connectionMap) {
    REQUIRE(it.second->isEmpty());
  }
}

TEST_CASE("Flow shutdown waits for a while", "[TestFlow2]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, "10 s");

  auto sourceProc = std::static_pointer_cast<minifi::processors::TestFlowFileGenerator>(root->findProcessorByName("Generator"));
  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));

  std::promise<void> execSinkPromise;
  std::future<void> execSinkFuture = execSinkPromise.get_future();
  sinkProc->onTriggerCb_ = [&] {
    execSinkFuture.wait();
  };

  testController.startFlow();

  // wait for the source processor to enqueue its flowFiles
  auto flowFilesEnqueued = [&] { return root->getTotalFlowFileCount() >= 3; };
  REQUIRE(verifyWithBusyWait(std::chrono::milliseconds{500}, flowFilesEnqueued));

  REQUIRE(sourceProc->trigger_count.load() >= 1);

  execSinkPromise.set_value();
  controller->stop();

  REQUIRE(sourceProc->trigger_count.load() >= 1);
  REQUIRE(sinkProc->trigger_count.load() >= 3);
}

TEST_CASE("Flow stopped after grace period", "[TestFlow3]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, "1000 ms");

  auto sourceProc = std::static_pointer_cast<minifi::processors::TestFlowFileGenerator>(root->findProcessorByName("Generator"));
  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));

  std::promise<void> execSinkPromise;
  std::future<void> execSinkFuture = execSinkPromise.get_future();
  sinkProc->onTriggerCb_ = [&]{
    execSinkFuture.wait();
    static std::atomic<bool> first_onTrigger{true};
    bool isFirst = true;
    // sleep only on the first trigger
    if (first_onTrigger.compare_exchange_strong(isFirst, false)) {
      std::this_thread::sleep_for(std::chrono::milliseconds{1500});
    }
  };

  testController.startFlow();

  // wait for the source processor to enqueue its flowFiles
  auto flowFilesEnqueued = [&] { return root->getTotalFlowFileCount() >= 3; };
  REQUIRE(verifyWithBusyWait(std::chrono::milliseconds{500}, flowFilesEnqueued));

  REQUIRE(sourceProc->trigger_count.load() >= 1);

  execSinkPromise.set_value();
  controller->stop();

  REQUIRE(sourceProc->trigger_count.load() >= 1);
  REQUIRE(sinkProc->trigger_count.load() >= 1);
}

TEST_CASE("Extend the waiting period during shutdown", "[TestFlow4]") {
  TestControllerWithFlow testController(yamlConfig);
  auto controller = testController.controller_;
  auto root = testController.root_;

  unsigned int timeout_ms = 1000;

  testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, std::to_string(timeout_ms) + " ms");

  auto sourceProc = std::static_pointer_cast<minifi::processors::TestFlowFileGenerator>(root->findProcessorByName("Generator"));
  auto sinkProc = std::static_pointer_cast<minifi::processors::TestProcessor>(root->findProcessorByName("TestProcessor"));

  std::promise<void> execSinkPromise;
  std::future<void> execSinkFuture = execSinkPromise.get_future();
  sinkProc->onTriggerCb_ = [&]{
    execSinkFuture.wait();
    static std::atomic<bool> first_onTrigger{true};
    bool isFirst = true;
    // sleep only on the first trigger
    if (first_onTrigger.compare_exchange_strong(isFirst, false)) {
      std::this_thread::sleep_for(std::chrono::milliseconds{1500});
    }
  };

  testController.startFlow();

  // wait for the source processor to enqueue its flowFiles
  std::size_t flow_file_count = 0;
  auto flowFilesEnqueued = [&] { return root->getTotalFlowFileCount() >= 3; };
  REQUIRE(verifyWithBusyWait(std::chrono::milliseconds{500}, flowFilesEnqueued));

  REQUIRE(sourceProc->trigger_count.load() >= 1);

  std::thread shutdownThread([&]{
    execSinkPromise.set_value();
    controller->stop();
  });

  auto shutdownInitiated = std::chrono::steady_clock::now();
  auto shutdownDuration = [&] {return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - shutdownInitiated);};

  std::this_thread::sleep_for(std::chrono::milliseconds{500});
  while (shutdownDuration() < std::chrono::milliseconds(5000) && controller->isRunning()) {
    timeout_ms += 500;
    testController.getLogger()->log_info("Controller still running after %u ms, extending the waiting period to %u ms, ff count: %u",
        static_cast<unsigned int>(shutdownDuration().count()), timeout_ms, static_cast<unsigned int>(root->getTotalFlowFileCount()));
    testController.configuration_->set(minifi::Configure::nifi_flowcontroller_drain_timeout, std::to_string(timeout_ms) + " ms");
    std::this_thread::sleep_for(std::chrono::milliseconds{500});
  }

  REQUIRE(!controller->isRunning());
  REQUIRE(shutdownDuration().count() > 1500);

  shutdownThread.join();

  REQUIRE(sourceProc->trigger_count.load() >= 1);
  REQUIRE(sinkProc->trigger_count.load() >= 3);
}
<|endoftext|>


<commit_before>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2014 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: litecompleter.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "litecompleter.h"
#include "codecompleter.h"

#include <QCompleter>
#include <QPlainTextEdit>
#include <QTextCursor>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QAbstractItemView>
#include <QScrollBar>
#include <QTextBlock>
#include <QTimer>
#include <QDebug>
//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

class WordItem : public QStandardItem
{
public:
    WordItem(const QString &text) : QStandardItem(text)
    {
    }
    enum {
        KindRole = Qt::UserRole+2,
        TempRole
    };
    void setKind(const QString &kind)
    {
        this->setData(kind,KindRole);
    }
    QString kind() const
    {
        return QStandardItem::data(KindRole).toString();
    }
    void setTemp(bool temp)
    {
        this->setData(temp,TempRole);
    }
    bool isTemp() const
    {
        return QStandardItem::data(TempRole).toBool();
    }
};

LiteCompleter::LiteCompleter(QObject *parent) :
    LiteApi::ICompleter(parent),
    m_completer( new CodeCompleterEx(this)),
    m_model(new QStandardItemModel(this)),
    m_bSearchSeparator(true),
    m_bExternalMode(false)
{
    m_completer->setModel(m_model);
    m_completer->setCaseSensitivity(Qt::CaseSensitive);
    m_completer->setSeparator(".");
    m_stop = '(';
    QObject::connect(m_completer, SIGNAL(activated(QModelIndex)),
                     this, SLOT(insertCompletion(QModelIndex)));
}

LiteCompleter::~LiteCompleter()
{
    delete m_completer;
    delete m_model;
}

void LiteCompleter::setEditor(QPlainTextEdit *editor)
{
    m_editor = editor;
    m_completer->setWidget(m_editor);
}

QStandardItem *LiteCompleter::findRoot(const QString &name)
{
    QStringList words = name.split(m_completer->separator(),QString::SkipEmptyParts);
    WordItem *root = 0;
    WordItem *item = 0;
    foreach (QString word, words) {
        item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        for (int i = 0; i < m_model->rowCount(parent); i++) {
            QModelIndex index = m_model->index(i,0,parent);
            if (index.data().toString() == word) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        if (item == 0) {
            item = new WordItem(word);
            if (root == 0) {
                m_model->appendRow(item);
            } else {
                root->appendRow(item);
            }
        }
        root = item;
    }
    return root;
}

void LiteCompleter::clearChildItem(QStandardItem *root)
{
    if (root) {
        QModelIndex index = m_model->indexFromItem(root);
        m_model->removeRows(0,m_model->rowCount(index),index);
    }
}

void LiteCompleter::appendChildItem(QStandardItem *root, QString name, const QString &kind, const QString &info, const QIcon &icon, bool temp)
{
    if (root == 0) {
        WordItem *item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        int count = m_model->rowCount(parent);
        while(count--) {
            QModelIndex index = m_model->index(count,0,parent);
            if (index.data().toString() == name) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        if (item == 0) {
            item = new WordItem(name);
            if (root == 0) {
                m_model->appendRow(item);
            } else {
                root->appendRow(item);
            }
        }
        if (item && item->kind().isEmpty()) {
            item->setKind(kind);
            item->setToolTip(info);
            item->setTemp(temp);
            item->setIcon(icon);
        }
   } else {
        WordItem *item = new WordItem(name);
        root->appendRow(item);
        item->setKind(kind);
        item->setToolTip(info);
        item->setTemp(temp);
        item->setIcon(icon);
    }
}

void LiteCompleter::clear()
{
    m_model->clear();
}

static void clearTempIndex(QStandardItemModel *model, QModelIndex parent) {
    int i = model->rowCount(parent);
    while (i--) {
        QModelIndex index = model->index(i,0,parent);
        if (index.data(WordItem::TempRole).toBool() == true) {
            model->removeRow(i,parent);
        } else {
            clearTempIndex(model,index);
        }
    }
}

void LiteCompleter::clearTemp()
{
    clearTempIndex(m_model,QModelIndex());
}

void LiteCompleter::showPopup()
{
    if (!m_editor) {
        return;
    }
    m_completer->model()->sort(0);
    m_completer->popup()->setCurrentIndex(m_completer->completionModel()->index(0, 0));
    QTextCursor cursor = m_editor->textCursor();
    int offset = m_completer->completionPrefix().length();
    int pos = m_completer->completionPrefix().indexOf(".");
    if (pos != -1) {
        offset -= pos+1;
    }
    cursor.movePosition(QTextCursor::Left,QTextCursor::MoveAnchor,offset);
    QRect cr = m_editor->cursorRect(cursor);
    cr.setLeft(cr.left()+m_editor->viewport()->x()-24);
    cr.setWidth(m_completer->popup()->sizeHintForColumn(0)
                + m_completer->popup()->verticalScrollBar()->sizeHint().width());
    m_completer->complete(cr); // popup it up!
}

void LiteCompleter::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
{
    m_completer->setCaseSensitivity(caseSensitivity);
}

void LiteCompleter::setCompletionPrefix(const QString &prefix)
{
    m_completer->setCompletionPrefix(prefix);
}

QString LiteCompleter::completionPrefix() const
{
    return m_completer->completionPrefix();
}

QAbstractItemView *LiteCompleter::popup() const
{
    return m_completer->popup();
}

QModelIndex LiteCompleter::currentIndex() const
{
    return m_completer->currentIndex();
}

QString LiteCompleter::currentCompletion() const
{
    return m_completer->currentCompletion();
}

QAbstractItemModel *LiteCompleter::model() const
{
    return m_model;
}

QAbstractItemModel *LiteCompleter::completionModel() const
{
    return m_completer->completionModel();
}

bool LiteCompleter::startCompleter(const QString &completionPrefix)
{
    if (completionPrefix != this->completionPrefix()) {
        this->setCompletionPrefix(completionPrefix);
        this->popup()->setCurrentIndex(this->completionModel()->index(0, 0));
    }
    if (!completionPrefix.isEmpty() && this->currentCompletion() == completionPrefix) {
        this->popup()->hide();
        return false;
    }
    this->showPopup();
    return true;
}

void LiteCompleter::updateCompleterModel()
{
    this->m_completer->updateFilter();
}

void LiteCompleter::setSearchSeparator(bool b)
{
    m_bSearchSeparator = b;
}

bool LiteCompleter::searchSeparator() const
{
    return m_bSearchSeparator;
}

bool LiteCompleter::externalMode() const
{
    return m_bExternalMode;
}

void LiteCompleter::setExternalMode(bool b)
{
    m_bExternalMode = b;
}

void LiteCompleter::appendItems(QStringList items,const QString &kind, const QString &info,const QIcon &icon, bool temp)
{
    foreach(QString item,items) {
        appendItemEx(item,kind,info,icon,temp);
    }
}

bool LiteCompleter::appendItem(const QString &name, const QIcon &icon, bool temp)
{
    QString func;
    int pos = name.indexOf(m_stop);
    if (pos == -1) {
        func = name.trimmed();
    } else {
        func = name.left(pos).trimmed();
        //arg = text.right(text.length()-pos).trimmed();
    }
    return this->appendItemEx(func,"","",icon,temp);
}

void LiteCompleter::clearItemChilds(const QString &name)
{
    QStringList words = name.split(m_completer->separator(),QString::SkipEmptyParts);
    WordItem *root = 0;
    WordItem *item = 0;
    foreach (QString word, words) {
        item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        int count = m_model->rowCount(parent);
        while(count--) {
            QModelIndex index = m_model->index(count,0,parent);
            if (index.data().toString() == word) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        root = item;
    }
    if (item) {
        QModelIndex index = m_model->indexFromItem(item);
        m_model->removeRows(0,m_model->rowCount(index),index);
    }
}

bool LiteCompleter::appendItemEx(const QString &name,const QString &kind, const QString &info, const QIcon &icon, bool temp)
{
    QStringList words = name.split(m_completer->separator(),QString::SkipEmptyParts);

    WordItem *root = 0;
    WordItem *item = 0;
    bool bnew = false;
    foreach (QString word, words) {
        item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        for (int i = 0; i < m_model->rowCount(parent); i++) {
            QModelIndex index = m_model->index(i,0,parent);
            if (index.data().toString() == word) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        if (item == 0) {
            item = new WordItem(word);
            if (root == 0) {
                m_model->appendRow(item);
            } else {
                root->appendRow(item);
            }
            bnew = true;
        }
        root = item;
    }
    if (item && item->kind().isEmpty()) {
        item->setKind(kind);
        item->setToolTip(info);
        item->setTemp(temp);
        item->setIcon(icon);
    }
    return bnew;
}

void LiteCompleter::completionPrefixChanged(QString prefix, bool force)
{
    if (!m_editor) {
        return;
    }
    if (m_completer->widget() != m_editor) {
        return;
    }
    emit prefixChanged(m_editor->textCursor(),prefix, force);
}

void LiteCompleter::insertCompletion(QModelIndex index)
{
    if (!m_editor) {
        return;
    }
    if (m_completer->widget() != m_editor)
        return;
    if (!index.isValid()) {
        return;
    }

    QString text = index.data().toString();
    QString kind = index.data(WordItem::KindRole).toString();
    QString info = index.data(Qt::ToolTipRole).toString();
    QString prefix = m_completer->completionPrefix();
    //IsAbs r.URL.
    int pos = prefix.lastIndexOf(m_completer->separator());
    int length = prefix.length();
    if (pos != -1) {
        length = prefix.length()-pos-1;
    }
    QString extra = text;
    QString wordText = text;
    QTextCursor tc = m_editor->textCursor();
    tc.beginEditBlock();
    if (m_completer->caseSensitivity() == Qt::CaseSensitive) {
        extra = text.right(text.length()-length);
        wordText = prefix+extra;
    } else {
        while (length--) {
            tc.deletePreviousChar();
        }
        extra = text;
        wordText = text;
    }

    if (kind == "func" && tc.block().text().at(tc.positionInBlock()-1) != '(') {
        extra += "()";
        tc.insertText(extra);
        if (!info.startsWith("func()")) {
            tc.movePosition(QTextCursor::Left,QTextCursor::MoveAnchor,1);
        }
    } else {
        tc.insertText(extra);
    }
    tc.endEditBlock();
    m_editor->setTextCursor(tc);
    emit wordCompleted(wordText,kind,info);
}
<commit_msg>fix completer case<commit_after>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2014 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: litecompleter.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "litecompleter.h"
#include "codecompleter.h"

#include <QCompleter>
#include <QPlainTextEdit>
#include <QTextCursor>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QAbstractItemView>
#include <QScrollBar>
#include <QTextBlock>
#include <QTimer>
#include <QDebug>
//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

class WordItem : public QStandardItem
{
public:
    WordItem(const QString &text) : QStandardItem(text)
    {
    }
    enum {
        KindRole = Qt::UserRole+2,
        TempRole
    };
    void setKind(const QString &kind)
    {
        this->setData(kind,KindRole);
    }
    QString kind() const
    {
        return QStandardItem::data(KindRole).toString();
    }
    void setTemp(bool temp)
    {
        this->setData(temp,TempRole);
    }
    bool isTemp() const
    {
        return QStandardItem::data(TempRole).toBool();
    }
};

LiteCompleter::LiteCompleter(QObject *parent) :
    LiteApi::ICompleter(parent),
    m_completer( new CodeCompleterEx(this)),
    m_model(new QStandardItemModel(this)),
    m_bSearchSeparator(true),
    m_bExternalMode(false)
{
    m_completer->setModel(m_model);
    m_completer->setCaseSensitivity(Qt::CaseSensitive);
    m_completer->setSeparator(".");
    m_stop = '(';
    QObject::connect(m_completer, SIGNAL(activated(QModelIndex)),
                     this, SLOT(insertCompletion(QModelIndex)));
}

LiteCompleter::~LiteCompleter()
{
    delete m_completer;
    delete m_model;
}

void LiteCompleter::setEditor(QPlainTextEdit *editor)
{
    m_editor = editor;
    m_completer->setWidget(m_editor);
}

QStandardItem *LiteCompleter::findRoot(const QString &name)
{
    QStringList words = name.split(m_completer->separator(),QString::SkipEmptyParts);
    WordItem *root = 0;
    WordItem *item = 0;
    foreach (QString word, words) {
        item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        for (int i = 0; i < m_model->rowCount(parent); i++) {
            QModelIndex index = m_model->index(i,0,parent);
            if (index.data().toString() == word) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        if (item == 0) {
            item = new WordItem(word);
            if (root == 0) {
                m_model->appendRow(item);
            } else {
                root->appendRow(item);
            }
        }
        root = item;
    }
    return root;
}

void LiteCompleter::clearChildItem(QStandardItem *root)
{
    if (root) {
        QModelIndex index = m_model->indexFromItem(root);
        m_model->removeRows(0,m_model->rowCount(index),index);
    }
}

void LiteCompleter::appendChildItem(QStandardItem *root, QString name, const QString &kind, const QString &info, const QIcon &icon, bool temp)
{
    if (root == 0) {
        WordItem *item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        int count = m_model->rowCount(parent);
        while(count--) {
            QModelIndex index = m_model->index(count,0,parent);
            if (index.data().toString() == name) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        if (item == 0) {
            item = new WordItem(name);
            if (root == 0) {
                m_model->appendRow(item);
            } else {
                root->appendRow(item);
            }
        }
        if (item && item->kind().isEmpty()) {
            item->setKind(kind);
            item->setToolTip(info);
            item->setTemp(temp);
            item->setIcon(icon);
        }
   } else {
        WordItem *item = new WordItem(name);
        root->appendRow(item);
        item->setKind(kind);
        item->setToolTip(info);
        item->setTemp(temp);
        item->setIcon(icon);
    }
}

void LiteCompleter::clear()
{
    m_model->clear();
}

static void clearTempIndex(QStandardItemModel *model, QModelIndex parent) {
    int i = model->rowCount(parent);
    while (i--) {
        QModelIndex index = model->index(i,0,parent);
        if (index.data(WordItem::TempRole).toBool() == true) {
            model->removeRow(i,parent);
        } else {
            clearTempIndex(model,index);
        }
    }
}

void LiteCompleter::clearTemp()
{
    clearTempIndex(m_model,QModelIndex());
}

void LiteCompleter::showPopup()
{
    if (!m_editor) {
        return;
    }
    m_completer->model()->sort(0);
    m_completer->popup()->setCurrentIndex(m_completer->completionModel()->index(0, 0));
    QTextCursor cursor = m_editor->textCursor();
    int offset = m_completer->completionPrefix().length();
    int pos = m_completer->completionPrefix().indexOf(".");
    if (pos != -1) {
        offset -= pos+1;
    }
    cursor.movePosition(QTextCursor::Left,QTextCursor::MoveAnchor,offset);
    QRect cr = m_editor->cursorRect(cursor);
    cr.setLeft(cr.left()+m_editor->viewport()->x()-24);
    cr.setWidth(m_completer->popup()->sizeHintForColumn(0)
                + m_completer->popup()->verticalScrollBar()->sizeHint().width());
    m_completer->complete(cr); // popup it up!
}

void LiteCompleter::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
{
    m_completer->setCaseSensitivity(caseSensitivity);
}

void LiteCompleter::setCompletionPrefix(const QString &prefix)
{
    m_completer->setCompletionPrefix(prefix);
}

QString LiteCompleter::completionPrefix() const
{
    return m_completer->completionPrefix();
}

QAbstractItemView *LiteCompleter::popup() const
{
    return m_completer->popup();
}

QModelIndex LiteCompleter::currentIndex() const
{
    return m_completer->currentIndex();
}

QString LiteCompleter::currentCompletion() const
{
    return m_completer->currentCompletion();
}

QAbstractItemModel *LiteCompleter::model() const
{
    return m_model;
}

QAbstractItemModel *LiteCompleter::completionModel() const
{
    return m_completer->completionModel();
}

bool LiteCompleter::startCompleter(const QString &completionPrefix)
{
    if (completionPrefix != this->completionPrefix()) {
        this->setCompletionPrefix(completionPrefix);
        this->popup()->setCurrentIndex(this->completionModel()->index(0, 0));
    }
    if (!completionPrefix.isEmpty() && this->currentCompletion() == completionPrefix) {
        this->popup()->hide();
        return false;
    }
    this->showPopup();
    return true;
}

void LiteCompleter::updateCompleterModel()
{
    this->m_completer->updateFilter();
}

void LiteCompleter::setSearchSeparator(bool b)
{
    m_bSearchSeparator = b;
}

bool LiteCompleter::searchSeparator() const
{
    return m_bSearchSeparator;
}

bool LiteCompleter::externalMode() const
{
    return m_bExternalMode;
}

void LiteCompleter::setExternalMode(bool b)
{
    m_bExternalMode = b;
}

void LiteCompleter::appendItems(QStringList items,const QString &kind, const QString &info,const QIcon &icon, bool temp)
{
    foreach(QString item,items) {
        appendItemEx(item,kind,info,icon,temp);
    }
}

bool LiteCompleter::appendItem(const QString &name, const QIcon &icon, bool temp)
{
    QString func;
    int pos = name.indexOf(m_stop);
    if (pos == -1) {
        func = name.trimmed();
    } else {
        func = name.left(pos).trimmed();
        //arg = text.right(text.length()-pos).trimmed();
    }
    return this->appendItemEx(func,"","",icon,temp);
}

void LiteCompleter::clearItemChilds(const QString &name)
{
    QStringList words = name.split(m_completer->separator(),QString::SkipEmptyParts);
    WordItem *root = 0;
    WordItem *item = 0;
    foreach (QString word, words) {
        item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        int count = m_model->rowCount(parent);
        while(count--) {
            QModelIndex index = m_model->index(count,0,parent);
            if (index.data().toString() == word) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        root = item;
    }
    if (item) {
        QModelIndex index = m_model->indexFromItem(item);
        m_model->removeRows(0,m_model->rowCount(index),index);
    }
}

bool LiteCompleter::appendItemEx(const QString &name,const QString &kind, const QString &info, const QIcon &icon, bool temp)
{
    QStringList words = name.split(m_completer->separator(),QString::SkipEmptyParts);

    WordItem *root = 0;
    WordItem *item = 0;
    bool bnew = false;
    foreach (QString word, words) {
        item = 0;
        QModelIndex parent = m_model->indexFromItem(root);
        for (int i = 0; i < m_model->rowCount(parent); i++) {
            QModelIndex index = m_model->index(i,0,parent);
            if (index.data().toString() == word) {
                item = static_cast<WordItem*>(m_model->itemFromIndex(index));
                break;
            }
        }
        if (item == 0) {
            item = new WordItem(word);
            if (root == 0) {
                m_model->appendRow(item);
            } else {
                root->appendRow(item);
            }
            bnew = true;
        }
        root = item;
    }
    if (item && item->kind().isEmpty()) {
        item->setKind(kind);
        item->setToolTip(info);
        item->setTemp(temp);
        item->setIcon(icon);
    }
    return bnew;
}

void LiteCompleter::completionPrefixChanged(QString prefix, bool force)
{
    if (!m_editor) {
        return;
    }
    if (m_completer->widget() != m_editor) {
        return;
    }
    emit prefixChanged(m_editor->textCursor(),prefix, force);
}

void LiteCompleter::insertCompletion(QModelIndex index)
{
    if (!m_editor) {
        return;
    }
    if (m_completer->widget() != m_editor)
        return;
    if (!index.isValid()) {
        return;
    }

    QString text = index.data().toString();
    QString kind = index.data(WordItem::KindRole).toString();
    QString info = index.data(Qt::ToolTipRole).toString();
    QString prefix = m_completer->completionPrefix();
    //IsAbs r.URL.
    int pos = prefix.lastIndexOf(m_completer->separator());
    int length = prefix.length();
    if (pos != -1) {
        length = prefix.length()-pos-1;
    }
    QString extra = text;
    QString wordText = text;
    QTextCursor tc = m_editor->textCursor();
    tc.beginEditBlock();
//    if (m_completer->caseSensitivity() == Qt::CaseSensitive) {
//        extra = text.right(text.length()-length);
//        wordText = prefix+extra;
//    } else {
        while (length--) {
            tc.deletePreviousChar();
        }
        extra = text;
        wordText = text;
//    }

    if (kind == "func" && tc.block().text().at(tc.positionInBlock()-1) != '(') {
        extra += "()";
        tc.insertText(extra);
        if (!info.startsWith("func()")) {
            tc.movePosition(QTextCursor::Left,QTextCursor::MoveAnchor,1);
        }
    } else {
        tc.insertText(extra);
    }
    tc.endEditBlock();
    m_editor->setTextCursor(tc);
    emit wordCompleted(wordText,kind,info);
}
<|endoftext|>


<commit_before>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2014 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: filesystemmodel.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "filesystemmodel.h"

#include <QFileInfo>
#include <QDir>
#include <QIcon>
#include <QFont>
#include <QFileIconProvider>
#include <QFileSystemWatcher>
#include <QDebug>
//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

FileNode::FileNode(FileSystemModel *model) :
    m_model(model),
    m_parent(0),
    m_children(0)
{

}

FileNode::FileNode(FileSystemModel *model, const QString &path, FileNode *parent) :
    m_model(model),
    m_parent(parent),
    m_children(0),
    m_path(path)
{
    QFileInfo info(path);
    if (m_model->isRootPathNodeFillPath() && parent && parent->parent() == 0) {
        m_text = QDir::toNativeSeparators(info.filePath());
    } else {
        m_text = info.fileName();
    }
    if (info.isDir() && !m_path.isEmpty()) {
        m_model->fileWatcher()->addPath(m_path);
    }
}

FileNode::~FileNode()
{
    if (this->isDir() && !m_path.isEmpty())  {
        m_model->fileWatcher()->removePath(m_path);
    }
    if (m_children) {
        qDeleteAll(m_children->begin(),m_children->end());
        delete m_children;
    }
}

QList<FileNode*>* FileNode::children()
{
    if (m_children == 0) {
        m_children = new QList<FileNode*>();
        if (!m_path.isEmpty()) {
            QFileInfo info(m_path);
            if (info.isDir()) {
                QDir dir(m_path);
                foreach(QFileInfo childInfo, dir.entryInfoList(this->m_model->filter(),this->m_model->sort())) {
                    if (!this->m_model->isShowHideFiles() && childInfo.isDir() && childInfo.fileName().startsWith(".")) {
                       continue;
                    }
                    m_children->append(new FileNode(this->m_model,childInfo.filePath(),this));
                }
            }
        }
    }
    return m_children;
}

FileNode* FileNode::parent()
{
    return m_parent;
}

FileNode* FileNode::child(int row)
{
    return children()->at(row);
}

int FileNode::childCount()
{
    return children()->count();
}

int FileNode::row() const
{
    if (m_parent) {
        return m_parent->children()->indexOf(const_cast<FileNode*>(this));
    }
    return 0;
}

QString FileNode::path() const
{
    return m_path;
}

QString FileNode::text() const
{
    return m_text;
}

bool FileNode::isDir() const
{
    return QFileInfo(m_path).isDir();
}

bool FileNode::isFile() const
{
    return QFileInfo(m_path).isFile();
}

QFileInfo FileNode::fileInfo() const
{
    return QFileInfo(m_path);
}

bool FileNode::isExist() const
{
    return QFileInfo(m_path).exists();
}

void FileNode::clear()
{
    if (m_children) {
        qDeleteAll(m_children->begin(),m_children->end());
        m_children->clear();
    }
}

void FileNode::reload()
{
    clear();
    if (m_children == 0) {
        m_children = new QList<FileNode*>();
    }
    if (!m_path.isEmpty()) {
        QFileInfo info(m_path);
        if (info.isDir()) {
            QDir dir(m_path);
            foreach(QFileInfo childInfo, dir.entryInfoList(this->m_model->filter(),this->m_model->sort())) {
                if (!this->m_model->isShowHideFiles() && childInfo.isDir() && childInfo.fileName().startsWith(".")) {
                   continue;
                }
                m_children->append(new FileNode(this->m_model,childInfo.filePath(),this));
            }
        }
    }
}

FileNode *FileNode::findPath(const QString &path)
{
    if (!path.startsWith(m_path)) {
        return 0;
    }
    if (path == m_path) {
        return this;
    }
    QStringList nameList = path.right(path.length()-m_path.length()).split("/",QString::SkipEmptyParts);
    FileNode *parent = this;
    bool find = false;
    foreach (QString name,nameList) {
        find = false;
        QList<FileNode*>* chilren = parent->children();
        for (int i = 0; i < chilren->count(); i++) {
            FileNode *node = chilren->at(i);
            if (!node->isDir()) {
                continue;
            }
            if (node->m_text == name) {
                parent = node;
                find = true;
                break;
            }
        }
        if (!find) {
            return 0;
        }
    }
    return parent;
}

FileSystemModel::FileSystemModel(QObject *parent) :
    QAbstractItemModel(parent),
    m_rootNode(new FileNode(this)),
    m_iconProvider(new QFileIconProvider),
    m_fileWatcher(new QFileSystemWatcher(this))
{
    m_filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot;
    m_sorts = QDir::DirsFirst | QDir::Name | QDir::Type;
   // connect(m_fileWatcher,SIGNAL(directoryChanged(QString)),this,SLOT(directoryChanged(QString)));
}

FileSystemModel::~FileSystemModel()
{
    delete m_rootNode;
    delete m_iconProvider;
}

void FileSystemModel::directoryChanged(const QString &path)
{
    this->beginResetModel();
    QDir dir(path);
    bool b = dir.exists();
    if (!b) {
        m_fileWatcher->removePath(path);
    }

    foreach(QModelIndex index,this->findPaths(path)) {
        FileNode *node = nodeFromIndex(index);
        if (b) {
            node->reload();
        }
        else {
            FileNode *parent = node->parent();
            if (parent) {
                parent->reload();
            }
        }
    }
    this->endResetModel();
}

FileNode *FileSystemModel::nodeFromIndex(const QModelIndex &index) const
{
    if (index.isValid()) {
        return static_cast<FileNode*>(index.internalPointer());
    }
    return m_rootNode;
}

void FileSystemModel::setStartIndex(const QModelIndex &index)
{
    m_startPath = filePath(index);
}

void FileSystemModel::setStartPath(const QString &path)
{
    m_startPath = path;
}

QModelIndex FileSystemModel::startIndex() const
{
    return findPath(m_startPath);
}

QString FileSystemModel::startPath() const
{
    return m_startPath;
}

QString FileSystemModel::filePath(const QModelIndex &index) const
{
    return nodeFromIndex(index)->path();
}

void FileSystemModel::setFilter(QDir::Filters filters)
{
    if (m_filters != filters) {
        m_filters = filters;
        this->reload();
    }
}

void FileSystemModel::setSort(QDir::SortFlags flags)
{
    if (m_sorts != flags) {
        m_sorts = flags;
        this->reload();
    }
}

QDir::Filters FileSystemModel::filter() const
{
    return m_filters;
}

bool FileSystemModel::isShowHideFiles() const
{
    return m_filters & QDir::Hidden;
}

QDir::SortFlags FileSystemModel::sort() const
{
    return m_sorts;
}

void FileSystemModel::clear()
{
    this->beginResetModel();
    m_rootNode->clear();
    m_pathList.clear();
    m_startPath.clear();
    this->endResetModel();
}

void FileSystemModel::reload()
{
    this->setRootPathList(this->rootPathList());
}

void FileSystemModel::setRootPath(const QString &path)
{
    this->setRootPathList(QStringList() << path);
}

bool FileSystemModel::removeRootPath(const QString &path)
{
    QString pathName = QDir::fromNativeSeparators(path);
    FileNode *node = 0;
    int index = -1;
    for (int i = 0; i < m_rootNode->childCount(); i++) {
        node = m_rootNode->children()->at(i);
        if (node && node->path() == pathName) {
            index = i;
            break;
        }
    }
    if (index == -1) {
        return false;
    }
    if (!m_pathList.removeAll(pathName)) {
        return false;
    }
    this->beginRemoveRows(QModelIndex(),index,index);
    m_rootNode->children()->removeAt(index);
    delete node;
    this->endRemoveRows();
    return true;
}

bool FileSystemModel::addRootPath(const QString &path)
{
    QString pathName = QDir::fromNativeSeparators(path);
    if (m_pathList.contains(pathName)) {
        return false;
    }
    this->beginInsertRows(QModelIndex(),m_rootNode->childCount(),m_rootNode->childCount());
    m_pathList.append(pathName);
    m_rootNode->children()->append(new FileNode(this,pathName,m_rootNode));
    this->endInsertRows();
    return true;
}

void FileSystemModel::setRootPathList(const QStringList &pathList)
{
    this->beginResetModel();
    m_rootNode->clear();
    m_pathList.clear();
    foreach (QString path, pathList) {
        m_pathList.append(QDir::fromNativeSeparators(QDir::cleanPath(path)));
    }
    m_pathList.removeDuplicates();

    foreach(QString path, m_pathList) {
        m_rootNode->children()->append(new FileNode(this,path,m_rootNode));
    }

    if (m_startPath.isEmpty() && !pathList.isEmpty()) {
        m_startPath = pathList.first();
    }

    this->endResetModel();
}

QStringList FileSystemModel::rootPathList() const
{
    return m_pathList;
}

QModelIndex FileSystemModel::findPathHelper(const QString &path, const QModelIndex &parentIndex) const
{
    FileNode *node = nodeFromIndex(parentIndex);
    if (!path.startsWith(node->path())) {
        return QModelIndex();
    }
    if (path == node->path()) {
        return parentIndex;
    }
    QStringList nameList = path.right(path.length()-node->path().length()).split("/",QString::SkipEmptyParts);
    QModelIndex parent = parentIndex;
    bool find = false;
    int count = nameList.count();
    for (int i = 0; i < count; i++) {
        find = false;
        for (int j = 0; j < this->rowCount(parent); j++) {
            QModelIndex index = this->index(j,0,parent);
            FileNode *node = nodeFromIndex(index);
            if ( ( (i == count-1) || node->isDir()) && node->text() == nameList.at(i)) {
                parent = index;
                find = true;
                break;
            }
        }
        if (!find) {
            return QModelIndex();
        }
    }
    return parent;
}

QList<QModelIndex> FileSystemModel::findPaths(const QString &path) const
{
    QList<QModelIndex> list;
    QString cpath = QDir::fromNativeSeparators(QDir::cleanPath(path));
    for (int i = 0; i < this->rowCount(); i++) {
        QModelIndex find = findPathHelper(cpath,this->index(i,0));
        if (find.isValid()) {
            list.append(find);
        }
     }
    return list;
}

QModelIndex FileSystemModel::findPath(const QString &path) const
{
    QList<QModelIndex> list = this->findPaths(path);
    if (!list.isEmpty()) {
        return list.last();
    }
    return QModelIndex();
}

int FileSystemModel::rowCount(const QModelIndex &parent) const
{
    FileNode *node = nodeFromIndex(parent);
    return node->childCount();
}

int FileSystemModel::columnCount(const QModelIndex&) const
{
    return 1;
}

QModelIndex FileSystemModel::parent(const QModelIndex &child) const
{
    FileNode *node = nodeFromIndex(child);
    FileNode *parent = node->parent();
    if (parent == m_rootNode) {
        return QModelIndex();
    }
    return createIndex(parent->row(),0,parent);
}

QModelIndex FileSystemModel::index(int row, int column,const QModelIndex &parent) const
{
    if (!hasIndex(row,column,parent))
        return QModelIndex();
    FileNode *node = nodeFromIndex(parent);
    return createIndex(row,column,node->child(row));
}

QVariant FileSystemModel::data(const QModelIndex &index, int role) const
{
    FileNode *node = nodeFromIndex(index);
    if (!node) {
        return QVariant();
    }
    switch(role) {
    case Qt::DisplayRole:
        return node->text();
    case Qt::ToolTipRole:
        return QDir::toNativeSeparators(node->path());
    case Qt::DecorationRole:
        return m_iconProvider->icon(node->fileInfo());
/*
    case Qt::FontRole: {
        QFont font;
        if (node->path() == m_startPath) {
            font.setBold(true);
        }
        return font;
    }
*/
    }
    return QVariant();
}

QFileSystemWatcher* FileSystemModel::fileWatcher() const
{
    return m_fileWatcher;
}

bool FileSystemModel::isRootPathNode(FileNode *node) const
{
    return node->parent() == m_rootNode;
}

bool FileSystemModel::isRootPathNodeFillPath() const
{
    return false;
}
<commit_msg>filesystem clean path<commit_after>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2014 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: filesystemmodel.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "filesystemmodel.h"

#include <QFileInfo>
#include <QDir>
#include <QIcon>
#include <QFont>
#include <QFileIconProvider>
#include <QFileSystemWatcher>
#include <QDebug>
//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

FileNode::FileNode(FileSystemModel *model) :
    m_model(model),
    m_parent(0),
    m_children(0)
{

}

FileNode::FileNode(FileSystemModel *model, const QString &path, FileNode *parent) :
    m_model(model),
    m_parent(parent),
    m_children(0),
    m_path(path)
{
    QFileInfo info(path);
    if (m_model->isRootPathNodeFillPath() && parent && parent->parent() == 0) {
        m_text = QDir::toNativeSeparators(info.filePath());
    } else {
        m_text = info.fileName();
    }
    if (info.isDir() && !m_path.isEmpty()) {
        m_model->fileWatcher()->addPath(m_path);
    }
}

FileNode::~FileNode()
{
    if (this->isDir() && !m_path.isEmpty())  {
        m_model->fileWatcher()->removePath(m_path);
    }
    if (m_children) {
        qDeleteAll(m_children->begin(),m_children->end());
        delete m_children;
    }
}

QList<FileNode*>* FileNode::children()
{
    if (m_children == 0) {
        m_children = new QList<FileNode*>();
        if (!m_path.isEmpty()) {
            QFileInfo info(m_path);
            if (info.isDir()) {
                QDir dir(m_path);
                foreach(QFileInfo childInfo, dir.entryInfoList(this->m_model->filter(),this->m_model->sort())) {
                    if (!this->m_model->isShowHideFiles() && childInfo.isDir() && childInfo.fileName().startsWith(".")) {
                       continue;
                    }
                    m_children->append(new FileNode(this->m_model,childInfo.filePath(),this));
                }
            }
        }
    }
    return m_children;
}

FileNode* FileNode::parent()
{
    return m_parent;
}

FileNode* FileNode::child(int row)
{
    return children()->at(row);
}

int FileNode::childCount()
{
    return children()->count();
}

int FileNode::row() const
{
    if (m_parent) {
        return m_parent->children()->indexOf(const_cast<FileNode*>(this));
    }
    return 0;
}

QString FileNode::path() const
{
    return m_path;
}

QString FileNode::text() const
{
    return m_text;
}

bool FileNode::isDir() const
{
    return QFileInfo(m_path).isDir();
}

bool FileNode::isFile() const
{
    return QFileInfo(m_path).isFile();
}

QFileInfo FileNode::fileInfo() const
{
    return QFileInfo(m_path);
}

bool FileNode::isExist() const
{
    return QFileInfo(m_path).exists();
}

void FileNode::clear()
{
    if (m_children) {
        qDeleteAll(m_children->begin(),m_children->end());
        m_children->clear();
    }
}

void FileNode::reload()
{
    clear();
    if (m_children == 0) {
        m_children = new QList<FileNode*>();
    }
    if (!m_path.isEmpty()) {
        QFileInfo info(m_path);
        if (info.isDir()) {
            QDir dir(m_path);
            foreach(QFileInfo childInfo, dir.entryInfoList(this->m_model->filter(),this->m_model->sort())) {
                if (!this->m_model->isShowHideFiles() && childInfo.isDir() && childInfo.fileName().startsWith(".")) {
                   continue;
                }
                m_children->append(new FileNode(this->m_model,childInfo.filePath(),this));
            }
        }
    }
}

FileNode *FileNode::findPath(const QString &path)
{
    if (!path.startsWith(m_path)) {
        return 0;
    }
    if (path == m_path) {
        return this;
    }
    QStringList nameList = path.right(path.length()-m_path.length()).split("/",QString::SkipEmptyParts);
    FileNode *parent = this;
    bool find = false;
    foreach (QString name,nameList) {
        find = false;
        QList<FileNode*>* chilren = parent->children();
        for (int i = 0; i < chilren->count(); i++) {
            FileNode *node = chilren->at(i);
            if (!node->isDir()) {
                continue;
            }
            if (node->m_text == name) {
                parent = node;
                find = true;
                break;
            }
        }
        if (!find) {
            return 0;
        }
    }
    return parent;
}

FileSystemModel::FileSystemModel(QObject *parent) :
    QAbstractItemModel(parent),
    m_rootNode(new FileNode(this)),
    m_iconProvider(new QFileIconProvider),
    m_fileWatcher(new QFileSystemWatcher(this))
{
    m_filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot;
    m_sorts = QDir::DirsFirst | QDir::Name | QDir::Type;
   // connect(m_fileWatcher,SIGNAL(directoryChanged(QString)),this,SLOT(directoryChanged(QString)));
}

FileSystemModel::~FileSystemModel()
{
    delete m_rootNode;
    delete m_iconProvider;
}

void FileSystemModel::directoryChanged(const QString &path)
{
    this->beginResetModel();
    QDir dir(path);
    bool b = dir.exists();
    if (!b) {
        m_fileWatcher->removePath(path);
    }

    foreach(QModelIndex index,this->findPaths(path)) {
        FileNode *node = nodeFromIndex(index);
        if (b) {
            node->reload();
        }
        else {
            FileNode *parent = node->parent();
            if (parent) {
                parent->reload();
            }
        }
    }
    this->endResetModel();
}

FileNode *FileSystemModel::nodeFromIndex(const QModelIndex &index) const
{
    if (index.isValid()) {
        return static_cast<FileNode*>(index.internalPointer());
    }
    return m_rootNode;
}

void FileSystemModel::setStartIndex(const QModelIndex &index)
{
    m_startPath = filePath(index);
}

void FileSystemModel::setStartPath(const QString &path)
{
    m_startPath = path;
}

QModelIndex FileSystemModel::startIndex() const
{
    return findPath(m_startPath);
}

QString FileSystemModel::startPath() const
{
    return m_startPath;
}

QString FileSystemModel::filePath(const QModelIndex &index) const
{
    return nodeFromIndex(index)->path();
}

void FileSystemModel::setFilter(QDir::Filters filters)
{
    if (m_filters != filters) {
        m_filters = filters;
        this->reload();
    }
}

void FileSystemModel::setSort(QDir::SortFlags flags)
{
    if (m_sorts != flags) {
        m_sorts = flags;
        this->reload();
    }
}

QDir::Filters FileSystemModel::filter() const
{
    return m_filters;
}

bool FileSystemModel::isShowHideFiles() const
{
    return m_filters & QDir::Hidden;
}

QDir::SortFlags FileSystemModel::sort() const
{
    return m_sorts;
}

void FileSystemModel::clear()
{
    this->beginResetModel();
    m_rootNode->clear();
    m_pathList.clear();
    m_startPath.clear();
    this->endResetModel();
}

void FileSystemModel::reload()
{
    this->setRootPathList(this->rootPathList());
}

void FileSystemModel::setRootPath(const QString &path)
{
    this->setRootPathList(QStringList() << path);
}

bool FileSystemModel::removeRootPath(const QString &path)
{
    QString pathName = QDir::fromNativeSeparators(path);
    FileNode *node = 0;
    int index = -1;
    for (int i = 0; i < m_rootNode->childCount(); i++) {
        node = m_rootNode->children()->at(i);
        if (node && node->path() == pathName) {
            index = i;
            break;
        }
    }
    if (index == -1) {
        return false;
    }
    if (!m_pathList.removeAll(pathName)) {
        return false;
    }
    this->beginRemoveRows(QModelIndex(),index,index);
    m_rootNode->children()->removeAt(index);
    delete node;
    this->endRemoveRows();
    return true;
}

bool FileSystemModel::addRootPath(const QString &path)
{
    QString pathName = QDir::fromNativeSeparators(QDir::cleanPath(path));
    if (m_pathList.contains(pathName)) {
        return false;
    }
    this->beginInsertRows(QModelIndex(),m_rootNode->childCount(),m_rootNode->childCount());
    m_pathList.append(pathName);
    m_rootNode->children()->append(new FileNode(this,pathName,m_rootNode));
    this->endInsertRows();
    return true;
}

void FileSystemModel::setRootPathList(const QStringList &pathList)
{
    this->beginResetModel();
    m_rootNode->clear();
    m_pathList.clear();
    foreach (QString path, pathList) {
        m_pathList.append(QDir::fromNativeSeparators(QDir::cleanPath(path)));
    }
    m_pathList.removeDuplicates();

    foreach(QString path, m_pathList) {
        m_rootNode->children()->append(new FileNode(this,path,m_rootNode));
    }

    if (m_startPath.isEmpty() && !pathList.isEmpty()) {
        m_startPath = pathList.first();
    }

    this->endResetModel();
}

QStringList FileSystemModel::rootPathList() const
{
    return m_pathList;
}

QModelIndex FileSystemModel::findPathHelper(const QString &path, const QModelIndex &parentIndex) const
{
    FileNode *node = nodeFromIndex(parentIndex);
    if (!path.startsWith(node->path())) {
        return QModelIndex();
    }
    if (path == node->path()) {
        return parentIndex;
    }
    QStringList nameList = path.right(path.length()-node->path().length()).split("/",QString::SkipEmptyParts);
    QModelIndex parent = parentIndex;
    bool find = false;
    int count = nameList.count();
    for (int i = 0; i < count; i++) {
        find = false;
        for (int j = 0; j < this->rowCount(parent); j++) {
            QModelIndex index = this->index(j,0,parent);
            FileNode *node = nodeFromIndex(index);
            if ( ( (i == count-1) || node->isDir()) && node->text() == nameList.at(i)) {
                parent = index;
                find = true;
                break;
            }
        }
        if (!find) {
            return QModelIndex();
        }
    }
    return parent;
}

QList<QModelIndex> FileSystemModel::findPaths(const QString &path) const
{
    QList<QModelIndex> list;
    QString cpath = QDir::fromNativeSeparators(QDir::cleanPath(path));
    for (int i = 0; i < this->rowCount(); i++) {
        QModelIndex find = findPathHelper(cpath,this->index(i,0));
        if (find.isValid()) {
            list.append(find);
        }
     }
    return list;
}

QModelIndex FileSystemModel::findPath(const QString &path) const
{
    QList<QModelIndex> list = this->findPaths(path);
    if (!list.isEmpty()) {
        return list.last();
    }
    return QModelIndex();
}

int FileSystemModel::rowCount(const QModelIndex &parent) const
{
    FileNode *node = nodeFromIndex(parent);
    return node->childCount();
}

int FileSystemModel::columnCount(const QModelIndex&) const
{
    return 1;
}

QModelIndex FileSystemModel::parent(const QModelIndex &child) const
{
    FileNode *node = nodeFromIndex(child);
    FileNode *parent = node->parent();
    if (parent == m_rootNode) {
        return QModelIndex();
    }
    return createIndex(parent->row(),0,parent);
}

QModelIndex FileSystemModel::index(int row, int column,const QModelIndex &parent) const
{
    if (!hasIndex(row,column,parent))
        return QModelIndex();
    FileNode *node = nodeFromIndex(parent);
    return createIndex(row,column,node->child(row));
}

QVariant FileSystemModel::data(const QModelIndex &index, int role) const
{
    FileNode *node = nodeFromIndex(index);
    if (!node) {
        return QVariant();
    }
    switch(role) {
    case Qt::DisplayRole:
        return node->text();
    case Qt::ToolTipRole:
        return QDir::toNativeSeparators(node->path());
    case Qt::DecorationRole:
        return m_iconProvider->icon(node->fileInfo());
/*
    case Qt::FontRole: {
        QFont font;
        if (node->path() == m_startPath) {
            font.setBold(true);
        }
        return font;
    }
*/
    }
    return QVariant();
}

QFileSystemWatcher* FileSystemModel::fileWatcher() const
{
    return m_fileWatcher;
}

bool FileSystemModel::isRootPathNode(FileNode *node) const
{
    return node->parent() == m_rootNode;
}

bool FileSystemModel::isRootPathNodeFillPath() const
{
    return false;
}
<|endoftext|>


<commit_before>/*
 * adds pose information given by pose_000x.txt into cloud_000x.pcd files (old dataset structure)
 * now we can use pcl_viewer *.pcd to show all point clouds in common coordinate system
 *
 *  Created on: Dec 04, 2014
 *      Author: Thomas Faeulhammer
 *
 */

#include <v4r/io/filesystem.h>
#include <v4r/io/eigen.h>
#include <v4r/common/faat_3d_rec_framework_defines.h>
#include <v4r/common/miscellaneous.h>
#include <pcl/common/transforms.h>
#include <pcl/console/parse.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>
#include <glog/logging.h>

namespace po = boost::program_options;

typedef pcl::PointXYZRGB PointT;

int main (int argc, char ** argv)
{
    std::string input_dir, out_dir = "/tmp/clouds_with_pose/";
    std::string cloud_prefix = "cloud_", pose_prefix = "pose_", indices_prefix = "object_indices_";
    bool invert_pose = false;
    bool use_indices = false;
    po::options_description desc("Save camera pose given by seperate pose file directly into header of .pcd file\n======================================\n**Allowed options");
    desc.add_options()
            ("help,h", "produce help message")
            ("input_dir,i", po::value<std::string>(&input_dir)->required(), "directory containing both .pcd and pose files")
            ("output_dir,o", po::value<std::string>(&out_dir)->default_value(out_dir), "output directory")
            ("use_indices,u", po::bool_switch(&use_indices), "if true, uses indices")
            ("invert_pose,t", po::bool_switch(&invert_pose), "if true, takes the inverse of the pose file (e.g. required for Willow Dataset)")
            ("cloud_prefix,c", po::value<std::string>(&cloud_prefix)->default_value(cloud_prefix), "prefix of cloud names")
            ("pose_prefix,p", po::value<std::string>(&pose_prefix)->default_value(pose_prefix), "prefix of camera pose names (e.g. transformation_)")
            ("indices_prefix,d", po::value<std::string>(&indices_prefix)->default_value(indices_prefix), "prefix of object indices names")
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    if (vm.count("help"))
    {
        std::cout << desc << std::endl;
        return false;
    }

    try  { po::notify(vm); }
    catch(std::exception& e)  {
        std::cerr << "Error: " << e.what() << std::endl << std::endl << desc << std::endl;
        return false;
    }

    std::vector< std::string> sub_folder_names = v4r::io::getFoldersInDirectory( input_dir );

    if( sub_folder_names.empty() )
        sub_folder_names.push_back("");

    for (const std::string &sub_folder : sub_folder_names)
    {
        const std::string path_extended = input_dir + "/" + sub_folder;

        std::cout << "Processing all point clouds in folder " << path_extended;
        const std::string search_pattern = ".*." + cloud_prefix + ".*.pcd";
        std::vector < std::string > cloud_files = v4r::io::getFilesInDirectory (path_extended, search_pattern, true);

        for (const std::string &cloud_file : cloud_files)
        {
            const std::string full_path = path_extended + "/"  + cloud_file;
            const std::string out_fn = out_dir + "/" + sub_folder + "/" + cloud_file;

            // Loading file and corresponding indices file (if it exists)
            pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
            pcl::io::loadPCDFile (full_path, *cloud);

            if(use_indices)
            {
                // Check if indices file exist
                std::string indices_filename( cloud_file );
                boost::replace_first (indices_filename, cloud_prefix, indices_prefix);

                if( v4r::io::existsFile( path_extended+"/"+indices_filename ) )
                {
                    pcl::PointCloud<IndexPoint> obj_indices_cloud;
                    pcl::io::loadPCDFile(path_extended+"/"+indices_filename, obj_indices_cloud);
                    pcl::PointIndices indices;
                    indices.indices.resize(obj_indices_cloud.points.size());
                    for(size_t kk=0; kk < obj_indices_cloud.points.size(); kk++)
                        indices.indices[kk] = obj_indices_cloud.points[kk].idx;
                    pcl::copyPointCloud(*cloud, indices, *cloud);
                }
                else
                {
                    boost::replace_last( indices_filename, ".pcd", ".txt");
                    if( v4r::io::existsFile( path_extended+"/"+indices_filename ) )
                    {
                        std::vector<int> indices;
                        int idx_tmp;
                        std::ifstream mask_f( path_extended+"/"+indices_filename );

                        while (mask_f >> idx_tmp)
                            indices.push_back(idx_tmp);

                        mask_f.close();

                        pcl::copyPointCloud(*cloud, indices, *cloud);
                    }
                    else
                    {
                        std::cerr << "Indices file " << path_extended << "/" << indices_filename << " does not exist." << std::endl;
                    }
                }
            }

            // Check if pose file exist
            std::string pose_fn( cloud_file );
            boost::replace_first (pose_fn, cloud_prefix, pose_prefix);
            boost::replace_last (pose_fn, ".pcd", ".txt");
            const std::string full_pose_path = input_dir + pose_fn;

            if( v4r::io::existsFile( full_pose_path ) )
            {
                Eigen::Matrix4f global_trans = v4r::io::readMatrixFromFile(full_pose_path);

                if(invert_pose)
                    global_trans = global_trans.inverse();

                v4r::setCloudPose(global_trans, *cloud);
                pcl::io::savePCDFileBinary(out_fn, *cloud);
            }
            else
                std::cerr << "Pose file " << full_pose_path << " does not exist." << std::endl;
        }
    }
}
<commit_msg>minor fixes for save pose into pcd<commit_after>/*
 * adds pose information given by pose_000x.txt into cloud_000x.pcd files (old dataset structure)
 * now we can use pcl_viewer *.pcd to show all point clouds in common coordinate system
 *
 *  Created on: Dec 04, 2014
 *      Author: Thomas Faeulhammer
 *
 */

#include <v4r/io/filesystem.h>
#include <v4r/io/eigen.h>
#include <v4r/common/faat_3d_rec_framework_defines.h>
#include <v4r/common/miscellaneous.h>
#include <pcl/common/transforms.h>
#include <pcl/console/parse.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>
#include <glog/logging.h>

namespace po = boost::program_options;

typedef pcl::PointXYZRGB PointT;

int main (int argc, char ** argv)
{
    std::string input_dir, out_dir = "/tmp/clouds_with_pose/";
    std::string cloud_prefix = "cloud_", pose_prefix = "pose_", indices_prefix = "object_indices_";
    bool invert_pose = false;
    bool use_indices = false;
    po::options_description desc("Save camera pose given by seperate pose file directly into header of .pcd file\n======================================\n**Allowed options");
    desc.add_options()
            ("help,h", "produce help message")
            ("input_dir,i", po::value<std::string>(&input_dir)->required(), "directory containing both .pcd and pose files")
            ("output_dir,o", po::value<std::string>(&out_dir)->default_value(out_dir), "output directory")
            ("use_indices,u", po::bool_switch(&use_indices), "if true, uses indices")
            ("invert_pose,t", po::bool_switch(&invert_pose), "if true, takes the inverse of the pose file (e.g. required for Willow Dataset)")
            ("cloud_prefix,c", po::value<std::string>(&cloud_prefix)->default_value(cloud_prefix)->implicit_value(""), "prefix of cloud names")
            ("pose_prefix,p", po::value<std::string>(&pose_prefix)->default_value(pose_prefix), "prefix of camera pose names (e.g. transformation_)")
            ("indices_prefix,d", po::value<std::string>(&indices_prefix)->default_value(indices_prefix), "prefix of object indices names")
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    if (vm.count("help"))
    {
        std::cout << desc << std::endl;
        return false;
    }

    try  { po::notify(vm); }
    catch(std::exception& e)  {
        std::cerr << "Error: " << e.what() << std::endl << std::endl << desc << std::endl;
        return false;
    }

    std::vector< std::string> sub_folder_names = v4r::io::getFoldersInDirectory( input_dir );

    if( sub_folder_names.empty() )
        sub_folder_names.push_back("");

    for (const std::string &sub_folder : sub_folder_names)
    {
        const std::string path_extended = input_dir + "/" + sub_folder;

        std::cout << "Processing all point clouds in folder " << path_extended;
        const std::string search_pattern = ".*." + cloud_prefix + ".*.pcd";
        std::vector < std::string > cloud_files = v4r::io::getFilesInDirectory (path_extended, search_pattern, true);

        for (const std::string &cloud_file : cloud_files)
        {
            const std::string full_path = path_extended + "/"  + cloud_file;
            const std::string out_fn = out_dir + "/" + sub_folder + "/" + cloud_file;

            // Loading file and corresponding indices file (if it exists)
            pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
            pcl::io::loadPCDFile (full_path, *cloud);

            if(use_indices)
            {
                // Check if indices file exist
                std::string indices_filename( cloud_file );
                boost::replace_first (indices_filename, cloud_prefix, indices_prefix);

                if( v4r::io::existsFile( path_extended+"/"+indices_filename ) )
                {
                    pcl::PointCloud<IndexPoint> obj_indices_cloud;
                    pcl::io::loadPCDFile(path_extended+"/"+indices_filename, obj_indices_cloud);
                    pcl::PointIndices indices;
                    indices.indices.resize(obj_indices_cloud.points.size());
                    for(size_t kk=0; kk < obj_indices_cloud.points.size(); kk++)
                        indices.indices[kk] = obj_indices_cloud.points[kk].idx;
                    pcl::copyPointCloud(*cloud, indices, *cloud);
                }
                else
                {
                    boost::replace_last( indices_filename, ".pcd", ".txt");
                    if( v4r::io::existsFile( path_extended+"/"+indices_filename ) )
                    {
                        std::vector<int> indices;
                        int idx_tmp;
                        std::ifstream mask_f( path_extended+"/"+indices_filename );

                        while (mask_f >> idx_tmp)
                            indices.push_back(idx_tmp);

                        mask_f.close();

                        pcl::copyPointCloud(*cloud, indices, *cloud);
                    }
                    else
                    {
                        std::cerr << "Indices file " << path_extended << "/" << indices_filename << " does not exist." << std::endl;
                    }
                }
            }

            // Check if pose file exist
            std::string pose_fn( cloud_file );
            boost::replace_first (pose_fn, cloud_prefix, pose_prefix);
            boost::replace_last (pose_fn, ".pcd", ".txt");
            const std::string full_pose_path = input_dir + pose_fn;

            if( v4r::io::existsFile( full_pose_path ) )
            {
                Eigen::Matrix4f global_trans = v4r::io::readMatrixFromFile(full_pose_path);

                if(invert_pose)
                    global_trans = global_trans.inverse();

                v4r::setCloudPose(global_trans, *cloud);
                v4r::io::createDirForFileIfNotExist(out_fn);
                pcl::io::savePCDFileBinary(out_fn, *cloud);
            }
            else
                std::cerr << "Pose file " << full_pose_path << " does not exist." << std::endl;
        }
    }
}
<|endoftext|>