<commit_before>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "bindings/global_callbacks.h"

#include "base/file_path.h"
#include "base/file_search.h"
#include "base/logging.h"
#include "bindings/global_scope.h"
#include "bindings/pawn_invoke.h"
#include "bindings/runtime.h"
#include "bindings/utilities.h"
#include "performance/trace_manager.h"
#include "plugin/sdk/plugincommon.h"

#include <include/v8.h>
#include <string>

namespace bindings {

// void addEventListener(string type, function listener);
void AddEventListenerCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() < 2) {
    ThrowException("unable to execute addEventListener(): 2 arguments required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute addEventListener(): expected a string for argument 1.");
    return;
  }

  if (!arguments[1]->IsFunction()) {
    ThrowException("unable to execute addEventListener(): expected a function for argument 2.");
    return;
  }

  global->AddEventListener(toString(arguments[0]), v8::Local<v8::Function>::Cast(arguments[1]));
}

// boolean dispatchEvent(string type[, object event]);
void DispatchEventCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute dispatchEvent(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute dispatchEvent(): expected a string for argument 1.");
    return;
  }

  const std::string type = toString(arguments[0]);

  if (arguments.Length() >= 2)
    global->DispatchEvent(type, arguments[1]);
  else
    global->DispatchEvent(type, v8::Null(arguments.GetIsolate()));
}

// object { duration, fps } frameCounter();
void FrameCounterCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(arguments.GetIsolate());

  double duration, average_fps;
  runtime->GetAndResetFrameCounter(&duration, &average_fps);

  v8::Local<v8::Object> object = v8::Object::New(runtime->isolate());
  object->Set(v8String("duration"), v8::Number::New(runtime->isolate(), duration));
  object->Set(v8String("fps"), v8::Number::New(runtime->isolate(), average_fps));

  arguments.GetReturnValue().Set(object);
}

// sequence<string> glob(string base, string pattern);
void GlobCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  if (arguments.Length() < 2) {
    ThrowException("unable to execute glob(): 2 arguments required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute glob(): expected a string for argument 1.");
    return;
  }

  if (!arguments[1]->IsString()) {
    ThrowException("unable to execute glob(): expected a string for argument 2.");
    return;
  }

  v8::Isolate* isolate = arguments.GetIsolate();

  const base::FilePath base = base::FilePath::CurrentDirectory().Append(toString(arguments[0]));
  const std::string query = toString(arguments[1]);

  std::vector<std::string> results;

  FileSearchStatus status = FileSearch(base, query, &results);
  switch (status) {
  case FileSearchStatus::ERR_INVALID_REGEX:
    ThrowException("unable to execute glob(): invalid expression: " + query);
    break;
  case FileSearchStatus::SUCCESS:
    {
      v8::Local<v8::Array> arr = v8::Array::New(isolate, results.size());
      for (size_t i = 0; i < results.size(); ++i)
        arr->Set(i, v8String(results[i]));

      arguments.GetReturnValue().Set(arr);
    }
    break;
  }
}

// boolean hasEventListeners(string type);
void HasEventListenersCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute hasEventListeners(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute hasEventListeners(): expected a string for argument 1.");
    return;
  }

  arguments.GetReturnValue().Set(global->HasEventListeners(toString(arguments[0])));
}

// double highResolutionTime();
void HighResolutionTimeCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();
  arguments.GetReturnValue().Set(global->HighResolutionTime());
}

// void notifyReady();
void NotifyReadyCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  Runtime::FromIsolate(arguments.GetIsolate())->SetReady();
}

// any pawnInvoke(string name[, string signature[, ...]]);
void PawnInvokeCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute pawnInvoke(): 1 argument required, but 0 provided.");
    return;
  }

  arguments.GetReturnValue().Set(global->GetPawnInvoke()->Call(arguments));
}

// void provideNative(string name, string parameters, function handler);
void ProvideNativeCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (!pAMXFunctions) {
    ThrowException("unable to register natives in the test runner.");
    return;
  }

  if (arguments.Length() != 3) {
    ThrowException("unable to execute provideNative(): 3 argument required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute provideNative(): expected a string for argument 1.");
    return;
  }

  if (!arguments[1]->IsString()) {
    ThrowException("unable to execute provideNative(): expected a string for argument 2.");
    return;
  }

  if (!arguments[2]->IsFunction()) {
    ThrowException("unable to execute provideNative(): expected a function for argument 3.");
    return;
  }

  const std::string name = toString(arguments[0]);
  const std::string parameters = toString(arguments[1]);

  if (!global->GetProvidedNatives()->Register(name, parameters, v8::Local<v8::Function>::Cast(arguments[2])))
    ThrowException("unable to execute provideNative(): the native could not be registered.");
}

// string readFile(string filename);
void ReadFileCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute readFile(): 1 argument required, but 0 provided.");
    return;
  }

  arguments.GetReturnValue().Set(v8String(global->ReadFile(toString(arguments[0]))));
}

// void removeEventListener(string type[, function listener]);
void RemoveEventListenerCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute removeEventListener(): 1 argument required, but 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute removeEventListener(): expected a string for argument 1.");
    return;
  }

  v8::Local<v8::Function> function;
  if (arguments[1]->IsFunction())
    function = v8::Local<v8::Function>::Cast(arguments[1]);

  global->RemoveEventListener(toString(arguments[0]), function);
}

// void reportTestsFinished(int totalTests, int failedTests);
void ReportTestsFinishedCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  if (arguments.Length() != 2) {
    ThrowException("unable to execute reportTestsFinished(): 2 argument required, but only" +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsNumber() || !arguments[1]->IsNumber()) {
    ThrowException("unable to execute reportTestsFinished(): expected numbers as arguments.");
    return;
  }

  unsigned int total_tests = static_cast<unsigned int>(arguments[0]->ToNumber()->IntegerValue());
  unsigned int failed_tests = static_cast<unsigned int>(arguments[1]->ToNumber()->IntegerValue());

  Runtime::Delegate* runtime_delegate = Runtime::FromIsolate(arguments.GetIsolate())->delegate();
  if (runtime_delegate)
    runtime_delegate->OnScriptTestsDone(total_tests, failed_tests);
}

// object requireImpl(string filename);
// NOTE: The public entry-point is require(), so reflect this in exceptions.
void RequireImplCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(arguments.GetIsolate());
  GlobalScope* global = runtime->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute require(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute require(): expected a string for argument 1.");
    return;
  }

  arguments.GetReturnValue().Set(global->RequireImpl(runtime.get(), toString(arguments[0])));
}

// void startTrace();
void StartTraceCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  LOG(INFO) << "[TraceManager] Started capturing traces.";
  performance::TraceManager::GetInstance()->set_enabled(true);
}

// void stopTrace(optional string filename);
void StopTraceCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  LOG(INFO) << "[TraceManager] Stopped capturing traces.";
  performance::TraceManager::GetInstance()->set_enabled(false);

  if (arguments.Length() == 0)
    return;

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute stopTrace(): expected a string for argument 1.");
    return;
  }

  const std::string filename = toString(arguments[0]);
  if (!filename.size()) {
    ThrowException("unable to execute stopTrace(): expected a non-empty string for argument 1.");
    return;
  }

  const base::FilePath file = base::FilePath::CurrentDirectory().Append(filename);

  // Write the captured traces to the |path|, clear state afterwards.
  performance::TraceManager::GetInstance()->Write(file, true /* clear_traces */);
}

// Promise<void> wait(unsigned long time);
void WaitCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(arguments.GetIsolate());
  GlobalScope* global = runtime->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute wait(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsNumber()) {
    ThrowException("unable to execute wait(): expected a number for argument 1.");
    return;
  }

  arguments.GetReturnValue().Set(global->Wait(runtime.get(), arguments[0]->ToNumber()->IntegerValue()));
}

}  // namespace bindings
<commit_msg>Stop the plugin from spinning when the test runner is done<commit_after>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "bindings/global_callbacks.h"

#include "base/file_path.h"
#include "base/file_search.h"
#include "base/logging.h"
#include "bindings/global_scope.h"
#include "bindings/pawn_invoke.h"
#include "bindings/runtime.h"
#include "bindings/utilities.h"
#include "performance/trace_manager.h"
#include "plugin/sdk/plugincommon.h"

#include <include/v8.h>
#include <string>

namespace bindings {

// void addEventListener(string type, function listener);
void AddEventListenerCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() < 2) {
    ThrowException("unable to execute addEventListener(): 2 arguments required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute addEventListener(): expected a string for argument 1.");
    return;
  }

  if (!arguments[1]->IsFunction()) {
    ThrowException("unable to execute addEventListener(): expected a function for argument 2.");
    return;
  }

  global->AddEventListener(toString(arguments[0]), v8::Local<v8::Function>::Cast(arguments[1]));
}

// boolean dispatchEvent(string type[, object event]);
void DispatchEventCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute dispatchEvent(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute dispatchEvent(): expected a string for argument 1.");
    return;
  }

  const std::string type = toString(arguments[0]);

  if (arguments.Length() >= 2)
    global->DispatchEvent(type, arguments[1]);
  else
    global->DispatchEvent(type, v8::Null(arguments.GetIsolate()));
}

// object { duration, fps } frameCounter();
void FrameCounterCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(arguments.GetIsolate());

  double duration, average_fps;
  runtime->GetAndResetFrameCounter(&duration, &average_fps);

  v8::Local<v8::Object> object = v8::Object::New(runtime->isolate());
  object->Set(v8String("duration"), v8::Number::New(runtime->isolate(), duration));
  object->Set(v8String("fps"), v8::Number::New(runtime->isolate(), average_fps));

  arguments.GetReturnValue().Set(object);
}

// sequence<string> glob(string base, string pattern);
void GlobCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  if (arguments.Length() < 2) {
    ThrowException("unable to execute glob(): 2 arguments required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute glob(): expected a string for argument 1.");
    return;
  }

  if (!arguments[1]->IsString()) {
    ThrowException("unable to execute glob(): expected a string for argument 2.");
    return;
  }

  v8::Isolate* isolate = arguments.GetIsolate();

  const base::FilePath base = base::FilePath::CurrentDirectory().Append(toString(arguments[0]));
  const std::string query = toString(arguments[1]);

  std::vector<std::string> results;

  FileSearchStatus status = FileSearch(base, query, &results);
  switch (status) {
  case FileSearchStatus::ERR_INVALID_REGEX:
    ThrowException("unable to execute glob(): invalid expression: " + query);
    break;
  case FileSearchStatus::SUCCESS:
    {
      v8::Local<v8::Array> arr = v8::Array::New(isolate, results.size());
      for (size_t i = 0; i < results.size(); ++i)
        arr->Set(i, v8String(results[i]));

      arguments.GetReturnValue().Set(arr);
    }
    break;
  }
}

// boolean hasEventListeners(string type);
void HasEventListenersCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute hasEventListeners(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute hasEventListeners(): expected a string for argument 1.");
    return;
  }

  arguments.GetReturnValue().Set(global->HasEventListeners(toString(arguments[0])));
}

// double highResolutionTime();
void HighResolutionTimeCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();
  arguments.GetReturnValue().Set(global->HighResolutionTime());
}

// void notifyReady();
void NotifyReadyCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  Runtime::FromIsolate(arguments.GetIsolate())->SetReady();
}

// any pawnInvoke(string name[, string signature[, ...]]);
void PawnInvokeCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute pawnInvoke(): 1 argument required, but 0 provided.");
    return;
  }

  arguments.GetReturnValue().Set(global->GetPawnInvoke()->Call(arguments));
}

// void provideNative(string name, string parameters, function handler);
void ProvideNativeCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (!pAMXFunctions) {
    ThrowException("unable to register natives in the test runner.");
    return;
  }

  if (arguments.Length() != 3) {
    ThrowException("unable to execute provideNative(): 3 argument required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute provideNative(): expected a string for argument 1.");
    return;
  }

  if (!arguments[1]->IsString()) {
    ThrowException("unable to execute provideNative(): expected a string for argument 2.");
    return;
  }

  if (!arguments[2]->IsFunction()) {
    ThrowException("unable to execute provideNative(): expected a function for argument 3.");
    return;
  }

  const std::string name = toString(arguments[0]);
  const std::string parameters = toString(arguments[1]);

  if (!global->GetProvidedNatives()->Register(name, parameters, v8::Local<v8::Function>::Cast(arguments[2])))
    ThrowException("unable to execute provideNative(): the native could not be registered.");
}

// string readFile(string filename);
void ReadFileCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute readFile(): 1 argument required, but 0 provided.");
    return;
  }

  arguments.GetReturnValue().Set(v8String(global->ReadFile(toString(arguments[0]))));
}

// void removeEventListener(string type[, function listener]);
void RemoveEventListenerCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  GlobalScope* global = Runtime::FromIsolate(arguments.GetIsolate())->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute removeEventListener(): 1 argument required, but 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute removeEventListener(): expected a string for argument 1.");
    return;
  }

  v8::Local<v8::Function> function;
  if (arguments[1]->IsFunction())
    function = v8::Local<v8::Function>::Cast(arguments[1]);

  global->RemoveEventListener(toString(arguments[0]), function);
}

// void reportTestsFinished(int totalTests, int failedTests);
void ReportTestsFinishedCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  if (arguments.Length() != 2) {
    ThrowException("unable to execute reportTestsFinished(): 2 argument required, but only" +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[0]->IsNumber() || !arguments[1]->IsNumber()) {
    ThrowException("unable to execute reportTestsFinished(): expected numbers as arguments.");
    return;
  }

  unsigned int total_tests = static_cast<unsigned int>(arguments[0]->ToNumber()->IntegerValue());
  unsigned int failed_tests = static_cast<unsigned int>(arguments[1]->ToNumber()->IntegerValue());

  auto runtime = Runtime::FromIsolate(arguments.GetIsolate());

  Runtime::Delegate* runtime_delegate = runtime->delegate();
  if (runtime_delegate)
    runtime_delegate->OnScriptTestsDone(total_tests, failed_tests);

  if (!pAMXFunctions) {
    runtime->SetReady();  // this stops the plugin from spinning
    ThrowException("The Test Runner is done- all's good, thanks for using this tool!");
  }
}

// object requireImpl(string filename);
// NOTE: The public entry-point is require(), so reflect this in exceptions.
void RequireImplCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(arguments.GetIsolate());
  GlobalScope* global = runtime->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute require(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute require(): expected a string for argument 1.");
    return;
  }

  arguments.GetReturnValue().Set(global->RequireImpl(runtime.get(), toString(arguments[0])));
}

// void startTrace();
void StartTraceCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  LOG(INFO) << "[TraceManager] Started capturing traces.";
  performance::TraceManager::GetInstance()->set_enabled(true);
}

// void stopTrace(optional string filename);
void StopTraceCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  LOG(INFO) << "[TraceManager] Stopped capturing traces.";
  performance::TraceManager::GetInstance()->set_enabled(false);

  if (arguments.Length() == 0)
    return;

  if (!arguments[0]->IsString()) {
    ThrowException("unable to execute stopTrace(): expected a string for argument 1.");
    return;
  }

  const std::string filename = toString(arguments[0]);
  if (!filename.size()) {
    ThrowException("unable to execute stopTrace(): expected a non-empty string for argument 1.");
    return;
  }

  const base::FilePath file = base::FilePath::CurrentDirectory().Append(filename);

  // Write the captured traces to the |path|, clear state afterwards.
  performance::TraceManager::GetInstance()->Write(file, true /* clear_traces */);
}

// Promise<void> wait(unsigned long time);
void WaitCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(arguments.GetIsolate());
  GlobalScope* global = runtime->GetGlobalScope();

  if (arguments.Length() == 0) {
    ThrowException("unable to execute wait(): 1 argument required, but only 0 provided.");
    return;
  }

  if (!arguments[0]->IsNumber()) {
    ThrowException("unable to execute wait(): expected a number for argument 1.");
    return;
  }

  arguments.GetReturnValue().Set(global->Wait(runtime.get(), arguments[0]->ToNumber()->IntegerValue()));
}

}  // namespace bindings
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qmakestep.h"

#include "projectexplorer/projectexplorerconstants.h"
#include "qmakeparser.h"
#include "qt4buildconfiguration.h"
#include "qt4project.h"
#include "qt4projectmanagerconstants.h"
#include "qt4projectmanager.h"
#include "qt4target.h"
#include "qtversionmanager.h"

#include <coreplugin/icore.h>
#include <utils/qtcassert.h>

#include <QtCore/QDir>
#include <QtCore/QFile>

using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
using namespace ProjectExplorer;

namespace {
const char * const QMAKE_BS_ID("QtProjectManager.QMakeBuildStep");

const char * const QMAKE_ARGUMENTS_KEY("QtProjectManager.QMakeBuildStep.QMakeArguments");
}

QMakeStep::QMakeStep(Qt4BuildConfiguration *bc) :
    AbstractProcessStep(bc, QLatin1String(QMAKE_BS_ID)),
    m_forced(false)
{
    ctor();
}

QMakeStep::QMakeStep(Qt4BuildConfiguration *bc, const QString &id) :
    AbstractProcessStep(bc, id),
    m_forced(false)
{
    ctor();
}

QMakeStep::QMakeStep(Qt4BuildConfiguration *bc, QMakeStep *bs) :
    AbstractProcessStep(bc, bs),
    m_forced(false),
    m_userArgs(bs->m_userArgs)
{
    ctor();
}

void QMakeStep::ctor()
{
    setDisplayName(tr("qmake", "QMakeStep display name."));
}

QMakeStep::~QMakeStep()
{
}

Qt4BuildConfiguration *QMakeStep::qt4BuildConfiguration() const
{
    return static_cast<Qt4BuildConfiguration *>(buildConfiguration());
}

QStringList QMakeStep::allArguments()
{
    QStringList additonalArguments = m_userArgs;
    Qt4BuildConfiguration *bc = qt4BuildConfiguration();
    QStringList arguments;
    if (bc->subNodeBuild())
        arguments << bc->subNodeBuild()->path();
    else
        arguments << buildConfiguration()->target()->project()->file()->fileName();
    arguments << "-r";

    if (!additonalArguments.contains("-spec"))
        arguments << "-spec" << bc->qtVersion()->mkspec();

#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
    ToolChain::ToolChainType type = bc->toolChainType();
    if (type == ToolChain::GCC_MAEMO)
        arguments << QLatin1String("-unix");
#endif

    // Find out what flags we pass on to qmake
    QStringList addedUserConfigArguments;
    QStringList removedUserConfigArguments;
    bc->getConfigCommandLineArguments(&addedUserConfigArguments, &removedUserConfigArguments);
    if (!removedUserConfigArguments.isEmpty()) {
        foreach (const QString &removedConfig, removedUserConfigArguments)
            arguments.append("CONFIG-=" + removedConfig);
    }
    if (!addedUserConfigArguments.isEmpty()) {
        foreach (const QString &addedConfig, addedUserConfigArguments)
            arguments.append("CONFIG+=" + addedConfig);
    }
    if (!additonalArguments.isEmpty())
        arguments << additonalArguments;

    return arguments;
}

bool QMakeStep::init()
{
    Qt4BuildConfiguration *qt4bc = qt4BuildConfiguration();
    const QtVersion *qtVersion = qt4bc->qtVersion();

    QStringList args = allArguments();
    QString workingDirectory;
    if (qt4bc->subNodeBuild())
        workingDirectory = qt4bc->subNodeBuild()->buildDir();
    else
        workingDirectory = qt4bc->buildDirectory();

    QString program = qtVersion->qmakeCommand();

    // Check whether we need to run qmake
    m_needToRunQMake = true;
    if (QDir(workingDirectory).exists(QLatin1String("Makefile"))) {
        QString qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(workingDirectory);
        if (qtVersion->qmakeCommand() == qmakePath) {
            m_needToRunQMake = !qt4bc->compareToImportFrom(workingDirectory);
        }
    }

    if (m_forced) {
        m_forced = false;
        m_needToRunQMake = true;
    }

    setEnabled(m_needToRunQMake);
    setWorkingDirectory(workingDirectory);
    setCommand(program);
    setArguments(args);
    setEnvironment(qt4bc->environment());

    setOutputParser(new QMakeParser);
    return AbstractProcessStep::init();
}

void QMakeStep::run(QFutureInterface<bool> &fi)
{
    Qt4Project *pro = qt4BuildConfiguration()->qt4Target()->qt4Project();
    if (pro->rootProjectNode()->projectType() == ScriptTemplate) {
        fi.reportResult(true);
        return;
    }

    // Warn on common error conditions:
    QList<ProjectExplorer::Task> issues =
            qt4BuildConfiguration()->qtVersion()->reportIssues(qt4BuildConfiguration()->qt4Target()->
                                                               qt4Project()->file()->fileName());
    bool canContinue = true;
    foreach (const ProjectExplorer::Task &t, issues) {
        addTask(t);
        if (t.type == Task::Error)
            canContinue = false;
    }
    if (!canContinue) {
        emit addOutput(tr("Configuration is faulty, please check the Build Issues view for details."));
        fi.reportResult(false);
        return;
    }

    if (!m_needToRunQMake) {
        emit addOutput(tr("Configuration unchanged, skipping qmake step."));
        fi.reportResult(true);
        return;
    }

    AbstractProcessStep::run(fi);
}

void QMakeStep::setForced(bool b)
{
    m_forced = b;
}

bool QMakeStep::forced()
{
    return m_forced;
}

ProjectExplorer::BuildStepConfigWidget *QMakeStep::createConfigWidget()
{
    return new QMakeStepConfigWidget(this);
}

bool QMakeStep::immutable() const
{
    return false;
}

void QMakeStep::processStartupFailed()
{
    m_forced = true;
    AbstractProcessStep::processStartupFailed();
}

bool QMakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
    bool result = AbstractProcessStep::processSucceeded(exitCode, status);
    if (!result)
        m_forced = true;
    qt4BuildConfiguration()->emitBuildDirectoryInitialized();
    return result;
}

void QMakeStep::setUserArguments(const QStringList &arguments)
{
    if (m_userArgs == arguments)
        return;
    m_userArgs = arguments;

    emit userArgumentsChanged();

    qt4BuildConfiguration()->emitQMakeBuildConfigurationChanged();
}

QStringList QMakeStep::userArguments()
{
    return m_userArgs;
}

QVariantMap QMakeStep::toMap() const
{
    QVariantMap map(AbstractProcessStep::toMap());
    map.insert(QLatin1String(QMAKE_ARGUMENTS_KEY), m_userArgs);
    return map;
}

bool QMakeStep::fromMap(const QVariantMap &map)
{
    m_userArgs = map.value(QLatin1String(QMAKE_ARGUMENTS_KEY)).toStringList();

    return BuildStep::fromMap(map);
}

////
// QMakeStepConfigWidget
////

QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
    : BuildStepConfigWidget(), m_step(step), m_ignoreChange(false)
{
    m_ui.setupUi(this);
    connect(m_ui.qmakeAdditonalArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
            this, SLOT(qmakeArgumentsLineEdited()));
    connect(m_ui.buildConfigurationComboBox, SIGNAL(currentIndexChanged(int)),
            this, SLOT(buildConfigurationSelected()));
    connect(step, SIGNAL(userArgumentsChanged()),
            this, SLOT(userArgumentsChanged()));
    connect(step->qt4BuildConfiguration(), SIGNAL(qtVersionChanged()),
            this, SLOT(qtVersionChanged()));
    connect(step->qt4BuildConfiguration(), SIGNAL(qmakeBuildConfigurationChanged()),
            this, SLOT(qmakeBuildConfigChanged()));
}

void QMakeStepConfigWidget::init()
{
    QString qmakeArgs = ProjectExplorer::Environment::joinArgumentList(m_step->userArguments());
    m_ui.qmakeAdditonalArgumentsLineEdit->setText(qmakeArgs);

    qmakeBuildConfigChanged();

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

QString QMakeStepConfigWidget::summaryText() const
{
    return m_summaryText;
}

QString QMakeStepConfigWidget::displayName() const
{
    return m_step->displayName();
}

void QMakeStepConfigWidget::qtVersionChanged()
{
    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::qmakeBuildConfigChanged()
{
    Qt4BuildConfiguration *bc = m_step->qt4BuildConfiguration();
    bool debug = bc->qmakeBuildConfiguration() & QtVersion::DebugBuild;
    m_ignoreChange = true;
    m_ui.buildConfigurationComboBox->setCurrentIndex(debug? 0 : 1);
    m_ignoreChange = false;
    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::userArgumentsChanged()
{
    if (m_ignoreChange)
        return;
    QString qmakeArgs = ProjectExplorer::Environment::joinArgumentList(m_step->userArguments());
    m_ui.qmakeAdditonalArgumentsLineEdit->setText(qmakeArgs);
    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::qmakeArgumentsLineEdited()
{
    m_ignoreChange = true;
    m_step->setUserArguments(
            ProjectExplorer::Environment::parseCombinedArgString(m_ui.qmakeAdditonalArgumentsLineEdit->text()));
    m_ignoreChange = false;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::buildConfigurationSelected()
{
    if (m_ignoreChange)
        return;
    Qt4BuildConfiguration *bc = m_step->qt4BuildConfiguration();
    QtVersion::QmakeBuildConfigs buildConfiguration = bc->qmakeBuildConfiguration();
    if (m_ui.buildConfigurationComboBox->currentIndex() == 0) { // debug
        buildConfiguration = buildConfiguration | QtVersion::DebugBuild;
    } else {
        buildConfiguration = buildConfiguration & ~QtVersion::DebugBuild;
    }
    m_ignoreChange = true;
    bc->setQMakeBuildConfiguration(buildConfiguration);
    m_ignoreChange = false;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::updateSummaryLabel()
{
    Qt4BuildConfiguration *qt4bc = m_step->qt4BuildConfiguration();
    const QtVersion *qtVersion = qt4bc->qtVersion();
    if (!qtVersion) {
        m_summaryText = tr("qmake: No Qt version set. Cannot run qmake.");
        emit updateSummary();
        return;
    }

    QStringList args = m_step->allArguments();
    // We don't want the full path to the .pro file
    const QString projectFileName = m_step->buildConfiguration()->target()->project()->file()->fileName();
    int index = args.indexOf(projectFileName);
    if (index != -1)
        args[index] = QFileInfo(projectFileName).fileName();

    // And we only use the .pro filename not the full path
    QString program = QFileInfo(qtVersion->qmakeCommand()).fileName();
    m_summaryText = tr("qmake: %1 %2").arg(program, args.join(QString(QLatin1Char(' '))));
    emit updateSummary();

}

void QMakeStepConfigWidget::updateEffectiveQMakeCall()
{
    Qt4BuildConfiguration *qt4bc = m_step->qt4BuildConfiguration();
    const QtVersion *qtVersion = qt4bc->qtVersion();
    QString program = QFileInfo(qtVersion->qmakeCommand()).fileName();
    m_ui.qmakeArgumentsEdit->setPlainText(program + QLatin1Char(' ') + ProjectExplorer::Environment::joinArgumentList(m_step->allArguments()));
}

////
// QMakeStepFactory
////

QMakeStepFactory::QMakeStepFactory(QObject *parent) :
    ProjectExplorer::IBuildStepFactory(parent)
{
}

QMakeStepFactory::~QMakeStepFactory()
{
}

bool QMakeStepFactory::canCreate(BuildConfiguration *parent, ProjectExplorer::StepType type, const QString &id) const
{
    if (type != ProjectExplorer::Build)
        return false;
    if (!qobject_cast<Qt4BuildConfiguration *>(parent))
        return false;
    return (id == QLatin1String(QMAKE_BS_ID));
}

ProjectExplorer::BuildStep *QMakeStepFactory::create(BuildConfiguration *parent, ProjectExplorer::StepType type,const QString &id)
{
    if (!canCreate(parent, type, id))
        return 0;
    Qt4BuildConfiguration *bc(qobject_cast<Qt4BuildConfiguration *>(parent));
    Q_ASSERT(bc);
    return new QMakeStep(bc);
}

bool QMakeStepFactory::canClone(BuildConfiguration *parent, ProjectExplorer::StepType type, BuildStep *source) const
{
    return canCreate(parent, type, source->id());
}

ProjectExplorer::BuildStep *QMakeStepFactory::clone(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type, ProjectExplorer::BuildStep *source)
{
    if (!canClone(parent, type, source))
        return 0;
    Qt4BuildConfiguration *bc(qobject_cast<Qt4BuildConfiguration *>(parent));
    Q_ASSERT(bc);
    return new QMakeStep(bc, qobject_cast<QMakeStep *>(source));
}

bool QMakeStepFactory::canRestore(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type, const QVariantMap &map) const
{
    QString id(ProjectExplorer::idFromMap(map));
    return canCreate(parent, type, id);
}

ProjectExplorer::BuildStep *QMakeStepFactory::restore(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type, const QVariantMap &map)
{
    if (!canRestore(parent, type, map))
        return 0;
    Qt4BuildConfiguration *bc(qobject_cast<Qt4BuildConfiguration *>(parent));
    Q_ASSERT(bc);
    QMakeStep *bs(new QMakeStep(bc));
    if (bs->fromMap(map))
        return bs;
    delete bs;
    return 0;
}

QStringList QMakeStepFactory::availableCreationIds(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type) const
{
    if (type == Build)
        if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(parent))
            if (!bc->qmakeStep())
                return QStringList() << QLatin1String(QMAKE_BS_ID);
    return QStringList();
}

QString QMakeStepFactory::displayNameForId(const QString &id) const
{
    if (id == QLatin1String(QMAKE_BS_ID))
        return tr("qmake");
    return QString();
}
<commit_msg>HACK: ensure a cleaner sourcedir for symbian builds<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qmakestep.h"

#include "projectexplorer/projectexplorerconstants.h"
#include "qmakeparser.h"
#include "qt4buildconfiguration.h"
#include "qt4project.h"
#include "qt4projectmanagerconstants.h"
#include "qt4projectmanager.h"
#include "qt4target.h"
#include "qtversionmanager.h"

#include <coreplugin/icore.h>
#include <utils/qtcassert.h>

#include <QtCore/QDir>
#include <QtCore/QFile>

using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
using namespace ProjectExplorer;

namespace {
const char * const QMAKE_BS_ID("QtProjectManager.QMakeBuildStep");

const char * const QMAKE_ARGUMENTS_KEY("QtProjectManager.QMakeBuildStep.QMakeArguments");
}

QMakeStep::QMakeStep(Qt4BuildConfiguration *bc) :
    AbstractProcessStep(bc, QLatin1String(QMAKE_BS_ID)),
    m_forced(false)
{
    ctor();
}

QMakeStep::QMakeStep(Qt4BuildConfiguration *bc, const QString &id) :
    AbstractProcessStep(bc, id),
    m_forced(false)
{
    ctor();
}

QMakeStep::QMakeStep(Qt4BuildConfiguration *bc, QMakeStep *bs) :
    AbstractProcessStep(bc, bs),
    m_forced(false),
    m_userArgs(bs->m_userArgs)
{
    ctor();
}

void QMakeStep::ctor()
{
    setDisplayName(tr("qmake", "QMakeStep display name."));
}

QMakeStep::~QMakeStep()
{
}

Qt4BuildConfiguration *QMakeStep::qt4BuildConfiguration() const
{
    return static_cast<Qt4BuildConfiguration *>(buildConfiguration());
}

QStringList QMakeStep::allArguments()
{
    QStringList additonalArguments = m_userArgs;
    Qt4BuildConfiguration *bc = qt4BuildConfiguration();
    QStringList arguments;
    if (bc->subNodeBuild())
        arguments << bc->subNodeBuild()->path();
    else
        arguments << buildConfiguration()->target()->project()->file()->fileName();
    arguments << "-r";

    if (!additonalArguments.contains("-spec"))
        arguments << "-spec" << bc->qtVersion()->mkspec();

#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
    ToolChain::ToolChainType type = bc->toolChainType();
    if (type == ToolChain::GCC_MAEMO)
        arguments << QLatin1String("-unix");
#endif
    if (bc->target()->id() == Constants::S60_DEVICE_TARGET_ID
        || bc->target()->id() == Constants::S60_EMULATOR_TARGET_ID) {
        // We have a target which does not allow shadow building.
        // But we really don't want to have the build artefacts in the source dir
        // so we try to hack around it, to make the common cases work.
        // This is a HACK, remove once the symbian make generator supports
        // shadow building
        arguments << QLatin1String("-after")
                  << QLatin1String("OBJECTS_DIR=.obj")
                  << QLatin1String("MOC_DIR=.moc")
                  << QLatin1String("UI_DIR=.ui")
                  << QLatin1String("RCC_DIR=.rcc");
    }

    // Find out what flags we pass on to qmake
    QStringList addedUserConfigArguments;
    QStringList removedUserConfigArguments;
    bc->getConfigCommandLineArguments(&addedUserConfigArguments, &removedUserConfigArguments);
    if (!removedUserConfigArguments.isEmpty()) {
        foreach (const QString &removedConfig, removedUserConfigArguments)
            arguments.append("CONFIG-=" + removedConfig);
    }
    if (!addedUserConfigArguments.isEmpty()) {
        foreach (const QString &addedConfig, addedUserConfigArguments)
            arguments.append("CONFIG+=" + addedConfig);
    }
    if (!additonalArguments.isEmpty())
        arguments << additonalArguments;

    return arguments;
}

bool QMakeStep::init()
{
    Qt4BuildConfiguration *qt4bc = qt4BuildConfiguration();
    const QtVersion *qtVersion = qt4bc->qtVersion();

    QStringList args = allArguments();
    QString workingDirectory;
    if (qt4bc->subNodeBuild())
        workingDirectory = qt4bc->subNodeBuild()->buildDir();
    else
        workingDirectory = qt4bc->buildDirectory();

    QString program = qtVersion->qmakeCommand();

    // Check whether we need to run qmake
    m_needToRunQMake = true;
    if (QDir(workingDirectory).exists(QLatin1String("Makefile"))) {
        QString qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(workingDirectory);
        if (qtVersion->qmakeCommand() == qmakePath) {
            m_needToRunQMake = !qt4bc->compareToImportFrom(workingDirectory);
        }
    }

    if (m_forced) {
        m_forced = false;
        m_needToRunQMake = true;
    }

    setEnabled(m_needToRunQMake);
    setWorkingDirectory(workingDirectory);
    setCommand(program);
    setArguments(args);
    setEnvironment(qt4bc->environment());

    setOutputParser(new QMakeParser);
    return AbstractProcessStep::init();
}

void QMakeStep::run(QFutureInterface<bool> &fi)
{
    Qt4Project *pro = qt4BuildConfiguration()->qt4Target()->qt4Project();
    if (pro->rootProjectNode()->projectType() == ScriptTemplate) {
        fi.reportResult(true);
        return;
    }

    // Warn on common error conditions:
    QList<ProjectExplorer::Task> issues =
            qt4BuildConfiguration()->qtVersion()->reportIssues(qt4BuildConfiguration()->qt4Target()->
                                                               qt4Project()->file()->fileName());
    bool canContinue = true;
    foreach (const ProjectExplorer::Task &t, issues) {
        addTask(t);
        if (t.type == Task::Error)
            canContinue = false;
    }
    if (!canContinue) {
        emit addOutput(tr("Configuration is faulty, please check the Build Issues view for details."));
        fi.reportResult(false);
        return;
    }

    if (!m_needToRunQMake) {
        emit addOutput(tr("Configuration unchanged, skipping qmake step."));
        fi.reportResult(true);
        return;
    }

    AbstractProcessStep::run(fi);
}

void QMakeStep::setForced(bool b)
{
    m_forced = b;
}

bool QMakeStep::forced()
{
    return m_forced;
}

ProjectExplorer::BuildStepConfigWidget *QMakeStep::createConfigWidget()
{
    return new QMakeStepConfigWidget(this);
}

bool QMakeStep::immutable() const
{
    return false;
}

void QMakeStep::processStartupFailed()
{
    m_forced = true;
    AbstractProcessStep::processStartupFailed();
}

bool QMakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
    bool result = AbstractProcessStep::processSucceeded(exitCode, status);
    if (!result)
        m_forced = true;
    qt4BuildConfiguration()->emitBuildDirectoryInitialized();
    return result;
}

void QMakeStep::setUserArguments(const QStringList &arguments)
{
    if (m_userArgs == arguments)
        return;
    m_userArgs = arguments;

    emit userArgumentsChanged();

    qt4BuildConfiguration()->emitQMakeBuildConfigurationChanged();
}

QStringList QMakeStep::userArguments()
{
    return m_userArgs;
}

QVariantMap QMakeStep::toMap() const
{
    QVariantMap map(AbstractProcessStep::toMap());
    map.insert(QLatin1String(QMAKE_ARGUMENTS_KEY), m_userArgs);
    return map;
}

bool QMakeStep::fromMap(const QVariantMap &map)
{
    m_userArgs = map.value(QLatin1String(QMAKE_ARGUMENTS_KEY)).toStringList();

    return BuildStep::fromMap(map);
}

////
// QMakeStepConfigWidget
////

QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
    : BuildStepConfigWidget(), m_step(step), m_ignoreChange(false)
{
    m_ui.setupUi(this);
    connect(m_ui.qmakeAdditonalArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
            this, SLOT(qmakeArgumentsLineEdited()));
    connect(m_ui.buildConfigurationComboBox, SIGNAL(currentIndexChanged(int)),
            this, SLOT(buildConfigurationSelected()));
    connect(step, SIGNAL(userArgumentsChanged()),
            this, SLOT(userArgumentsChanged()));
    connect(step->qt4BuildConfiguration(), SIGNAL(qtVersionChanged()),
            this, SLOT(qtVersionChanged()));
    connect(step->qt4BuildConfiguration(), SIGNAL(qmakeBuildConfigurationChanged()),
            this, SLOT(qmakeBuildConfigChanged()));
}

void QMakeStepConfigWidget::init()
{
    QString qmakeArgs = ProjectExplorer::Environment::joinArgumentList(m_step->userArguments());
    m_ui.qmakeAdditonalArgumentsLineEdit->setText(qmakeArgs);

    qmakeBuildConfigChanged();

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

QString QMakeStepConfigWidget::summaryText() const
{
    return m_summaryText;
}

QString QMakeStepConfigWidget::displayName() const
{
    return m_step->displayName();
}

void QMakeStepConfigWidget::qtVersionChanged()
{
    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::qmakeBuildConfigChanged()
{
    Qt4BuildConfiguration *bc = m_step->qt4BuildConfiguration();
    bool debug = bc->qmakeBuildConfiguration() & QtVersion::DebugBuild;
    m_ignoreChange = true;
    m_ui.buildConfigurationComboBox->setCurrentIndex(debug? 0 : 1);
    m_ignoreChange = false;
    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::userArgumentsChanged()
{
    if (m_ignoreChange)
        return;
    QString qmakeArgs = ProjectExplorer::Environment::joinArgumentList(m_step->userArguments());
    m_ui.qmakeAdditonalArgumentsLineEdit->setText(qmakeArgs);
    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::qmakeArgumentsLineEdited()
{
    m_ignoreChange = true;
    m_step->setUserArguments(
            ProjectExplorer::Environment::parseCombinedArgString(m_ui.qmakeAdditonalArgumentsLineEdit->text()));
    m_ignoreChange = false;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::buildConfigurationSelected()
{
    if (m_ignoreChange)
        return;
    Qt4BuildConfiguration *bc = m_step->qt4BuildConfiguration();
    QtVersion::QmakeBuildConfigs buildConfiguration = bc->qmakeBuildConfiguration();
    if (m_ui.buildConfigurationComboBox->currentIndex() == 0) { // debug
        buildConfiguration = buildConfiguration | QtVersion::DebugBuild;
    } else {
        buildConfiguration = buildConfiguration & ~QtVersion::DebugBuild;
    }
    m_ignoreChange = true;
    bc->setQMakeBuildConfiguration(buildConfiguration);
    m_ignoreChange = false;

    updateSummaryLabel();
    updateEffectiveQMakeCall();
}

void QMakeStepConfigWidget::updateSummaryLabel()
{
    Qt4BuildConfiguration *qt4bc = m_step->qt4BuildConfiguration();
    const QtVersion *qtVersion = qt4bc->qtVersion();
    if (!qtVersion) {
        m_summaryText = tr("qmake: No Qt version set. Cannot run qmake.");
        emit updateSummary();
        return;
    }

    QStringList args = m_step->allArguments();
    // We don't want the full path to the .pro file
    const QString projectFileName = m_step->buildConfiguration()->target()->project()->file()->fileName();
    int index = args.indexOf(projectFileName);
    if (index != -1)
        args[index] = QFileInfo(projectFileName).fileName();

    // And we only use the .pro filename not the full path
    QString program = QFileInfo(qtVersion->qmakeCommand()).fileName();
    m_summaryText = tr("qmake: %1 %2").arg(program, args.join(QString(QLatin1Char(' '))));
    emit updateSummary();

}

void QMakeStepConfigWidget::updateEffectiveQMakeCall()
{
    Qt4BuildConfiguration *qt4bc = m_step->qt4BuildConfiguration();
    const QtVersion *qtVersion = qt4bc->qtVersion();
    QString program = QFileInfo(qtVersion->qmakeCommand()).fileName();
    m_ui.qmakeArgumentsEdit->setPlainText(program + QLatin1Char(' ') + ProjectExplorer::Environment::joinArgumentList(m_step->allArguments()));
}

////
// QMakeStepFactory
////

QMakeStepFactory::QMakeStepFactory(QObject *parent) :
    ProjectExplorer::IBuildStepFactory(parent)
{
}

QMakeStepFactory::~QMakeStepFactory()
{
}

bool QMakeStepFactory::canCreate(BuildConfiguration *parent, ProjectExplorer::StepType type, const QString &id) const
{
    if (type != ProjectExplorer::Build)
        return false;
    if (!qobject_cast<Qt4BuildConfiguration *>(parent))
        return false;
    return (id == QLatin1String(QMAKE_BS_ID));
}

ProjectExplorer::BuildStep *QMakeStepFactory::create(BuildConfiguration *parent, ProjectExplorer::StepType type,const QString &id)
{
    if (!canCreate(parent, type, id))
        return 0;
    Qt4BuildConfiguration *bc(qobject_cast<Qt4BuildConfiguration *>(parent));
    Q_ASSERT(bc);
    return new QMakeStep(bc);
}

bool QMakeStepFactory::canClone(BuildConfiguration *parent, ProjectExplorer::StepType type, BuildStep *source) const
{
    return canCreate(parent, type, source->id());
}

ProjectExplorer::BuildStep *QMakeStepFactory::clone(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type, ProjectExplorer::BuildStep *source)
{
    if (!canClone(parent, type, source))
        return 0;
    Qt4BuildConfiguration *bc(qobject_cast<Qt4BuildConfiguration *>(parent));
    Q_ASSERT(bc);
    return new QMakeStep(bc, qobject_cast<QMakeStep *>(source));
}

bool QMakeStepFactory::canRestore(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type, const QVariantMap &map) const
{
    QString id(ProjectExplorer::idFromMap(map));
    return canCreate(parent, type, id);
}

ProjectExplorer::BuildStep *QMakeStepFactory::restore(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type, const QVariantMap &map)
{
    if (!canRestore(parent, type, map))
        return 0;
    Qt4BuildConfiguration *bc(qobject_cast<Qt4BuildConfiguration *>(parent));
    Q_ASSERT(bc);
    QMakeStep *bs(new QMakeStep(bc));
    if (bs->fromMap(map))
        return bs;
    delete bs;
    return 0;
}

QStringList QMakeStepFactory::availableCreationIds(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::StepType type) const
{
    if (type == Build)
        if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(parent))
            if (!bc->qmakeStep())
                return QStringList() << QLatin1String(QMAKE_BS_ID);
    return QStringList();
}

QString QMakeStepFactory::displayNameForId(const QString &id) const
{
    if (id == QLatin1String(QMAKE_BS_ID))
        return tr("qmake");
    return QString();
}
<|endoftext|>


<commit_before>#include <UnitTest11.hpp>
#include <UnitTest11/TestFixtureRunner.hpp>

namespace ut11
{
    namespace Utility
    {
        template<> struct ParseToString<ut11::Output*>
        {
            inline std::string operator()(ut11::Output* value) const
            {
                std::stringstream stream;
                stream << value;
                return stream.str();
            }
        };
    }
}

namespace
{
    class FakeOutput : public ut11::Output
    {
    public:
        virtual ~FakeOutput() { }

        MockAction(Begin)
        MockAction(Finish, std::size_t, std::size_t)

        MockAction(BeginFixture, std::string)
        MockAction(EndFixture, std::string)

        MockAction(BeginTest)
        MockAction(EndTest)

        MockAction(BeginGiven, std::string)
        MockAction(EndGiven, std::string)

        MockAction(BeginWhen, std::string)
        MockAction(EndWhen, std::string)

        MockAction(BeginThen, std::string)
        MockAction(EndThen, std::string)

        MockAction(BeginFinally, std::string)
        MockAction(EndFinally, std::string)

        MockAction(OnError, std::size_t, std::string, std::string)
        MockAction(OnUnknownError)

        ut11::Mock<void (std::exception)> mockOnError1;
        virtual void OnError(const std::exception& ex) { mockOnError1(ex); }
    };

    class FakeTestFixture : public ut11::TestFixtureAbstract
    {
    private:
        ut11::TestFixtureResults m_runResults;

    public:
        ut11::Output* RunOutputUsed;

        FakeTestFixture(ut11::TestFixtureResults runResults)
            : m_runResults(runResults), RunOutputUsed(nullptr)
        {
        }

        MockAction(AddCategory, ut11::Category);
        MockFunctionConst(std::set<ut11::Category>, GetCategories);

        MockAction(Given, std::string, std::function<void(void)>);
        MockAction(When, std::string, std::function<void(void)>);
        MockAction(Then, std::string, std::function<void(void)>);
        MockAction(Finally, std::string, std::function<void(void)>);

        MockFunction(std::string, GetName);

        virtual ut11::TestFixtureResults Run(ut11::Output& output)
        {
            RunOutputUsed = &output;
            return m_runResults;
        }
    };
}

class TestFixtureRunnerTests : public ut11::TestFixture
{
private:
    ut11::TestFixtureRunner m_runner;
    FakeOutput m_output;

    int m_expectedResult;
    int m_result;

public:
    virtual void Run()
    {
        Given("a TestFixtureRunner with added Fixture with failing tests", [&]() {
            m_runner = ut11::TestFixtureRunner();

            m_expectedResult = 2;

            ut11::TestFixtureResults fixtureResults;
            fixtureResults.ran = 5;
            fixtureResults.succeeded = 3;

            FakeTestFixture* fixtureOne = new FakeTestFixture(fixtureResults);
            fixtureOne->mockGetName.SetReturn(std::string("nameOne"));

            fixtureResults.ran = 4;
            fixtureResults.succeeded = 4;

            FakeTestFixture* fixtureTwo = new FakeTestFixture(fixtureResults);
            fixtureTwo->mockGetName.SetReturn(std::string("nameTwo"));

            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureOne));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureTwo));
        });
        When("running the TestFixtureRunner", [&]() {
            m_result = m_runner.Run(m_output);
        });
        Then("the number of failing tests is returned", [&]() {
            AssertThat(m_result, ut11::Is::EqualTo(m_expectedResult));
        });
    }
};
DeclareFixture(TestFixtureRunnerTests)(ut11::Category("unit"));

class TestFixtureRunnerMultipleFixturesWithSameNameTests : public ut11::TestFixture
{
private:
    ut11::TestFixtureRunner m_runner;
    FakeOutput m_output;
    FakeTestFixture* m_fixtureOne;
    FakeTestFixture* m_fixtureTwo;

public:
    virtual void Run()
    {
        Given("a TestFixtureRunner where two fixtures with the same names are added", [&]() {
            m_runner = ut11::TestFixtureRunner();
            m_output = FakeOutput();

            m_fixtureOne = new FakeTestFixture(ut11::TestFixtureResults());
            m_fixtureTwo = new FakeTestFixture(ut11::TestFixtureResults());

            m_fixtureOne->mockGetName.SetReturn("name");
            m_fixtureTwo->mockGetName.SetReturn("name");

            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(m_fixtureOne));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(m_fixtureTwo));
        });
        When("Running the test fixture runner", [&]() {
            m_runner.Run(m_output);
        });
        Then("the first test fixture is ran", [&]() {
            AssertThat(m_fixtureOne->RunOutputUsed, ut11::Is::Not::Null);
        });
        Then("the second test fixture is not ran", [&](){
            AssertThat(m_fixtureTwo->RunOutputUsed, ut11::Is::Null);
        });
    }
};
DeclareFixture(TestFixtureRunnerMultipleFixturesWithSameNameTests)(ut11::Category("unit"));

class TestFixtureRunnerCategoryTests : public ut11::TestFixture
{
private:
    ut11::TestFixtureRunner m_runner;

    int m_expectedResult;
    int m_result;

public:
    virtual void Run()
    {
        Given("a TestFixtureRunner with added Fixture with failing tests", [&]() {
            m_runner = ut11::TestFixtureRunner();

            m_expectedResult = 2;

            ut11::TestFixtureResults fixtureResults;
            fixtureResults.ran = 5;
            fixtureResults.succeeded = 4;

            FakeTestFixture* fixtureOne = new FakeTestFixture(fixtureResults);
            fixtureOne->mockGetName.SetReturn(std::string("nameOne"));
            fixtureOne->mockGetCategoriesConst.SetReturn(std::set<ut11::Category>({ ut11::Category("category") }));

            fixtureResults.ran = 4;
            fixtureResults.succeeded = 1;

            FakeTestFixture* fixtureTwo = new FakeTestFixture(fixtureResults);
            fixtureTwo->mockGetName.SetReturn(std::string("nameTwo"));
            fixtureTwo->mockGetCategoriesConst.SetReturn(std::set<ut11::Category>({ ut11::Category("unrancategory") }));

            fixtureResults.ran = 7;
            fixtureResults.succeeded = 6;

            FakeTestFixture* fixtureThree = new FakeTestFixture(fixtureResults);
            fixtureThree->mockGetName.SetReturn(std::string("nameThree"));
            fixtureThree->mockGetCategoriesConst.SetReturn(std::set<ut11::Category>({ ut11::Category("category") }));

            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureOne));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureTwo));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureThree));
        });
        When("running the TestFixtureRunner", [&]() {
            FakeOutput output;
            m_result = m_runner.RunCategories(output, {"category"});
        });
        Then("the number of failing tests is returned", [&]() {
            AssertThat(m_result, ut11::Is::EqualTo(m_expectedResult));
        });
    }
};
DeclareFixture(TestFixtureRunnerCategoryTests)(ut11::Category("unit"));
<commit_msg>Resolves potential ambiguous function call in test<commit_after>#include <UnitTest11.hpp>
#include <UnitTest11/TestFixtureRunner.hpp>

namespace ut11
{
    namespace Utility
    {
        template<> struct ParseToString<ut11::Output*>
        {
            inline std::string operator()(ut11::Output* value) const
            {
                std::stringstream stream;
                stream << value;
                return stream.str();
            }
        };
    }
}

namespace
{
    class FakeOutput : public ut11::Output
    {
    public:
        virtual ~FakeOutput() { }

        MockAction(Begin)
        MockAction(Finish, std::size_t, std::size_t)

        MockAction(BeginFixture, std::string)
        MockAction(EndFixture, std::string)

        MockAction(BeginTest)
        MockAction(EndTest)

        MockAction(BeginGiven, std::string)
        MockAction(EndGiven, std::string)

        MockAction(BeginWhen, std::string)
        MockAction(EndWhen, std::string)

        MockAction(BeginThen, std::string)
        MockAction(EndThen, std::string)

        MockAction(BeginFinally, std::string)
        MockAction(EndFinally, std::string)

        MockAction(OnError, std::size_t, std::string, std::string)
        MockAction(OnUnknownError)

        ut11::Mock<void (std::exception)> mockOnError1;
        virtual void OnError(const std::exception& ex) { mockOnError1(ex); }
    };

    class FakeTestFixture : public ut11::TestFixtureAbstract
    {
    private:
        ut11::TestFixtureResults m_runResults;

    public:
        ut11::Output* RunOutputUsed;

        FakeTestFixture(ut11::TestFixtureResults runResults)
            : m_runResults(runResults), RunOutputUsed(nullptr)
        {
        }

        MockAction(AddCategory, ut11::Category);
        MockFunctionConst(std::set<ut11::Category>, GetCategories);

        MockAction(Given, std::string, std::function<void(void)>);
        MockAction(When, std::string, std::function<void(void)>);
        MockAction(Then, std::string, std::function<void(void)>);
        MockAction(Finally, std::string, std::function<void(void)>);

        MockFunction(std::string, GetName);

        virtual ut11::TestFixtureResults Run(ut11::Output& output)
        {
            RunOutputUsed = &output;
            return m_runResults;
        }
    };
}

class TestFixtureRunnerTests : public ut11::TestFixture
{
private:
    ut11::TestFixtureRunner m_runner;
    FakeOutput m_output;

    int m_expectedResult;
    int m_result;

public:
    virtual void Run()
    {
        Given("a TestFixtureRunner with added Fixture with failing tests", [&]() {
            m_runner = ut11::TestFixtureRunner();

            m_expectedResult = 2;

            ut11::TestFixtureResults fixtureResults;
            fixtureResults.ran = 5;
            fixtureResults.succeeded = 3;

            FakeTestFixture* fixtureOne = new FakeTestFixture(fixtureResults);
            fixtureOne->mockGetName.SetReturn(std::string("nameOne"));

            fixtureResults.ran = 4;
            fixtureResults.succeeded = 4;

            FakeTestFixture* fixtureTwo = new FakeTestFixture(fixtureResults);
            fixtureTwo->mockGetName.SetReturn(std::string("nameTwo"));

            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureOne));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureTwo));
        });
        When("running the TestFixtureRunner", [&]() {
            m_result = m_runner.Run(m_output);
        });
        Then("the number of failing tests is returned", [&]() {
            AssertThat(m_result, ut11::Is::EqualTo(m_expectedResult));
        });
    }
};
DeclareFixture(TestFixtureRunnerTests)(ut11::Category("unit"));

class TestFixtureRunnerMultipleFixturesWithSameNameTests : public ut11::TestFixture
{
private:
    ut11::TestFixtureRunner m_runner;
    FakeOutput m_output;
    FakeTestFixture* m_fixtureOne;
    FakeTestFixture* m_fixtureTwo;

public:
    virtual void Run()
    {
        Given("a TestFixtureRunner where two fixtures with the same names are added", [&]() {
            m_runner = ut11::TestFixtureRunner();
            m_output = FakeOutput();

            m_fixtureOne = new FakeTestFixture(ut11::TestFixtureResults());
            m_fixtureTwo = new FakeTestFixture(ut11::TestFixtureResults());

            m_fixtureOne->mockGetName.SetReturn(std::string("name"));
            m_fixtureTwo->mockGetName.SetReturn(std::string("name"));

            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(m_fixtureOne));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(m_fixtureTwo));
        });
        When("Running the test fixture runner", [&]() {
            m_runner.Run(m_output);
        });
        Then("the first test fixture is ran", [&]() {
            AssertThat(m_fixtureOne->RunOutputUsed, ut11::Is::Not::Null);
        });
        Then("the second test fixture is not ran", [&](){
            AssertThat(m_fixtureTwo->RunOutputUsed, ut11::Is::Null);
        });
    }
};
DeclareFixture(TestFixtureRunnerMultipleFixturesWithSameNameTests)(ut11::Category("unit"));

class TestFixtureRunnerCategoryTests : public ut11::TestFixture
{
private:
    ut11::TestFixtureRunner m_runner;

    int m_expectedResult;
    int m_result;

public:
    virtual void Run()
    {
        Given("a TestFixtureRunner with added Fixture with failing tests", [&]() {
            m_runner = ut11::TestFixtureRunner();

            m_expectedResult = 2;

            ut11::TestFixtureResults fixtureResults;
            fixtureResults.ran = 5;
            fixtureResults.succeeded = 4;

            FakeTestFixture* fixtureOne = new FakeTestFixture(fixtureResults);
            fixtureOne->mockGetName.SetReturn(std::string("nameOne"));
            fixtureOne->mockGetCategoriesConst.SetReturn(std::set<ut11::Category>({ ut11::Category("category") }));

            fixtureResults.ran = 4;
            fixtureResults.succeeded = 1;

            FakeTestFixture* fixtureTwo = new FakeTestFixture(fixtureResults);
            fixtureTwo->mockGetName.SetReturn(std::string("nameTwo"));
            fixtureTwo->mockGetCategoriesConst.SetReturn(std::set<ut11::Category>({ ut11::Category("unrancategory") }));

            fixtureResults.ran = 7;
            fixtureResults.succeeded = 6;

            FakeTestFixture* fixtureThree = new FakeTestFixture(fixtureResults);
            fixtureThree->mockGetName.SetReturn(std::string("nameThree"));
            fixtureThree->mockGetCategoriesConst.SetReturn(std::set<ut11::Category>({ ut11::Category("category") }));

            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureOne));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureTwo));
            m_runner.AddFixture(std::unique_ptr<ut11::TestFixtureAbstract>(fixtureThree));
        });
        When("running the TestFixtureRunner", [&]() {
            FakeOutput output;
            m_result = m_runner.RunCategories(output, {"category"});
        });
        Then("the number of failing tests is returned", [&]() {
            AssertThat(m_result, ut11::Is::EqualTo(m_expectedResult));
        });
    }
};
DeclareFixture(TestFixtureRunnerCategoryTests)(ut11::Category("unit"));
<|endoftext|>


<commit_before>// This file is part of the AliceVision project.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#include <aliceVision/sfm/sfm.hpp>
#include <aliceVision/sfm/pipeline/regionsIO.hpp>
#include <aliceVision/feature/feature.hpp>
#include <aliceVision/image/all.hpp>
#include <aliceVision/system/Timer.hpp>

#include <dependencies/stlplus3/filesystemSimplified/file_system.hpp>

#include <boost/program_options.hpp>

#include <cstdlib>

using namespace aliceVision;
using namespace aliceVision::sfm;
using namespace std;
namespace po = boost::program_options;

// ---------------------------------------------------------------------------
// Image localization API sample:
// ---------------------------------------------------------------------------
// - Allow to locate an image to an existing SfM_reconstruction
//   if 3D-2D matches are found
// - A demonstration mode (default):
//   - try to locate all the view of the SfM_Data reconstruction
// ---------------------------------------------------------------------------
//
int main(int argc, char **argv)
{
  // command-line parameters

  std::string verboseLevel = system::EVerboseLevel_enumToString(system::Logger::getDefaultVerboseLevel());
  std::string sfmDataFilename;
  std::string describerTypesName = feature::EImageDescriberType_enumToString(feature::EImageDescriberType::SIFT);
  std::string featuresFolder;
  std::string outputFolder;
  std::string queryImage;
  double maxResidualError = std::numeric_limits<double>::infinity();

  po::options_description allParams(
    "Image localization in an existing SfM reconstruction\n"
    "AliceVision sfmLocalization");

  po::options_description requiredParams("Required parameters");
  requiredParams.add_options()
    ("input,i", po::value<std::string>(&sfmDataFilename)->required(),
      "SfMData file.")
    ("output,o", po::value<std::string>(&outputFolder)->required(),
      "Output path.")
    ("featuresFolder,f", po::value<std::string>(&featuresFolder)->required(),
      "Path to a folder containing the extracted features.")
    ("queryImage", po::value<std::string>(&queryImage)->required(),
      "Path to the image that must be localized.");

  po::options_description optionalParams("Optional parameters");
  optionalParams.add_options()
    ("describerTypes,d", po::value<std::string>(&describerTypesName)->default_value(describerTypesName),
      feature::EImageDescriberType_informations().c_str())
    ("maxResidualError", po::value<double>(&maxResidualError)->default_value(maxResidualError),
      "Upper bound of the residual error tolerance.");

  po::options_description logParams("Log parameters");
  logParams.add_options()
    ("verboseLevel,v", po::value<std::string>(&verboseLevel)->default_value(verboseLevel),
      "verbosity level (fatal,  error, warning, info, debug, trace).");

  allParams.add(requiredParams).add(optionalParams).add(logParams);

  po::variables_map vm;
  try
  {
    po::store(po::parse_command_line(argc, argv, allParams), vm);

    if(vm.count("help") || (argc == 1))
    {
      ALICEVISION_COUT(allParams);
      return EXIT_SUCCESS;
    }
    po::notify(vm);
  }
  catch(boost::program_options::required_option& e)
  {
    ALICEVISION_CERR("ERROR: " << e.what());
    ALICEVISION_COUT("Usage:\n\n" << allParams);
    return EXIT_FAILURE;
  }
  catch(boost::program_options::error& e)
  {
    ALICEVISION_CERR("ERROR: " << e.what());
    ALICEVISION_COUT("Usage:\n\n" << allParams);
    return EXIT_FAILURE;
  }

  // set verbose level
  system::Logger::get()->setLogLevel(verboseLevel);

  // Load input SfM_Data scene
  SfMData sfmData;
  if (!Load(sfmData, sfmDataFilename, ESfMData(ALL))) {
    std::cerr << std::endl
      << "The input SfM_Data file \""<< sfmDataFilename << "\" cannot be read." << std::endl;
    return EXIT_FAILURE;
  }

  if (sfmData.GetPoses().empty() || sfmData.GetLandmarks().empty())
  {
    std::cerr << std::endl
      << "The input SfM_Data file have not 3D content to match with." << std::endl;
    return EXIT_FAILURE;
  }

  // ---------------
  // Initialization
  // ---------------

  // Init the regions_type from the image describer file (used for image regions extraction)
  using namespace aliceVision::feature;

  // Get imageDescriberMethodType
  EImageDescriberType describerType = EImageDescriberType_stringToEnum(describerTypesName);

  // Get imageDecriber fom type
  std::unique_ptr<ImageDescriber> imageDescribers = createImageDescriber(describerType);

  // Load the SfM_Data region's views
  //-
  //-- Localization
  // - init the retrieval database
  // - Go along the sfm_data view
  // - extract the regions of the view
  // - try to locate the image
  //-
  sfm::SfMLocalizationSingle3DTrackObservationDatabase localizer;
  {
    RegionsPerView regionsPerView;

    std::vector<std::string> featuresFolders = sfmData.getFeaturesFolders();
    featuresFolders.emplace_back(featuresFolder);

    if (!sfm::loadRegionsPerView(regionsPerView, sfmData, featuresFolders, {describerType}))
    {
      std::cerr << std::endl << "Invalid regions." << std::endl;
      return EXIT_FAILURE;
    }

    if (outputFolder.empty())
    {
      std::cerr << "\nIt is an invalid output folder" << std::endl;
      return EXIT_FAILURE;
    }

    if (!stlplus::folder_exists(outputFolder))
      stlplus::folder_create(outputFolder);

    if (!localizer.Init(sfmData, regionsPerView))
    {
      std::cerr << "Cannot initialize the SfM localizer" << std::endl;
    }
  }

  std::vector<Vec3> vec_found_poses;

  if (!queryImage.empty())
  {
    std::cout << "SfM::localization => try with image: " << queryImage << std::endl;
    std::unique_ptr<Regions> query_regions;
    image::Image<unsigned char> imageGray;
    {
      image::readImage(queryImage, imageGray);

      // Compute features and descriptors
      imageDescribers->Describe(imageGray, query_regions);
      std::cout << "#regions detected in query image: " << query_regions->RegionCount() << std::endl;
    }

    // Suppose intrinsic as unknown
    std::shared_ptr<camera::IntrinsicBase> optional_intrinsic (nullptr);

    geometry::Pose3 pose;
    sfm::ImageLocalizerMatchData matching_data;
    matching_data.error_max = maxResidualError;

    // Try to localize the image in the database thanks to its regions
    if (!localizer.Localize(
      Pair(imageGray.Width(), imageGray.Height()),
      optional_intrinsic.get(),
      *(query_regions.get()),
      pose,
      &matching_data))
    {
      std::cerr << "Cannot locate the image" << std::endl;
    }
    else
    {
      const bool b_new_intrinsic = (optional_intrinsic == nullptr);
      // A valid pose has been found (try to refine it):
      // If not intrinsic as input:
      //  init a new one from the projection matrix decomposition
      // Else use the existing one and consider as static.
      if (b_new_intrinsic)
      {
        // setup a default camera model from the found projection matrix
        Mat3 K, R;
        Vec3 t;
        KRt_From_P(matching_data.projection_matrix, &K, &R, &t);

        const double focal = (K(0,0) + K(1,1))/2.0;
        const Vec2 principal_point(K(0,2), K(1,2));
        optional_intrinsic = std::make_shared<camera::PinholeRadialK3>(
          imageGray.Width(), imageGray.Height(),
          focal, principal_point(0), principal_point(1));
      }
      sfm::SfMLocalizer::RefinePose
      (
        optional_intrinsic.get(),
        pose, matching_data,
        true, b_new_intrinsic
      );

      vec_found_poses.push_back(pose.center());
    }
  }
  else
  {
    std::cout << "----------------\n"
      << " DEMONSTRATION \n"
      << "----------------\n" << std::endl;
    std::cout << "Will try to locate all the view of the loaded sfm_data file." << std::endl;

    for (const auto & viewIter : sfmData.GetViews())
    {
      const View * view = viewIter.second.get();
      // Load an image, extract the regions and match
      const std::string sImagePath = view->getImagePath();

      std::cout << "SfM::localization => try with image: " << sImagePath << std::endl;

      std::unique_ptr<Regions> query_regions;
      imageDescribers->Allocate(query_regions);
      const std::string basename = stlplus::basename_part(sImagePath);
      const std::string featFile = stlplus::create_filespec(featuresFolder, basename, ".feat");
      const std::string descFile = stlplus::create_filespec(featuresFolder, basename, ".desc");

      try
      {
        query_regions->Load(featFile, descFile);
      }
      catch(const std::exception& e)
      {
        std::stringstream ss;
        ss << "Invalid regions files for the view " << basename << " : \n";
        ss << "\t- Features file : " << featFile << "\n";
        ss << "\t- Descriptors file: " << descFile << "\n";
        ss << "\t  " << e.what() << "\n";
        ALICEVISION_LOG_WARNING(ss.str());
        continue;
      }

      // Initialize intrinsics data for the view if any
      std::shared_ptr<camera::IntrinsicBase> optional_intrinsic (nullptr);
      if (sfmData.GetIntrinsics().count(view->getIntrinsicId()))
      {
        optional_intrinsic = sfmData.GetIntrinsics().at(view->getIntrinsicId());
      }

      geometry::Pose3 pose;
      sfm::ImageLocalizerMatchData matching_data;
      matching_data.error_max = maxResidualError;

      // Try to localize the image in the database thanks to its regions
      if (!localizer.Localize(
        Pair(view->getWidth(), view->getHeight()),
        optional_intrinsic.get(),
        *(query_regions.get()),
        pose,
        &matching_data))
      {
        std::cerr << "Cannot locate the image" << std::endl;
      }
      else
      {
        const bool b_new_intrinsic = (optional_intrinsic == nullptr);
        // A valid pose has been found (try to refine it):
        // If no valid intrinsic as input:
        //  init a new one from the projection matrix decomposition
        // Else use the existing one and consider it as constant
        if (b_new_intrinsic)
        {
          // setup a default camera model from the found projection matrix
          Mat3 K, R;
          Vec3 t;
          KRt_From_P(matching_data.projection_matrix, &K, &R, &t);

          const double focal = (K(0,0) + K(1,1))/2.0;
          const Vec2 principal_point(K(0,2), K(1,2));
          optional_intrinsic = std::make_shared<camera::PinholeRadialK3>(
            view->getWidth(), view->getHeight(),
            focal, principal_point(0), principal_point(1));
        }
        sfm::SfMLocalizer::RefinePose
        (
          optional_intrinsic.get(),
          pose, matching_data,
          true, b_new_intrinsic
        );

        vec_found_poses.push_back(pose.center());
      }
    }
    std::cout
      << "\n#images found: " << vec_found_poses.size()
      << "\n#sfm_data view count: " << sfmData.GetViews().size()
      << std::endl;
  }

  // Export the found camera position
  const std::string out_file_name = stlplus::create_filespec(outputFolder, "found_pose_centers", "ply");
  {
    std::ofstream outfile;
    outfile.open(out_file_name.c_str(), std::ios_base::out);
    if (outfile.is_open()) {
      outfile << "ply"
       << "\n" << "format ascii 1.0"
       << "\n" << "element vertex " << vec_found_poses.size()
       << "\n" << "property float x"
       << "\n" << "property float y"
       << "\n" << "property float z"
       << "\n" << "property uchar red"
       << "\n" << "property uchar green"
       << "\n" << "property uchar blue"
       << "\n" << "end_header" << "\n";

      for (const Vec3 & pose_center: vec_found_poses) {
        outfile << pose_center.transpose() << " " << "255 0 0" << "\n";
      }

      outfile.close();
    }
  }

  return EXIT_FAILURE;
}
<commit_msg>[software] `sfmLocalization` formatting<commit_after>// This file is part of the AliceVision project.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#include <aliceVision/sfm/sfm.hpp>
#include <aliceVision/sfm/pipeline/regionsIO.hpp>
#include <aliceVision/feature/feature.hpp>
#include <aliceVision/image/all.hpp>
#include <aliceVision/system/Timer.hpp>
#include <aliceVision/system/Logger.hpp>
#include <aliceVision/system/cmdline.hpp>

#include <dependencies/stlplus3/filesystemSimplified/file_system.hpp>

#include <boost/program_options.hpp>

#include <cstdlib>

using namespace aliceVision;
using namespace aliceVision::sfm;
using namespace std;
namespace po = boost::program_options;

// ---------------------------------------------------------------------------
// Image localization API sample:
// ---------------------------------------------------------------------------
// - Allow to locate an image to an existing SfM_reconstruction
//   if 3D-2D matches are found
// - A demonstration mode (default):
//   - try to locate all the view of the SfM_Data reconstruction
// ---------------------------------------------------------------------------
//
int main(int argc, char **argv)
{
  // command-line parameters

  std::string verboseLevel = system::EVerboseLevel_enumToString(system::Logger::getDefaultVerboseLevel());
  std::string sfmDataFilename;
  std::string describerTypesName = feature::EImageDescriberType_enumToString(feature::EImageDescriberType::SIFT);
  std::string featuresFolder;
  std::string outputFolder;
  std::string queryImage;
  double maxResidualError = std::numeric_limits<double>::infinity();

  po::options_description allParams(
    "Image localization in an existing SfM reconstruction\n"
    "AliceVision sfmLocalization");

  po::options_description requiredParams("Required parameters");
  requiredParams.add_options()
    ("input,i", po::value<std::string>(&sfmDataFilename)->required(),
      "SfMData file.")
    ("output,o", po::value<std::string>(&outputFolder)->required(),
      "Output path.")
    ("featuresFolder,f", po::value<std::string>(&featuresFolder)->required(),
      "Path to a folder containing the extracted features.")
    ("queryImage", po::value<std::string>(&queryImage)->required(),
      "Path to the image that must be localized.");

  po::options_description optionalParams("Optional parameters");
  optionalParams.add_options()
    ("describerTypes,d", po::value<std::string>(&describerTypesName)->default_value(describerTypesName),
      feature::EImageDescriberType_informations().c_str())
    ("maxResidualError", po::value<double>(&maxResidualError)->default_value(maxResidualError),
      "Upper bound of the residual error tolerance.");

  po::options_description logParams("Log parameters");
  logParams.add_options()
    ("verboseLevel,v", po::value<std::string>(&verboseLevel)->default_value(verboseLevel),
      "verbosity level (fatal,  error, warning, info, debug, trace).");

  allParams.add(requiredParams).add(optionalParams).add(logParams);

  po::variables_map vm;
  try
  {
    po::store(po::parse_command_line(argc, argv, allParams), vm);

    if(vm.count("help") || (argc == 1))
    {
      ALICEVISION_COUT(allParams);
      return EXIT_SUCCESS;
    }
    po::notify(vm);
  }
  catch(boost::program_options::required_option& e)
  {
    ALICEVISION_CERR("ERROR: " << e.what());
    ALICEVISION_COUT("Usage:\n\n" << allParams);
    return EXIT_FAILURE;
  }
  catch(boost::program_options::error& e)
  {
    ALICEVISION_CERR("ERROR: " << e.what());
    ALICEVISION_COUT("Usage:\n\n" << allParams);
    return EXIT_FAILURE;
  }

  ALICEVISION_COUT("Program called with the following parameters:");
  ALICEVISION_COUT(vm);

  // set verbose level
  system::Logger::get()->setLogLevel(verboseLevel);

  // Load input SfM_Data scene
  SfMData sfmData;
  if (!Load(sfmData, sfmDataFilename, ESfMData(ALL)))
  {
    ALICEVISION_LOG_ERROR("The input SfMData file '"<< sfmDataFilename << "' cannot be read");
    return EXIT_FAILURE;
  }

  if (sfmData.GetPoses().empty() || sfmData.GetLandmarks().empty())
  {
    ALICEVISION_LOG_ERROR("The input SfM_Data file have not 3D content to match with.");
    return EXIT_FAILURE;
  }

  // ---------------
  // Initialization
  // ---------------

  // Init the regions_type from the image describer file (used for image regions extraction)
  using namespace aliceVision::feature;

  // Get imageDescriberMethodType
  EImageDescriberType describerType = EImageDescriberType_stringToEnum(describerTypesName);

  // Get imageDecriber fom type
  std::unique_ptr<ImageDescriber> imageDescribers = createImageDescriber(describerType);

  // Load the SfM_Data region's views
  //-
  //-- Localization
  // - init the retrieval database
  // - Go along the sfm_data view
  // - extract the regions of the view
  // - try to locate the image
  //-
  sfm::SfMLocalizationSingle3DTrackObservationDatabase localizer;
  {
    RegionsPerView regionsPerView;

    std::vector<std::string> featuresFolders = sfmData.getFeaturesFolders();
    featuresFolders.emplace_back(featuresFolder);

    if (!sfm::loadRegionsPerView(regionsPerView, sfmData, featuresFolders, {describerType}))
    {
      ALICEVISION_LOG_ERROR("Invalid regions.");
      return EXIT_FAILURE;
    }

    if (outputFolder.empty())
    {
      ALICEVISION_LOG_ERROR("It is an invalid output folder");
      return EXIT_FAILURE;
    }

    if (!stlplus::folder_exists(outputFolder))
      stlplus::folder_create(outputFolder);

    if(!localizer.Init(sfmData, regionsPerView))
    {
      ALICEVISION_LOG_ERROR("Cannot initialize the SfM localizer");
    }
  }

  std::vector<Vec3> vec_found_poses;

  if (!queryImage.empty())
  {
    ALICEVISION_LOG_INFO("SfM::localization => try with image: " << queryImage);
    std::unique_ptr<Regions> query_regions;
    image::Image<unsigned char> imageGray;
    {
      image::readImage(queryImage, imageGray);

      // Compute features and descriptors
      imageDescribers->Describe(imageGray, query_regions);
      ALICEVISION_LOG_INFO("# regions detected in query image: " << query_regions->RegionCount());
    }

    // Suppose intrinsic as unknown
    std::shared_ptr<camera::IntrinsicBase> optional_intrinsic (nullptr);

    geometry::Pose3 pose;
    sfm::ImageLocalizerMatchData matching_data;
    matching_data.error_max = maxResidualError;

    // Try to localize the image in the database thanks to its regions
    if (!localizer.Localize(
      Pair(imageGray.Width(), imageGray.Height()),
      optional_intrinsic.get(),
      *(query_regions.get()),
      pose,
      &matching_data))
    {
      ALICEVISION_LOG_ERROR("Cannot locate the image");
    }
    else
    {
      const bool b_new_intrinsic = (optional_intrinsic == nullptr);
      // A valid pose has been found (try to refine it):
      // If not intrinsic as input:
      //  init a new one from the projection matrix decomposition
      // Else use the existing one and consider as static.
      if (b_new_intrinsic)
      {
        // setup a default camera model from the found projection matrix
        Mat3 K, R;
        Vec3 t;
        KRt_From_P(matching_data.projection_matrix, &K, &R, &t);

        const double focal = (K(0,0) + K(1,1))/2.0;
        const Vec2 principal_point(K(0,2), K(1,2));
        optional_intrinsic = std::make_shared<camera::PinholeRadialK3>(
          imageGray.Width(), imageGray.Height(),
          focal, principal_point(0), principal_point(1));
      }
      sfm::SfMLocalizer::RefinePose
      (
        optional_intrinsic.get(),
        pose, matching_data,
        true, b_new_intrinsic
      );

      vec_found_poses.push_back(pose.center());
    }
  }
  else
  {
    ALICEVISION_LOG_INFO("DEMONSTRATION" << std::endl << "Will try to locate all the view of the loaded sfm_data file.");

    for (const auto & viewIter : sfmData.GetViews())
    {
      const View * view = viewIter.second.get();
      // Load an image, extract the regions and match
      const std::string sImagePath = view->getImagePath();

      ALICEVISION_LOG_INFO("SfM::localization => try with image: " << sImagePath);

      std::unique_ptr<Regions> query_regions;
      imageDescribers->Allocate(query_regions);
      const std::string basename = stlplus::basename_part(sImagePath);
      const std::string featFile = stlplus::create_filespec(featuresFolder, basename, ".feat");
      const std::string descFile = stlplus::create_filespec(featuresFolder, basename, ".desc");

      try
      {
        query_regions->Load(featFile, descFile);
      }
      catch(const std::exception& e)
      {
        std::stringstream ss;
        ss << "Invalid regions files for the view " << basename << " : \n";
        ss << "\t- Features file : " << featFile << "\n";
        ss << "\t- Descriptors file: " << descFile << "\n";
        ss << "\t  " << e.what() << "\n";
        ALICEVISION_LOG_WARNING(ss.str());
        continue;
      }

      // Initialize intrinsics data for the view if any
      std::shared_ptr<camera::IntrinsicBase> optional_intrinsic (nullptr);
      if (sfmData.GetIntrinsics().count(view->getIntrinsicId()))
      {
        optional_intrinsic = sfmData.GetIntrinsics().at(view->getIntrinsicId());
      }

      geometry::Pose3 pose;
      sfm::ImageLocalizerMatchData matching_data;
      matching_data.error_max = maxResidualError;

      // Try to localize the image in the database thanks to its regions
      if (!localizer.Localize(
        Pair(view->getWidth(), view->getHeight()),
        optional_intrinsic.get(),
        *(query_regions.get()),
        pose,
        &matching_data))
      {
        ALICEVISION_LOG_ERROR("Cannot locate the image");
      }
      else
      {
        const bool b_new_intrinsic = (optional_intrinsic == nullptr);
        // A valid pose has been found (try to refine it):
        // If no valid intrinsic as input:
        //  init a new one from the projection matrix decomposition
        // Else use the existing one and consider it as constant
        if (b_new_intrinsic)
        {
          // setup a default camera model from the found projection matrix
          Mat3 K, R;
          Vec3 t;
          KRt_From_P(matching_data.projection_matrix, &K, &R, &t);

          const double focal = (K(0,0) + K(1,1))/2.0;
          const Vec2 principal_point(K(0,2), K(1,2));
          optional_intrinsic = std::make_shared<camera::PinholeRadialK3>(
            view->getWidth(), view->getHeight(),
            focal, principal_point(0), principal_point(1));
        }
        sfm::SfMLocalizer::RefinePose
        (
          optional_intrinsic.get(),
          pose, matching_data,
          true, b_new_intrinsic
        );

        vec_found_poses.push_back(pose.center());
      }
    }
    ALICEVISION_LOG_INFO("# images found: " << vec_found_poses.size());
    ALICEVISION_LOG_INFO("# sfmData view count: " << sfmData.GetViews().size());
  }

  // Export the found camera position
  const std::string out_file_name = stlplus::create_filespec(outputFolder, "found_pose_centers", "ply");
  {
    std::ofstream outfile;
    outfile.open(out_file_name.c_str(), std::ios_base::out);
    if (outfile.is_open()) {
      outfile << "ply"
       << "\n" << "format ascii 1.0"
       << "\n" << "element vertex " << vec_found_poses.size()
       << "\n" << "property float x"
       << "\n" << "property float y"
       << "\n" << "property float z"
       << "\n" << "property uchar red"
       << "\n" << "property uchar green"
       << "\n" << "property uchar blue"
       << "\n" << "end_header" << "\n";

      for (const Vec3 & pose_center: vec_found_poses) {
        outfile << pose_center.transpose() << " " << "255 0 0" << "\n";
      }

      outfile.close();
    }
  }

  return EXIT_FAILURE;
}
<|endoftext|>